]> git.basschouten.com Git - openhab-addons.git/blob
26b465ed99440137d1a209ef7abe788bb37ad2f8
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.hdpowerview.internal.handler;
14
15 import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;
16
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
23 import org.openhab.binding.hdpowerview.internal.api.Firmware;
24 import org.openhab.binding.hdpowerview.internal.api.responses.RepeaterData;
25 import org.openhab.binding.hdpowerview.internal.config.HDPowerViewRepeaterConfiguration;
26 import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
27 import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException;
28 import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.UnDefType;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Handles commands for an HD PowerView Repeater
43  *
44  * @author Jacob Laursen - Initial contribution
45  */
46 @NonNullByDefault
47 public class HDPowerViewRepeaterHandler extends AbstractHubbedThingHandler {
48
49     private final Logger logger = LoggerFactory.getLogger(HDPowerViewRepeaterHandler.class);
50
51     private static final int REFRESH_INTERVAL_MINUTES = 5;
52     private static final int IDENTITY_PERIOD_SECONDS = 3;
53     private static final String COMMAND_IDENTIFY = "IDENTIFY";
54
55     private @Nullable ScheduledFuture<?> refreshStatusFuture = null;
56     private @Nullable ScheduledFuture<?> resetIdentifyStateFuture = null;
57     private int repeaterId;
58
59     public HDPowerViewRepeaterHandler(Thing thing) {
60         super(thing);
61     }
62
63     @Override
64     public void initialize() {
65         repeaterId = getConfigAs(HDPowerViewRepeaterConfiguration.class).id;
66         logger.debug("Initializing repeater handler for repeater {}", repeaterId);
67         if (repeaterId <= 0) {
68             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
69                     "@text/offline.conf-error.invalid-id");
70             return;
71         }
72         Bridge bridge = getBridge();
73         if (bridge == null) {
74             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
75             return;
76         }
77         if (!(bridge.getHandler() instanceof HDPowerViewHubHandler)) {
78             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED,
79                     "@text/offline.conf-error.invalid-bridge-handler");
80             return;
81         }
82         ThingStatus bridgeStatus = bridge.getStatus();
83         if (bridgeStatus == ThingStatus.ONLINE) {
84             updateStatus(ThingStatus.UNKNOWN);
85         } else {
86             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
87         }
88         scheduleRefreshJob();
89     }
90
91     @Override
92     public void dispose() {
93         logger.debug("Disposing repeater handler for repeater {}", repeaterId);
94         cancelRefreshJob();
95         cancelResetIdentifyStateJob();
96     }
97
98     @Override
99     public void handleCommand(ChannelUID channelUID, Command command) {
100         HDPowerViewHubHandler bridge = getBridgeHandler();
101         if (bridge == null) {
102             logger.warn("Missing bridge handler");
103             return;
104         }
105         HDPowerViewWebTargets webTargets = bridge.getWebTargets();
106         if (webTargets == null) {
107             logger.warn("Web targets not initialized");
108             return;
109         }
110
111         try {
112             RepeaterData repeaterData;
113
114             switch (channelUID.getId()) {
115                 case CHANNEL_REPEATER_IDENTIFY:
116                     if (command instanceof StringType) {
117                         if (COMMAND_IDENTIFY.equals(((StringType) command).toString())) {
118                             repeaterData = webTargets.identifyRepeater(repeaterId);
119                             scheduler.submit(() -> updatePropertyAndState(repeaterData));
120                             cancelResetIdentifyStateJob();
121                             resetIdentifyStateFuture = scheduler.schedule(() -> {
122                                 updateState(CHANNEL_REPEATER_IDENTIFY, UnDefType.UNDEF);
123                             }, IDENTITY_PERIOD_SECONDS, TimeUnit.SECONDS);
124                         } else {
125                             logger.warn("Unsupported command: {}. Supported commands are: " + COMMAND_IDENTIFY,
126                                     command);
127                         }
128                     }
129                     break;
130                 case CHANNEL_REPEATER_BLINKING_ENABLED:
131                     repeaterData = webTargets.enableRepeaterBlinking(repeaterId, OnOffType.ON == command);
132                     scheduler.submit(() -> updatePropertyAndState(repeaterData));
133                     break;
134             }
135         } catch (HubInvalidResponseException e) {
136             Throwable cause = e.getCause();
137             if (cause == null) {
138                 logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
139             } else {
140                 logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
141             }
142         } catch (HubMaintenanceException e) {
143             // exceptions are logged in HDPowerViewWebTargets
144         } catch (HubException e) {
145             logger.warn("Unexpected error: {}", e.getMessage());
146         }
147     }
148
149     private void cancelResetIdentifyStateJob() {
150         ScheduledFuture<?> scheduledJob = resetIdentifyStateFuture;
151         if (scheduledJob != null) {
152             scheduledJob.cancel(true);
153         }
154         resetIdentifyStateFuture = null;
155     }
156
157     private void scheduleRefreshJob() {
158         cancelRefreshJob();
159         logger.debug("Scheduling poll for repeater {} now, then every {} minutes", repeaterId,
160                 REFRESH_INTERVAL_MINUTES);
161         this.refreshStatusFuture = scheduler.scheduleWithFixedDelay(this::poll, 0, REFRESH_INTERVAL_MINUTES,
162                 TimeUnit.MINUTES);
163     }
164
165     private void cancelRefreshJob() {
166         ScheduledFuture<?> future = this.refreshStatusFuture;
167         if (future != null) {
168             future.cancel(false);
169         }
170         this.refreshStatusFuture = null;
171     }
172
173     private synchronized void poll() {
174         HDPowerViewHubHandler bridge = getBridgeHandler();
175         if (bridge == null) {
176             logger.warn("Missing bridge handler");
177             return;
178         }
179         HDPowerViewWebTargets webTargets = bridge.getWebTargets();
180         if (webTargets == null) {
181             logger.warn("Web targets not initialized");
182             return;
183         }
184         try {
185             logger.debug("Polling for status information");
186
187             RepeaterData repeaterData = webTargets.getRepeater(repeaterId);
188             updatePropertyAndState(repeaterData);
189
190         } catch (HubInvalidResponseException e) {
191             Throwable cause = e.getCause();
192             if (cause == null) {
193                 logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
194             } else {
195                 logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
196             }
197         } catch (HubMaintenanceException e) {
198             // exceptions are logged in HDPowerViewWebTargets
199         } catch (HubException e) {
200             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.getMessage());
201         }
202     }
203
204     private void updatePropertyAndState(RepeaterData repeaterData) {
205         updateStatus(ThingStatus.ONLINE);
206
207         Firmware firmware = repeaterData.firmware;
208         if (firmware != null) {
209             logger.debug("Repeater firmware version received: {}", firmware.toString());
210             updateProperty(Thing.PROPERTY_FIRMWARE_VERSION, firmware.toString());
211         } else {
212             logger.warn("Repeater firmware version missing in response");
213         }
214
215         updateState(CHANNEL_REPEATER_BLINKING_ENABLED, repeaterData.blinkEnabled ? OnOffType.ON : OnOffType.OFF);
216     }
217 }