[benqprojector] Fix response processing for newer projectors (#18009)

* Fix message processing for newer projectors

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
mlobstein 2025-01-05 15:14:30 -06:00 committed by GitHub
parent b5203ebff4
commit b4bcf802f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 24 deletions

View File

@ -89,7 +89,7 @@ String benqAspectRatio "Aspect Ratio [%s]" { channel="benqprojector:p
Switch benqFreeze { channel="benqprojector:projector-serial:hometheater:freeze" } Switch benqFreeze { channel="benqprojector:projector-serial:hometheater:freeze" }
Switch benqBlank { channel="benqprojector:projector-serial:hometheater:blank" } Switch benqBlank { channel="benqprojector:projector-serial:hometheater:blank" }
String benqDirect { channel="benqprojector:projector-serial:hometheater:directcmd" } String benqDirect { channel="benqprojector:projector-serial:hometheater:directcmd" }
Number benqLampTime "Lamp Time [%d h]" <switch> { channel="benqprojector:projector-serial:hometheater:lamptime" } Number benqLampTime "Lamp Time [%d h]" <light> { channel="benqprojector:projector-serial:hometheater:lamptime" }
``` ```
sitemaps/benq.sitemap sitemaps/benq.sitemap
@ -98,7 +98,7 @@ sitemaps/benq.sitemap
sitemap benq label="BenQ Projector" { sitemap benq label="BenQ Projector" {
Frame label="Controls" { Frame label="Controls" {
Switch item=benqPower label="Power" Switch item=benqPower label="Power"
Selection item=benqSource label="Source" mappings=["hdmi"="HDMI", "hdmi2"="HDMI2", "ypbr"="Component", "RGB"="Computer", "vid"="Video", "svid"="S-Video"] Selection item=benqSource label="Source" mappings=["hdmi"="HDMI", "hdmi2"="HDMI2", "usbreader"="USB Reader", "ypbr"="Component", "RGB"="Computer", "vid"="Video", "svid"="S-Video"]
Selection item=benqPictureMode label="Picture Mode" Selection item=benqPictureMode label="Picture Mode"
Selection item=benqAspectRatio label="Aspect Ratio" Selection item=benqAspectRatio label="Aspect Ratio"
Switch item=benqFreeze label="Freeze" Switch item=benqFreeze label="Freeze"

View File

@ -42,4 +42,7 @@ public class BenqProjectorBindingConstants {
// Config properties // Config properties
public static final String THING_PROPERTY_HOST = "host"; public static final String THING_PROPERTY_HOST = "host";
public static final String THING_PROPERTY_PORT = "port"; public static final String THING_PROPERTY_PORT = "port";
// Unsupported item response
public static final String UNSUPPORTED_ITM = "Unsupported item";
} }

View File

@ -12,7 +12,10 @@
*/ */
package org.openhab.binding.benqprojector.internal; package org.openhab.binding.benqprojector.internal;
import static org.openhab.binding.benqprojector.internal.BenqProjectorBindingConstants.*;
import java.time.Duration; import java.time.Duration;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -33,10 +36,6 @@ import org.slf4j.LoggerFactory;
*/ */
@NonNullByDefault @NonNullByDefault
public class BenqProjectorDevice { public class BenqProjectorDevice {
private static final String UNSUPPORTED_ITM = "Unsupported item";
private static final String BLOCK_ITM = "Block item";
private static final String ILLEGAL_FMT = "Illegal format";
private static final int LAMP_REFRESH_WAIT_MINUTES = 5; private static final int LAMP_REFRESH_WAIT_MINUTES = 5;
private ExpiringCache<Integer> cachedLampHours = new ExpiringCache<>(Duration.ofMinutes(LAMP_REFRESH_WAIT_MINUTES), private ExpiringCache<Integer> cachedLampHours = new ExpiringCache<>(Duration.ofMinutes(LAMP_REFRESH_WAIT_MINUTES),
@ -67,14 +66,6 @@ public class BenqProjectorDevice {
return "UNSUPPORTED"; return "UNSUPPORTED";
} }
if (response.contains(BLOCK_ITM)) {
throw new BenqProjectorCommandException("Block Item received for command: " + query);
}
if (response.contains(ILLEGAL_FMT)) {
throw new BenqProjectorCommandException("Illegal Format response received for command: " + query);
}
logger.debug("Response: '{}'", response); logger.debug("Response: '{}'", response);
// example: SOUR=HDMI2 // example: SOUR=HDMI2
@ -122,11 +113,17 @@ public class BenqProjectorDevice {
* Power * Power
*/ */
public Switch getPowerStatus() throws BenqProjectorCommandException, BenqProjectorException { public Switch getPowerStatus() throws BenqProjectorCommandException, BenqProjectorException {
return (queryString("pow=?").contains("on") ? Switch.ON : Switch.OFF); return (queryString("pow=?").toLowerCase(Locale.ENGLISH).contains("on") ? Switch.ON : Switch.OFF);
} }
public void setPower(Switch value) throws BenqProjectorCommandException, BenqProjectorException { public void setPower(Switch value) throws BenqProjectorCommandException, BenqProjectorException {
sendCommand(value == Switch.ON ? "pow=on" : "pow=off"); if (value == Switch.ON) {
sendCommand("pow=on");
} else {
// some projectors need the off command twice to switch off
sendCommand("pow=off");
sendCommand("pow=off");
}
} }
/* /*
@ -166,7 +163,7 @@ public class BenqProjectorDevice {
* Blank Screen * Blank Screen
*/ */
public Switch getBlank() throws BenqProjectorCommandException, BenqProjectorException { public Switch getBlank() throws BenqProjectorCommandException, BenqProjectorException {
return (queryString("blank=?").contains("on") ? Switch.ON : Switch.OFF); return (queryString("blank=?").toLowerCase(Locale.ENGLISH).contains("on") ? Switch.ON : Switch.OFF);
} }
public void setBlank(Switch value) throws BenqProjectorCommandException, BenqProjectorException { public void setBlank(Switch value) throws BenqProjectorCommandException, BenqProjectorException {
@ -177,7 +174,7 @@ public class BenqProjectorDevice {
* Freeze * Freeze
*/ */
public Switch getFreeze() throws BenqProjectorCommandException, BenqProjectorException { public Switch getFreeze() throws BenqProjectorCommandException, BenqProjectorException {
return (queryString("freeze=?").contains("on") ? Switch.ON : Switch.OFF); return (queryString("freeze=?").toLowerCase(Locale.ENGLISH).contains("on") ? Switch.ON : Switch.OFF);
} }
public void setFreeze(Switch value) throws BenqProjectorCommandException, BenqProjectorException { public void setFreeze(Switch value) throws BenqProjectorCommandException, BenqProjectorException {

View File

@ -12,6 +12,8 @@
*/ */
package org.openhab.binding.benqprojector.internal.connector; package org.openhab.binding.benqprojector.internal.connector;
import static org.openhab.binding.benqprojector.internal.BenqProjectorBindingConstants.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -19,6 +21,7 @@ import java.nio.charset.StandardCharsets;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.benqprojector.internal.BenqProjectorCommandException;
import org.openhab.binding.benqprojector.internal.BenqProjectorException; import org.openhab.binding.benqprojector.internal.BenqProjectorException;
/** /**
@ -34,6 +37,9 @@ public interface BenqProjectorConnector {
static final String END = "#\r"; static final String END = "#\r";
static final String BLANK = ""; static final String BLANK = "";
static final String BLOCK_ITM = "Block item";
static final String ILLEGAL_FMT = "Illegal format";
/** /**
* Procedure for connecting to projector. * Procedure for connecting to projector.
* *
@ -55,8 +61,9 @@ public interface BenqProjectorConnector {
* Message to send. * Message to send.
* *
* @throws BenqProjectorException * @throws BenqProjectorException
* @throws BenqProjectorCommandException
*/ */
String sendMessage(String data) throws BenqProjectorException; String sendMessage(String data) throws BenqProjectorException, BenqProjectorCommandException;
/** /**
* Common method called by the Serial or Tcp connector to send the message to the projector, wait for a response and * Common method called by the Serial or Tcp connector to send the message to the projector, wait for a response and
@ -70,9 +77,10 @@ public interface BenqProjectorConnector {
* The connector's output stream. * The connector's output stream.
* *
* @throws BenqProjectorException * @throws BenqProjectorException
* @throws BenqProjectorCommandException
*/ */
default String sendMsgReadResp(String data, @Nullable InputStream in, @Nullable OutputStream out) default String sendMsgReadResp(String data, @Nullable InputStream in, @Nullable OutputStream out)
throws IOException, BenqProjectorException { throws IOException, BenqProjectorException, BenqProjectorCommandException {
String resp = BLANK; String resp = BLANK;
if (in != null && out != null) { if (in != null && out != null) {
@ -88,8 +96,24 @@ public interface BenqProjectorConnector {
byte[] tmpData = new byte[availableBytes]; byte[] tmpData = new byte[availableBytes];
int readBytes = in.read(tmpData, 0, availableBytes); int readBytes = in.read(tmpData, 0, availableBytes);
resp = resp.concat(new String(tmpData, 0, readBytes, StandardCharsets.US_ASCII)); resp = resp.concat(new String(tmpData, 0, readBytes, StandardCharsets.US_ASCII));
if (resp.contains(END)) {
return resp.replaceAll("[\\r\\n*#>]", BLANK).replace(data, BLANK); if (resp.contains(UNSUPPORTED_ITM)) {
return resp;
}
if (resp.contains(BLOCK_ITM)) {
throw new BenqProjectorCommandException("Block Item received for command: " + data);
}
if (resp.contains(ILLEGAL_FMT)) {
throw new BenqProjectorCommandException(
"Illegal Format response received for command: " + data);
}
// The response is fully received when the second '#' arrives
// example: *pow=?# *POW=ON#
if (resp.chars().filter(ch -> ch == '#').count() >= 2) {
return resp.replaceAll("[\\s\\r\\n*#>]", BLANK).replace(data, BLANK);
} }
} else { } else {
try { try {

View File

@ -18,6 +18,7 @@ import java.io.OutputStream;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.benqprojector.internal.BenqProjectorCommandException;
import org.openhab.binding.benqprojector.internal.BenqProjectorException; import org.openhab.binding.benqprojector.internal.BenqProjectorException;
import org.openhab.core.io.transport.serial.PortInUseException; import org.openhab.core.io.transport.serial.PortInUseException;
import org.openhab.core.io.transport.serial.SerialPort; import org.openhab.core.io.transport.serial.SerialPort;
@ -120,7 +121,7 @@ public class BenqProjectorSerialConnector implements BenqProjectorConnector, Ser
} }
@Override @Override
public String sendMessage(String data) throws BenqProjectorException { public String sendMessage(String data) throws BenqProjectorException, BenqProjectorCommandException {
InputStream in = this.in; InputStream in = this.in;
OutputStream out = this.out; OutputStream out = this.out;

View File

@ -19,6 +19,7 @@ import java.net.Socket;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.benqprojector.internal.BenqProjectorCommandException;
import org.openhab.binding.benqprojector.internal.BenqProjectorException; import org.openhab.binding.benqprojector.internal.BenqProjectorException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -99,7 +100,7 @@ public class BenqProjectorTcpConnector implements BenqProjectorConnector {
} }
@Override @Override
public String sendMessage(String data) throws BenqProjectorException { public String sendMessage(String data) throws BenqProjectorException, BenqProjectorCommandException {
InputStream in = this.in; InputStream in = this.in;
OutputStream out = this.out; OutputStream out = this.out;