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 updateStatus(ThingStatus.ONLINE);
160 if (isLinked(channel.getUID())) {
161 updateState(channel.getUID(), state);
164 } catch (IllegalArgumentException e) {
165 logger.warn("Unknown channel {}", channel.getUID().getId());
170 private State queryDataFromDevice(EpsonProjectorCommandType commandType) {
171 EpsonProjectorDevice remoteController = device.get();
174 if (!remoteController.isConnected()) {
175 remoteController.connect();
178 if (!remoteController.isReady()) {
179 logger.debug("Refusing command {} while not ready", commandType.toString());
183 switch (commandType) {
185 Switch autoKeystone = remoteController.getAutoKeystone();
186 return autoKeystone == Switch.ON ? OnOffType.ON : OnOffType.OFF;
188 AspectRatio aspectRatio = remoteController.getAspectRatio();
189 return new StringType(aspectRatio.toString());
191 Background background = remoteController.getBackground();
192 return new StringType(background.toString());
194 int brightness = remoteController.getBrightness();
195 return new DecimalType(brightness);
197 ColorMode colorMode = remoteController.getColorMode();
198 return new StringType(colorMode.toString());
200 int ctemp = remoteController.getColorTemperature();
201 return new DecimalType(ctemp);
203 int contrast = remoteController.getContrast();
204 return new DecimalType(contrast);
206 int density = remoteController.getDensity();
207 return new DecimalType(density);
209 int err = remoteController.getError();
210 return new DecimalType(err);
212 String errString = remoteController.getErrorString();
213 return new StringType(errString);
215 int fleshColor = remoteController.getFleshColor();
216 return new DecimalType(fleshColor);
218 Switch freeze = remoteController.getFreeze();
219 return freeze == Switch.ON ? OnOffType.ON : OnOffType.OFF;
221 Gamma gamma = remoteController.getGamma();
222 return new StringType(gamma.toString());
224 int hKeystone = remoteController.getHorizontalKeystone();
225 return new DecimalType(hKeystone);
227 int hPosition = remoteController.getHorizontalPosition();
228 return new DecimalType(hPosition);
230 Switch hReverse = remoteController.getHorizontalReverse();
231 return hReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
235 int lampTime = remoteController.getLampTime();
236 return new DecimalType(lampTime);
238 Luminance luminance = remoteController.getLuminance();
239 return new StringType(luminance.toString());
241 Switch mute = remoteController.getMute();
242 return mute == Switch.ON ? OnOffType.ON : OnOffType.OFF;
244 PowerStatus powerStatus = remoteController.getPowerStatus();
245 if (isLinked(CHANNEL_TYPE_POWERSTATE)) {
246 updateState(CHANNEL_TYPE_POWERSTATE, new StringType(powerStatus.toString()));
249 if (powerStatus == PowerStatus.ON || powerStatus == PowerStatus.WARMUP) {
254 return OnOffType.OFF;
259 return new StringType(remoteController.getSource());
261 int tint = remoteController.getTint();
262 return new DecimalType(tint);
264 int vKeystone = remoteController.getVerticalKeystone();
265 return new DecimalType(vKeystone);
267 int volume = remoteController.getVolume();
268 return new DecimalType(volume);
270 int vPosition = remoteController.getVerticalPosition();
271 return new DecimalType(vPosition);
273 Switch vReverse = remoteController.getVerticalReverse();
274 return vReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
276 logger.warn("Unknown '{}' command!", commandType);
277 return UnDefType.UNDEF;
279 } catch (EpsonProjectorCommandException e) {
280 logger.debug("Error executing command '{}', {}", commandType, e.getMessage());
281 return UnDefType.UNDEF;
282 } catch (EpsonProjectorException e) {
283 logger.debug("Couldn't execute command '{}', {}", commandType, e.getMessage());
288 return UnDefType.UNDEF;
291 private void sendDataToDevice(EpsonProjectorCommandType commandType, Command command) {
292 EpsonProjectorDevice remoteController = device.get();
295 if (!remoteController.isConnected()) {
296 remoteController.connect();
299 if (!remoteController.isReady()) {
300 logger.debug("Refusing command '{}' while not ready", commandType.toString());
304 switch (commandType) {
306 remoteController.setAutoKeystone((command == OnOffType.ON ? Switch.ON : Switch.OFF));
309 remoteController.setAspectRatio(AspectRatio.valueOf(command.toString()));
312 remoteController.setBackground(Background.valueOf(command.toString()));
315 remoteController.setBrightness(((DecimalType) command).intValue());
318 remoteController.setColorMode(ColorMode.valueOf(command.toString()));
321 remoteController.setColorTemperature(((DecimalType) command).intValue());
324 remoteController.setContrast(((DecimalType) command).intValue());
327 remoteController.setDensity(((DecimalType) command).intValue());
330 logger.warn("'{}' is read only parameter", commandType);
333 logger.warn("'{}' is read only parameter", commandType);
336 remoteController.setFleshColor(((DecimalType) command).intValue());
339 remoteController.setFreeze(command == OnOffType.ON ? Switch.ON : Switch.OFF);
342 remoteController.setGamma(Gamma.valueOf(command.toString()));
345 remoteController.setHorizontalKeystone(((DecimalType) command).intValue());
348 remoteController.setHorizontalPosition(((DecimalType) command).intValue());
351 remoteController.setHorizontalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
354 remoteController.sendKeyCode(((DecimalType) command).intValue());
357 logger.warn("'{}' is read only parameter", commandType);
360 remoteController.setLuminance(Luminance.valueOf(command.toString()));
363 remoteController.setMute((command == OnOffType.ON ? Switch.ON : Switch.OFF));
366 if (command == OnOffType.ON) {
367 remoteController.setPower(Switch.ON);
370 remoteController.setPower(Switch.OFF);
375 logger.warn("'{}' is read only parameter", commandType);
378 remoteController.setSource(command.toString());
381 remoteController.setTint(((DecimalType) command).intValue());
384 remoteController.setVerticalKeystone(((DecimalType) command).intValue());
387 remoteController.setVolume(((DecimalType) command).intValue());
390 remoteController.setVerticalPosition(((DecimalType) command).intValue());
393 remoteController.setVerticalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
396 logger.warn("Unknown '{}' command!", commandType);
399 } catch (EpsonProjectorCommandException e) {
400 logger.debug("Error executing command '{}', {}", commandType, e.getMessage());
401 } catch (EpsonProjectorException e) {
402 logger.warn("Couldn't execute command '{}', {}", commandType, e.getMessage());
407 private void closeConnection() {
408 EpsonProjectorDevice remoteController = device.get();
410 logger.debug("Closing connection to device '{}'", this.thing.getUID());
411 remoteController.disconnect();
412 updateStatus(ThingStatus.OFFLINE);
413 } catch (EpsonProjectorException e) {
414 logger.debug("Error occurred when closing connection to device '{}'", this.thing.getUID(), e);