]> git.basschouten.com Git - openhab-addons.git/blob
1b7171a600ef382f0fcd151d69c4b423d2ff7e5c
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.enigma2.internal.handler;
14
15 import static org.openhab.binding.enigma2.internal.Enigma2BindingConstants.*;
16
17 import java.time.LocalDateTime;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Optional;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.enigma2.internal.Enigma2Client;
29 import org.openhab.binding.enigma2.internal.Enigma2Configuration;
30 import org.openhab.binding.enigma2.internal.Enigma2RemoteKey;
31 import org.openhab.binding.enigma2.internal.actions.Enigma2Actions;
32 import org.openhab.core.library.types.*;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.binding.BaseThingHandler;
38 import org.openhab.core.thing.binding.ThingHandlerService;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link Enigma2Handler} is responsible for handling commands, which are
46  * sent to one of the channels.
47  *
48  * @author Guido Dolfen - Initial contribution
49  */
50 @NonNullByDefault
51 public class Enigma2Handler extends BaseThingHandler {
52     private final Logger logger = LoggerFactory.getLogger(Enigma2Handler.class);
53     private Enigma2Configuration configuration = new Enigma2Configuration();
54     private Optional<Enigma2Client> enigma2Client = Optional.empty();
55     private @Nullable ScheduledFuture<?> refreshJob;
56     private LocalDateTime lastAnswerTime = LocalDateTime.now();
57
58     public Enigma2Handler(Thing thing) {
59         super(thing);
60     }
61
62     @Override
63     public void initialize() {
64         configuration = getConfigAs(Enigma2Configuration.class);
65         if (configuration.host.isEmpty()) {
66             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "host must not be empty");
67         } else if (configuration.timeout <= 0 || configuration.timeout > 300) {
68             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
69                     "timeout must be between 0 and 300 seconds");
70         } else if (configuration.refreshInterval <= 0 || configuration.refreshInterval > 3600) {
71             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
72                     "refreshInterval must be between 0 and 3600 seconds");
73         }
74         enigma2Client = Optional.of(new Enigma2Client(configuration.host, configuration.user, configuration.password,
75                 configuration.timeout));
76         refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 2, configuration.refreshInterval,
77                 TimeUnit.SECONDS);
78     }
79
80     private void refresh() {
81         getEnigma2Client().ifPresent(client -> {
82             boolean online = client.refresh();
83             if (online) {
84                 updateStatus(ThingStatus.ONLINE);
85                 updateState(CHANNEL_POWER, client.isPower() ? OnOffType.ON : OnOffType.OFF);
86                 updateState(CHANNEL_MUTE, client.isMute() ? OnOffType.ON : OnOffType.OFF);
87                 updateState(CHANNEL_VOLUME, new PercentType(client.getVolume()));
88                 updateState(CHANNEL_CHANNEL, new StringType(client.getChannel()));
89                 updateState(CHANNEL_TITLE, new StringType(client.getTitle()));
90                 updateState(CHANNEL_DESCRIPTION, new StringType(client.getDescription()));
91                 if (lastAnswerTime.isBefore(client.getLastAnswerTime())) {
92                     lastAnswerTime = client.getLastAnswerTime();
93                     updateState(CHANNEL_ANSWER, new StringType(client.getAnswer()));
94                 }
95             } else {
96                 updateStatus(ThingStatus.OFFLINE);
97             }
98         });
99     }
100
101     @Override
102     public void dispose() {
103         ScheduledFuture<?> job = this.refreshJob;
104         if (job != null) {
105             job.cancel(true);
106         }
107         this.refreshJob = null;
108     }
109
110     @Override
111     public void handleCommand(ChannelUID channelUID, Command command) {
112         logger.debug("handleCommand({},{})", channelUID, command);
113         getEnigma2Client().ifPresent(client -> {
114             switch (channelUID.getId()) {
115                 case CHANNEL_POWER:
116                     handlePower(channelUID, command, client);
117                     break;
118                 case CHANNEL_CHANNEL:
119                     handleChannel(channelUID, command, client);
120                     break;
121                 case CHANNEL_MEDIA_PLAYER:
122                     handleMediaPlayer(channelUID, command);
123                     break;
124                 case CHANNEL_MEDIA_STOP:
125                     handleMediaStop(channelUID, command);
126                     break;
127                 case CHANNEL_MUTE:
128                     handleMute(channelUID, command, client);
129                     break;
130                 case CHANNEL_VOLUME:
131                     handleVolume(channelUID, command, client);
132                     break;
133                 case CHANNEL_TITLE:
134                     handleTitle(channelUID, command, client);
135                     break;
136                 case CHANNEL_DESCRIPTION:
137                     handleDescription(channelUID, command, client);
138                     break;
139                 case CHANNEL_ANSWER:
140                     handleAnswer(channelUID, command, client);
141                     break;
142                 default:
143                     logger.debug("Channel {} is not supported", channelUID);
144                     break;
145             }
146         });
147     }
148
149     private void handleVolume(ChannelUID channelUID, Command command, Enigma2Client client) {
150         if (command instanceof RefreshType) {
151             client.refreshVolume();
152             updateState(channelUID, new PercentType(client.getVolume()));
153         } else if (command instanceof PercentType) {
154             client.setVolume(((PercentType) command).intValue());
155         } else if (command instanceof DecimalType) {
156             client.setVolume(((DecimalType) command).intValue());
157         } else {
158             logger.info("Channel {} only accepts PercentType, DecimalType, RefreshType. Type was {}.", channelUID,
159                     command.getClass());
160         }
161     }
162
163     private void handleMute(ChannelUID channelUID, Command command, Enigma2Client client) {
164         if (command instanceof RefreshType) {
165             client.refreshVolume();
166             updateState(channelUID, client.isMute() ? OnOffType.ON : OnOffType.OFF);
167         } else if (OnOffType.ON.equals(command)) {
168             client.setMute(true);
169         } else if (OnOffType.OFF.equals(command)) {
170             client.setMute(false);
171         } else {
172             logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
173         }
174     }
175
176     private void handleAnswer(ChannelUID channelUID, Command command, Enigma2Client client) {
177         if (command instanceof RefreshType) {
178             client.refreshAnswer();
179             if (lastAnswerTime.isBefore(client.getLastAnswerTime())) {
180                 lastAnswerTime = client.getLastAnswerTime();
181                 updateState(channelUID, new StringType(client.getAnswer()));
182             }
183         } else {
184             logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
185         }
186     }
187
188     private void handleMediaStop(ChannelUID channelUID, Command command) {
189         if (command instanceof RefreshType) {
190             return;
191         } else if (command instanceof OnOffType) {
192             sendRcCommand(Enigma2RemoteKey.STOP);
193         } else {
194             logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
195         }
196     }
197
198     private void handleMediaPlayer(ChannelUID channelUID, Command command) {
199         if (RefreshType.REFRESH == command) {
200             return;
201         } else if (PlayPauseType.PLAY == command) {
202             sendRcCommand(Enigma2RemoteKey.PLAY);
203         } else if (PlayPauseType.PAUSE == command) {
204             sendRcCommand(Enigma2RemoteKey.PAUSE);
205         } else if (NextPreviousType.NEXT == command) {
206             sendRcCommand(Enigma2RemoteKey.FAST_FORWARD);
207         } else if (NextPreviousType.PREVIOUS == command) {
208             sendRcCommand(Enigma2RemoteKey.FAST_BACKWARD);
209         } else {
210             logger.info("Channel {} only accepts PlayPauseType, NextPreviousType, RefreshType. Type was {}.",
211                     channelUID, command.getClass());
212         }
213     }
214
215     private void handleChannel(ChannelUID channelUID, Command command, Enigma2Client client) {
216         if (command instanceof RefreshType) {
217             client.refreshChannel();
218             updateState(channelUID, new StringType(client.getChannel()));
219         } else if (command instanceof StringType) {
220             client.setChannel(command.toString());
221         } else {
222             logger.info("Channel {} only accepts StringType, RefreshType. Type was {}.", channelUID,
223                     command.getClass());
224         }
225     }
226
227     private void handleTitle(ChannelUID channelUID, Command command, Enigma2Client client) {
228         if (command instanceof RefreshType) {
229             client.refreshEpg();
230             updateState(channelUID, new StringType(client.getTitle()));
231         } else {
232             logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
233         }
234     }
235
236     private void handleDescription(ChannelUID channelUID, Command command, Enigma2Client client) {
237         if (command instanceof RefreshType) {
238             client.refreshEpg();
239             updateState(channelUID, new StringType(client.getDescription()));
240         } else {
241             logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
242         }
243     }
244
245     private void handlePower(ChannelUID channelUID, Command command, Enigma2Client client) {
246         if (RefreshType.REFRESH == command) {
247             client.refreshPower();
248             updateState(channelUID, client.isPower() ? OnOffType.ON : OnOffType.OFF);
249         } else if (OnOffType.ON == command) {
250             client.setPower(true);
251         } else if (OnOffType.OFF == command) {
252             client.setPower(false);
253         } else {
254             logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
255         }
256     }
257
258     public void sendRcCommand(String rcButton) {
259         logger.debug("sendRcCommand({})", rcButton);
260         try {
261             Enigma2RemoteKey remoteKey = Enigma2RemoteKey.valueOf(rcButton);
262             sendRcCommand(remoteKey);
263         } catch (IllegalArgumentException ex) {
264             logger.warn("{} is not a valid value for button - available are: {}", rcButton,
265                     Stream.of(Enigma2RemoteKey.values()).map(b -> b.name()).collect(Collectors.joining(", ")));
266         }
267     }
268
269     private void sendRcCommand(Enigma2RemoteKey remoteKey) {
270         getEnigma2Client().ifPresent(client -> client.sendRcCommand(remoteKey.getValue()));
271     }
272
273     public void sendInfo(int timeout, String text) {
274         getEnigma2Client().ifPresent(client -> client.sendInfo(timeout, text));
275     }
276
277     public void sendWarning(int timeout, String text) {
278         getEnigma2Client().ifPresent(client -> client.sendWarning(timeout, text));
279     }
280
281     public void sendError(int timeout, String text) {
282         getEnigma2Client().ifPresent(client -> client.sendError(timeout, text));
283     }
284
285     public void sendQuestion(int timeout, String text) {
286         getEnigma2Client().ifPresent(client -> client.sendQuestion(timeout, text));
287     }
288
289     @Override
290     public Collection<Class<? extends ThingHandlerService>> getServices() {
291         return Collections.singleton(Enigma2Actions.class);
292     }
293
294     /**
295      * Getter for Test-Injection
296      * 
297      * @return Enigma2Client.
298      */
299     Optional<Enigma2Client> getEnigma2Client() {
300         return enigma2Client;
301     }
302 }