2 * Copyright (c) 2010-2021 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.epsonprojector.internal.handler;
15 import static org.openhab.binding.epsonprojector.internal.EpsonProjectorBindingConstants.*;
17 import java.util.List;
18 import java.util.Optional;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.epsonprojector.internal.EpsonProjectorCommandException;
25 import org.openhab.binding.epsonprojector.internal.EpsonProjectorCommandType;
26 import org.openhab.binding.epsonprojector.internal.EpsonProjectorDevice;
27 import org.openhab.binding.epsonprojector.internal.EpsonProjectorException;
28 import org.openhab.binding.epsonprojector.internal.configuration.EpsonProjectorConfiguration;
29 import org.openhab.binding.epsonprojector.internal.enums.AspectRatio;
30 import org.openhab.binding.epsonprojector.internal.enums.Background;
31 import org.openhab.binding.epsonprojector.internal.enums.ColorMode;
32 import org.openhab.binding.epsonprojector.internal.enums.Gamma;
33 import org.openhab.binding.epsonprojector.internal.enums.Luminance;
34 import org.openhab.binding.epsonprojector.internal.enums.PowerStatus;
35 import org.openhab.binding.epsonprojector.internal.enums.Switch;
36 import org.openhab.core.io.transport.serial.SerialPortManager;
37 import org.openhab.core.library.types.DecimalType;
38 import org.openhab.core.library.types.OnOffType;
39 import org.openhab.core.library.types.StringType;
40 import org.openhab.core.thing.Channel;
41 import org.openhab.core.thing.ChannelUID;
42 import org.openhab.core.thing.Thing;
43 import org.openhab.core.thing.ThingStatus;
44 import org.openhab.core.thing.ThingStatusDetail;
45 import org.openhab.core.thing.ThingTypeUID;
46 import org.openhab.core.thing.binding.BaseThingHandler;
47 import org.openhab.core.types.Command;
48 import org.openhab.core.types.RefreshType;
49 import org.openhab.core.types.State;
50 import org.openhab.core.types.UnDefType;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 * The {@link EpsonProjectorHandler} is responsible for handling commands, which are
56 * sent to one of the channels.
58 * @author Pauli Anttila, Yannick Schaus - Initial contribution
59 * @author Michael Lobstein - Improvements for OH3
62 public class EpsonProjectorHandler extends BaseThingHandler {
63 private static final int DEFAULT_POLLING_INTERVAL_SEC = 10;
65 private final Logger logger = LoggerFactory.getLogger(EpsonProjectorHandler.class);
66 private final SerialPortManager serialPortManager;
68 private @Nullable ScheduledFuture<?> pollingJob;
69 private Optional<EpsonProjectorDevice> device = Optional.empty();
71 private boolean isPowerOn = false;
72 private int pollingInterval = DEFAULT_POLLING_INTERVAL_SEC;
74 public EpsonProjectorHandler(Thing thing, SerialPortManager serialPortManager) {
76 this.serialPortManager = serialPortManager;
80 public void handleCommand(ChannelUID channelUID, Command command) {
81 String channelId = channelUID.getId();
82 if (command instanceof RefreshType) {
83 Channel channel = this.thing.getChannel(channelUID);
84 if (channel != null) {
85 updateChannelState(channel);
88 EpsonProjectorCommandType epsonCommand = EpsonProjectorCommandType.getCommandType(channelId);
89 sendDataToDevice(epsonCommand, command);
94 public void initialize() {
95 EpsonProjectorConfiguration config = getConfigAs(EpsonProjectorConfiguration.class);
96 ThingTypeUID thingTypeUID = thing.getThingTypeUID();
98 if (THING_TYPE_PROJECTOR_SERIAL.equals(thingTypeUID)) {
99 device = Optional.of(new EpsonProjectorDevice(serialPortManager, config));
100 } else if (THING_TYPE_PROJECTOR_TCP.equals(thingTypeUID)) {
101 device = Optional.of(new EpsonProjectorDevice(config));
103 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
106 pollingInterval = config.pollingInterval;
107 device.ifPresent(dev -> dev.setScheduler(scheduler));
108 updateStatus(ThingStatus.UNKNOWN);
109 schedulePollingJob();
113 * Schedule the polling job
115 private void schedulePollingJob() {
118 pollingJob = scheduler.scheduleWithFixedDelay(() -> {
119 List<Channel> channels = this.thing.getChannels();
120 for (Channel channel : channels) {
121 // only query power & lamp time when projector is off
122 if (isPowerOn || (channel.getUID().getId().equals(CHANNEL_TYPE_POWER)
123 || channel.getUID().getId().equals(CHANNEL_TYPE_LAMPTIME))) {
124 updateChannelState(channel);
127 }, 0, (pollingInterval > 0) ? pollingInterval : DEFAULT_POLLING_INTERVAL_SEC, TimeUnit.SECONDS);
131 * Cancel the polling job
133 private void cancelPollingJob() {
134 ScheduledFuture<?> pollingJob = this.pollingJob;
135 if (pollingJob != null) {
136 pollingJob.cancel(true);
137 this.pollingJob = null;
142 public void dispose() {
148 private void updateChannelState(Channel channel) {
150 if (!isLinked(channel.getUID()) && !channel.getUID().getId().equals(CHANNEL_TYPE_POWER)) {
154 EpsonProjectorCommandType epsonCommand = EpsonProjectorCommandType.getCommandType(channel.getUID().getId());
156 State state = queryDataFromDevice(epsonCommand);
159 if (isLinked(channel.getUID())) {
160 updateState(channel.getUID(), state);
162 // the first valid response will cause the thing to go ONLINE
163 if (state != UnDefType.UNDEF) {
164 updateStatus(ThingStatus.ONLINE);
167 } catch (IllegalArgumentException e) {
168 logger.warn("Unknown channel {}", channel.getUID().getId());
173 private State queryDataFromDevice(EpsonProjectorCommandType commandType) {
174 EpsonProjectorDevice remoteController = device.get();
177 if (!remoteController.isConnected()) {
178 remoteController.connect();
181 if (!remoteController.isReady()) {
182 logger.debug("Refusing command {} while not ready", commandType.toString());
186 switch (commandType) {
188 Switch autoKeystone = remoteController.getAutoKeystone();
189 return autoKeystone == Switch.ON ? OnOffType.ON : OnOffType.OFF;
191 AspectRatio aspectRatio = remoteController.getAspectRatio();
192 return new StringType(aspectRatio.toString());
194 Background background = remoteController.getBackground();
195 return new StringType(background.toString());
197 int brightness = remoteController.getBrightness();
198 return new DecimalType(brightness);
200 ColorMode colorMode = remoteController.getColorMode();
201 return new StringType(colorMode.toString());
203 int ctemp = remoteController.getColorTemperature();
204 return new DecimalType(ctemp);
206 int contrast = remoteController.getContrast();
207 return new DecimalType(contrast);
209 int density = remoteController.getDensity();
210 return new DecimalType(density);
212 int err = remoteController.getError();
213 return new DecimalType(err);
215 String errString = remoteController.getErrorString();
216 return new StringType(errString);
218 int fleshColor = remoteController.getFleshColor();
219 return new DecimalType(fleshColor);
221 Switch freeze = remoteController.getFreeze();
222 return freeze == Switch.ON ? OnOffType.ON : OnOffType.OFF;
224 Gamma gamma = remoteController.getGamma();
225 return new StringType(gamma.toString());
227 int hKeystone = remoteController.getHorizontalKeystone();
228 return new DecimalType(hKeystone);
230 int hPosition = remoteController.getHorizontalPosition();
231 return new DecimalType(hPosition);
233 Switch hReverse = remoteController.getHorizontalReverse();
234 return hReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
238 int lampTime = remoteController.getLampTime();
239 return new DecimalType(lampTime);
241 Luminance luminance = remoteController.getLuminance();
242 return new StringType(luminance.toString());
244 Switch mute = remoteController.getMute();
245 return mute == Switch.ON ? OnOffType.ON : OnOffType.OFF;
247 PowerStatus powerStatus = remoteController.getPowerStatus();
248 if (isLinked(CHANNEL_TYPE_POWERSTATE)) {
249 updateState(CHANNEL_TYPE_POWERSTATE, new StringType(powerStatus.toString()));
252 if (powerStatus == PowerStatus.ON || powerStatus == PowerStatus.WARMUP) {
257 return OnOffType.OFF;
262 return new StringType(remoteController.getSource());
264 int tint = remoteController.getTint();
265 return new DecimalType(tint);
267 int vKeystone = remoteController.getVerticalKeystone();
268 return new DecimalType(vKeystone);
270 int volume = remoteController.getVolume();
271 return new DecimalType(volume);
273 int vPosition = remoteController.getVerticalPosition();
274 return new DecimalType(vPosition);
276 Switch vReverse = remoteController.getVerticalReverse();
277 return vReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
279 logger.warn("Unknown '{}' command!", commandType);
280 return UnDefType.UNDEF;
282 } catch (EpsonProjectorCommandException e) {
283 logger.debug("Error executing command '{}', {}", commandType, e.getMessage());
284 return UnDefType.UNDEF;
285 } catch (EpsonProjectorException e) {
286 logger.debug("Couldn't execute command '{}', {}", commandType, e.getMessage());
291 return UnDefType.UNDEF;
294 private void sendDataToDevice(EpsonProjectorCommandType commandType, Command command) {
295 EpsonProjectorDevice remoteController = device.get();
298 if (!remoteController.isConnected()) {
299 remoteController.connect();
302 if (!remoteController.isReady()) {
303 logger.debug("Refusing command '{}' while not ready", commandType.toString());
307 switch (commandType) {
309 remoteController.setAutoKeystone((command == OnOffType.ON ? Switch.ON : Switch.OFF));
312 remoteController.setAspectRatio(AspectRatio.valueOf(command.toString()));
315 remoteController.setBackground(Background.valueOf(command.toString()));
318 remoteController.setBrightness(((DecimalType) command).intValue());
321 remoteController.setColorMode(ColorMode.valueOf(command.toString()));
324 remoteController.setColorTemperature(((DecimalType) command).intValue());
327 remoteController.setContrast(((DecimalType) command).intValue());
330 remoteController.setDensity(((DecimalType) command).intValue());
333 logger.warn("'{}' is read only parameter", commandType);
336 logger.warn("'{}' is read only parameter", commandType);
339 remoteController.setFleshColor(((DecimalType) command).intValue());
342 remoteController.setFreeze(command == OnOffType.ON ? Switch.ON : Switch.OFF);
345 remoteController.setGamma(Gamma.valueOf(command.toString()));
348 remoteController.setHorizontalKeystone(((DecimalType) command).intValue());
351 remoteController.setHorizontalPosition(((DecimalType) command).intValue());
354 remoteController.setHorizontalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
357 remoteController.sendKeyCode(command.toString());
360 logger.warn("'{}' is read only parameter", commandType);
363 remoteController.setLuminance(Luminance.valueOf(command.toString()));
366 remoteController.setMute((command == OnOffType.ON ? Switch.ON : Switch.OFF));
369 if (command == OnOffType.ON) {
370 remoteController.setPower(Switch.ON);
373 remoteController.setPower(Switch.OFF);
378 logger.warn("'{}' is read only parameter", commandType);
381 remoteController.setSource(command.toString());
384 remoteController.setTint(((DecimalType) command).intValue());
387 remoteController.setVerticalKeystone(((DecimalType) command).intValue());
390 remoteController.setVolume(((DecimalType) command).intValue());
393 remoteController.setVerticalPosition(((DecimalType) command).intValue());
396 remoteController.setVerticalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
399 logger.warn("Unknown '{}' command!", commandType);
402 } catch (EpsonProjectorCommandException e) {
403 logger.debug("Error executing command '{}', {}", commandType, e.getMessage());
404 } catch (EpsonProjectorException e) {
405 logger.warn("Couldn't execute command '{}', {}", commandType, e.getMessage());
410 private void closeConnection() {
411 EpsonProjectorDevice remoteController = device.get();
413 logger.debug("Closing connection to device '{}'", this.thing.getUID());
414 remoteController.disconnect();
415 updateStatus(ThingStatus.OFFLINE);
416 } catch (EpsonProjectorException e) {
417 logger.debug("Error occurred when closing connection to device '{}'", this.thing.getUID(), e);