2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.benqprojector.internal;
15 import java.time.Duration;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.benqprojector.internal.configuration.BenqProjectorConfiguration;
20 import org.openhab.binding.benqprojector.internal.connector.BenqProjectorConnector;
21 import org.openhab.binding.benqprojector.internal.connector.BenqProjectorSerialConnector;
22 import org.openhab.binding.benqprojector.internal.connector.BenqProjectorTcpConnector;
23 import org.openhab.binding.benqprojector.internal.enums.Switch;
24 import org.openhab.core.cache.ExpiringCache;
25 import org.openhab.core.io.transport.serial.SerialPortManager;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * Provide high level interface to BenQ projector.
32 * @author Michael Lobstein - Initial contribution
35 public class BenqProjectorDevice {
36 private static final String UNSUPPORTED_ITM = "Unsupported item";
37 private static final String BLOCK_ITM = "Block item";
38 private static final String ILLEGAL_FMT = "Illegal format";
40 private static final int LAMP_REFRESH_WAIT_MINUTES = 5;
42 private ExpiringCache<Integer> cachedLampHours = new ExpiringCache<>(Duration.ofMinutes(LAMP_REFRESH_WAIT_MINUTES),
45 private final Logger logger = LoggerFactory.getLogger(BenqProjectorDevice.class);
47 private BenqProjectorConnector connection;
48 private boolean connected = false;
50 public BenqProjectorDevice(SerialPortManager serialPortManager, BenqProjectorConfiguration config) {
51 connection = new BenqProjectorSerialConnector(serialPortManager, config.serialPort);
54 public BenqProjectorDevice(BenqProjectorConfiguration config) {
55 connection = new BenqProjectorTcpConnector(config.host, config.port);
58 private synchronized String sendQuery(String query) throws BenqProjectorCommandException, BenqProjectorException {
59 logger.debug("Query: '{}'", query);
60 String response = connection.sendMessage(query);
62 if (response.length() == 0) {
63 throw new BenqProjectorException("No response received");
66 if (response.contains(UNSUPPORTED_ITM)) {
70 if (response.contains(BLOCK_ITM)) {
71 throw new BenqProjectorCommandException("Block Item received for command: " + query);
74 if (response.contains(ILLEGAL_FMT)) {
75 throw new BenqProjectorCommandException("Illegal Format response received for command: " + query);
78 logger.debug("Response: '{}'", response);
80 // example: SOUR=HDMI2
81 String[] responseParts = response.split("=");
82 if (responseParts.length != 2) {
83 throw new BenqProjectorCommandException("Invalid respose for command: " + query);
86 return responseParts[1].toLowerCase();
89 protected void sendCommand(String command) throws BenqProjectorCommandException, BenqProjectorException {
93 protected int queryInt(String query) throws BenqProjectorCommandException, BenqProjectorException {
94 String response = sendQuery(query);
96 return Integer.parseInt(response);
97 } catch (NumberFormatException nfe) {
98 throw new BenqProjectorCommandException(
99 "Unable to parse response '" + response + "' as Integer for command: " + query);
103 protected String queryString(String query) throws BenqProjectorCommandException, BenqProjectorException {
104 return sendQuery(query);
107 public void connect() throws BenqProjectorException {
108 connection.connect();
112 public void disconnect() throws BenqProjectorException {
113 connection.disconnect();
117 public boolean isConnected() {
124 public Switch getPowerStatus() throws BenqProjectorCommandException, BenqProjectorException {
125 return (queryString("pow=?").contains("on") ? Switch.ON : Switch.OFF);
128 public void setPower(Switch value) throws BenqProjectorCommandException, BenqProjectorException {
129 sendCommand(value == Switch.ON ? "pow=on" : "pow=off");
135 public @Nullable String getSource() throws BenqProjectorCommandException, BenqProjectorException {
136 return queryString("sour=?");
139 public void setSource(String value) throws BenqProjectorCommandException, BenqProjectorException {
140 sendCommand(String.format("sour=%s", value));
146 public @Nullable String getPictureMode() throws BenqProjectorCommandException, BenqProjectorException {
147 return queryString("appmod=?");
150 public void setPictureMode(String value) throws BenqProjectorCommandException, BenqProjectorException {
151 sendCommand(String.format("appmod=%s", value));
157 public @Nullable String getAspectRatio() throws BenqProjectorCommandException, BenqProjectorException {
158 return queryString("asp=?");
161 public void setAspectRatio(String value) throws BenqProjectorCommandException, BenqProjectorException {
162 sendCommand(String.format("asp=%s", value));
168 public Switch getBlank() throws BenqProjectorCommandException, BenqProjectorException {
169 return (queryString("blank=?").contains("on") ? Switch.ON : Switch.OFF);
172 public void setBlank(Switch value) throws BenqProjectorCommandException, BenqProjectorException {
173 sendCommand(String.format("blank=%s", (value == Switch.ON ? "on" : "off")));
179 public Switch getFreeze() throws BenqProjectorCommandException, BenqProjectorException {
180 return (queryString("freeze=?").contains("on") ? Switch.ON : Switch.OFF);
183 public void setFreeze(Switch value) throws BenqProjectorCommandException, BenqProjectorException {
184 sendCommand(String.format("freeze=%s", (value == Switch.ON ? "on" : "off")));
190 public void sendDirectCommand(String value) throws BenqProjectorCommandException, BenqProjectorException {
195 * Lamp Time (hours) - get from cache
197 public int getLampTime() throws BenqProjectorCommandException, BenqProjectorException {
198 Integer lampHours = cachedLampHours.getValue();
200 if (lampHours != null) {
201 return lampHours.intValue();
203 throw new BenqProjectorCommandException("cachedLampHours returned null");
210 private @Nullable Integer queryLamp() {
212 return Integer.valueOf(queryInt("ltim=?"));
213 } catch (BenqProjectorCommandException | BenqProjectorException e) {
214 logger.debug("Error executing command ltim=?", e);