]> git.basschouten.com Git - openhab-addons.git/blob
d9029b21de245174acc649e79c65c3738a053c0a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.epsonprojector.internal.handler;
14
15 import static org.openhab.binding.epsonprojector.internal.EpsonProjectorBindingConstants.*;
16
17 import java.util.List;
18 import java.util.Optional;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21
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;
53
54 /**
55  * The {@link EpsonProjectorHandler} is responsible for handling commands, which are
56  * sent to one of the channels.
57  *
58  * @author Pauli Anttila, Yannick Schaus - Initial contribution
59  * @author Michael Lobstein - Improvements for OH3
60  */
61 @NonNullByDefault
62 public class EpsonProjectorHandler extends BaseThingHandler {
63     private static final int DEFAULT_POLLING_INTERVAL_SEC = 10;
64
65     private final Logger logger = LoggerFactory.getLogger(EpsonProjectorHandler.class);
66     private final SerialPortManager serialPortManager;
67
68     private @Nullable ScheduledFuture<?> pollingJob;
69     private Optional<EpsonProjectorDevice> device = Optional.empty();
70
71     private boolean isPowerOn = false;
72     private int pollingInterval = DEFAULT_POLLING_INTERVAL_SEC;
73
74     public EpsonProjectorHandler(Thing thing, SerialPortManager serialPortManager) {
75         super(thing);
76         this.serialPortManager = serialPortManager;
77     }
78
79     @Override
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);
86             }
87         } else {
88             EpsonProjectorCommandType epsonCommand = EpsonProjectorCommandType.getCommandType(channelId);
89             sendDataToDevice(epsonCommand, command);
90         }
91     }
92
93     @Override
94     public void initialize() {
95         EpsonProjectorConfiguration config = getConfigAs(EpsonProjectorConfiguration.class);
96         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
97
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));
102         } else {
103             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
104         }
105
106         pollingInterval = config.pollingInterval;
107         device.ifPresent(dev -> dev.setScheduler(scheduler));
108         updateStatus(ThingStatus.UNKNOWN);
109         schedulePollingJob();
110     }
111
112     /**
113      * Schedule the polling job
114      */
115     private void schedulePollingJob() {
116         cancelPollingJob();
117
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);
125                 }
126             }
127         }, 0, (pollingInterval > 0) ? pollingInterval : DEFAULT_POLLING_INTERVAL_SEC, TimeUnit.SECONDS);
128     }
129
130     /**
131      * Cancel the polling job
132      */
133     private void cancelPollingJob() {
134         ScheduledFuture<?> pollingJob = this.pollingJob;
135         if (pollingJob != null) {
136             pollingJob.cancel(true);
137             this.pollingJob = null;
138         }
139     }
140
141     @Override
142     public void dispose() {
143         cancelPollingJob();
144         closeConnection();
145         super.dispose();
146     }
147
148     private void updateChannelState(Channel channel) {
149         try {
150             if (!isLinked(channel.getUID()) && !channel.getUID().getId().equals(CHANNEL_TYPE_POWER)) {
151                 return;
152             }
153
154             EpsonProjectorCommandType epsonCommand = EpsonProjectorCommandType.getCommandType(channel.getUID().getId());
155
156             State state = queryDataFromDevice(epsonCommand);
157
158             if (state != null) {
159                 updateStatus(ThingStatus.ONLINE);
160                 if (isLinked(channel.getUID())) {
161                     updateState(channel.getUID(), state);
162                 }
163             }
164         } catch (IllegalArgumentException e) {
165             logger.warn("Unknown channel {}", channel.getUID().getId());
166         }
167     }
168
169     @Nullable
170     private State queryDataFromDevice(EpsonProjectorCommandType commandType) {
171         EpsonProjectorDevice remoteController = device.get();
172
173         try {
174             if (!remoteController.isConnected()) {
175                 remoteController.connect();
176             }
177
178             if (!remoteController.isReady()) {
179                 logger.debug("Refusing command {} while not ready", commandType.toString());
180                 return null;
181             }
182
183             switch (commandType) {
184                 case AKEYSTONE:
185                     Switch autoKeystone = remoteController.getAutoKeystone();
186                     return autoKeystone == Switch.ON ? OnOffType.ON : OnOffType.OFF;
187                 case ASPECT_RATIO:
188                     AspectRatio aspectRatio = remoteController.getAspectRatio();
189                     return new StringType(aspectRatio.toString());
190                 case BACKGROUND:
191                     Background background = remoteController.getBackground();
192                     return new StringType(background.toString());
193                 case BRIGHTNESS:
194                     int brightness = remoteController.getBrightness();
195                     return new DecimalType(brightness);
196                 case COLOR_MODE:
197                     ColorMode colorMode = remoteController.getColorMode();
198                     return new StringType(colorMode.toString());
199                 case COLOR_TEMP:
200                     int ctemp = remoteController.getColorTemperature();
201                     return new DecimalType(ctemp);
202                 case CONTRAST:
203                     int contrast = remoteController.getContrast();
204                     return new DecimalType(contrast);
205                 case DENSITY:
206                     int density = remoteController.getDensity();
207                     return new DecimalType(density);
208                 case ERR_CODE:
209                     int err = remoteController.getError();
210                     return new DecimalType(err);
211                 case ERR_MESSAGE:
212                     String errString = remoteController.getErrorString();
213                     return new StringType(errString);
214                 case FLESH_TEMP:
215                     int fleshColor = remoteController.getFleshColor();
216                     return new DecimalType(fleshColor);
217                 case FREEZE:
218                     Switch freeze = remoteController.getFreeze();
219                     return freeze == Switch.ON ? OnOffType.ON : OnOffType.OFF;
220                 case GAMMA:
221                     Gamma gamma = remoteController.getGamma();
222                     return new StringType(gamma.toString());
223                 case HKEYSTONE:
224                     int hKeystone = remoteController.getHorizontalKeystone();
225                     return new DecimalType(hKeystone);
226                 case HPOSITION:
227                     int hPosition = remoteController.getHorizontalPosition();
228                     return new DecimalType(hPosition);
229                 case HREVERSE:
230                     Switch hReverse = remoteController.getHorizontalReverse();
231                     return hReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
232                 case KEY_CODE:
233                     break;
234                 case LAMP_TIME:
235                     int lampTime = remoteController.getLampTime();
236                     return new DecimalType(lampTime);
237                 case LUMINANCE:
238                     Luminance luminance = remoteController.getLuminance();
239                     return new StringType(luminance.toString());
240                 case MUTE:
241                     Switch mute = remoteController.getMute();
242                     return mute == Switch.ON ? OnOffType.ON : OnOffType.OFF;
243                 case POWER:
244                     PowerStatus powerStatus = remoteController.getPowerStatus();
245                     if (isLinked(CHANNEL_TYPE_POWERSTATE)) {
246                         updateState(CHANNEL_TYPE_POWERSTATE, new StringType(powerStatus.toString()));
247                     }
248
249                     if (powerStatus == PowerStatus.ON || powerStatus == PowerStatus.WARMUP) {
250                         isPowerOn = true;
251                         return OnOffType.ON;
252                     } else {
253                         isPowerOn = false;
254                         return OnOffType.OFF;
255                     }
256                 case POWER_STATE:
257                     return null;
258                 case SOURCE:
259                     return new StringType(remoteController.getSource());
260                 case TINT:
261                     int tint = remoteController.getTint();
262                     return new DecimalType(tint);
263                 case VKEYSTONE:
264                     int vKeystone = remoteController.getVerticalKeystone();
265                     return new DecimalType(vKeystone);
266                 case VOLUME:
267                     int volume = remoteController.getVolume();
268                     return new DecimalType(volume);
269                 case VPOSITION:
270                     int vPosition = remoteController.getVerticalPosition();
271                     return new DecimalType(vPosition);
272                 case VREVERSE:
273                     Switch vReverse = remoteController.getVerticalReverse();
274                     return vReverse == Switch.ON ? OnOffType.ON : OnOffType.OFF;
275                 default:
276                     logger.warn("Unknown '{}' command!", commandType);
277                     return UnDefType.UNDEF;
278             }
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());
284             closeConnection();
285             return null;
286         }
287
288         return UnDefType.UNDEF;
289     }
290
291     private void sendDataToDevice(EpsonProjectorCommandType commandType, Command command) {
292         EpsonProjectorDevice remoteController = device.get();
293
294         try {
295             if (!remoteController.isConnected()) {
296                 remoteController.connect();
297             }
298
299             if (!remoteController.isReady()) {
300                 logger.debug("Refusing command '{}' while not ready", commandType.toString());
301                 return;
302             }
303
304             switch (commandType) {
305                 case AKEYSTONE:
306                     remoteController.setAutoKeystone((command == OnOffType.ON ? Switch.ON : Switch.OFF));
307                     break;
308                 case ASPECT_RATIO:
309                     remoteController.setAspectRatio(AspectRatio.valueOf(command.toString()));
310                     break;
311                 case BACKGROUND:
312                     remoteController.setBackground(Background.valueOf(command.toString()));
313                     break;
314                 case BRIGHTNESS:
315                     remoteController.setBrightness(((DecimalType) command).intValue());
316                     break;
317                 case COLOR_MODE:
318                     remoteController.setColorMode(ColorMode.valueOf(command.toString()));
319                     break;
320                 case COLOR_TEMP:
321                     remoteController.setColorTemperature(((DecimalType) command).intValue());
322                     break;
323                 case CONTRAST:
324                     remoteController.setContrast(((DecimalType) command).intValue());
325                     break;
326                 case DENSITY:
327                     remoteController.setDensity(((DecimalType) command).intValue());
328                     break;
329                 case ERR_CODE:
330                     logger.warn("'{}' is read only parameter", commandType);
331                     break;
332                 case ERR_MESSAGE:
333                     logger.warn("'{}' is read only parameter", commandType);
334                     break;
335                 case FLESH_TEMP:
336                     remoteController.setFleshColor(((DecimalType) command).intValue());
337                     break;
338                 case FREEZE:
339                     remoteController.setFreeze(command == OnOffType.ON ? Switch.ON : Switch.OFF);
340                     break;
341                 case GAMMA:
342                     remoteController.setGamma(Gamma.valueOf(command.toString()));
343                     break;
344                 case HKEYSTONE:
345                     remoteController.setHorizontalKeystone(((DecimalType) command).intValue());
346                     break;
347                 case HPOSITION:
348                     remoteController.setHorizontalPosition(((DecimalType) command).intValue());
349                     break;
350                 case HREVERSE:
351                     remoteController.setHorizontalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
352                     break;
353                 case KEY_CODE:
354                     remoteController.sendKeyCode(command.toString());
355                     break;
356                 case LAMP_TIME:
357                     logger.warn("'{}' is read only parameter", commandType);
358                     break;
359                 case LUMINANCE:
360                     remoteController.setLuminance(Luminance.valueOf(command.toString()));
361                     break;
362                 case MUTE:
363                     remoteController.setMute((command == OnOffType.ON ? Switch.ON : Switch.OFF));
364                     break;
365                 case POWER:
366                     if (command == OnOffType.ON) {
367                         remoteController.setPower(Switch.ON);
368                         isPowerOn = true;
369                     } else {
370                         remoteController.setPower(Switch.OFF);
371                         isPowerOn = false;
372                     }
373                     break;
374                 case POWER_STATE:
375                     logger.warn("'{}' is read only parameter", commandType);
376                     break;
377                 case SOURCE:
378                     remoteController.setSource(command.toString());
379                     break;
380                 case TINT:
381                     remoteController.setTint(((DecimalType) command).intValue());
382                     break;
383                 case VKEYSTONE:
384                     remoteController.setVerticalKeystone(((DecimalType) command).intValue());
385                     break;
386                 case VOLUME:
387                     remoteController.setVolume(((DecimalType) command).intValue());
388                     break;
389                 case VPOSITION:
390                     remoteController.setVerticalPosition(((DecimalType) command).intValue());
391                     break;
392                 case VREVERSE:
393                     remoteController.setVerticalReverse((command == OnOffType.ON ? Switch.ON : Switch.OFF));
394                     break;
395                 default:
396                     logger.warn("Unknown '{}' command!", commandType);
397                     break;
398             }
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());
403             closeConnection();
404         }
405     }
406
407     private void closeConnection() {
408         EpsonProjectorDevice remoteController = device.get();
409         try {
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);
415         }
416     }
417 }