2 * Copyright (c) 2010-2022 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.hdpowerview.internal.handler;
15 import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
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;
42 * Handles commands for an HD PowerView Repeater
44 * @author Jacob Laursen - Initial contribution
47 public class HDPowerViewRepeaterHandler extends AbstractHubbedThingHandler {
49 private final Logger logger = LoggerFactory.getLogger(HDPowerViewRepeaterHandler.class);
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";
55 private @Nullable ScheduledFuture<?> refreshStatusFuture = null;
56 private @Nullable ScheduledFuture<?> resetIdentifyStateFuture = null;
57 private int repeaterId;
59 public HDPowerViewRepeaterHandler(Thing thing) {
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");
72 Bridge bridge = getBridge();
74 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
77 if (!(bridge.getHandler() instanceof HDPowerViewHubHandler)) {
78 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED,
79 "@text/offline.conf-error.invalid-bridge-handler");
82 ThingStatus bridgeStatus = bridge.getStatus();
83 if (bridgeStatus == ThingStatus.ONLINE) {
84 updateStatus(ThingStatus.UNKNOWN);
86 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
92 public void dispose() {
93 logger.debug("Disposing repeater handler for repeater {}", repeaterId);
95 cancelResetIdentifyStateJob();
99 public void handleCommand(ChannelUID channelUID, Command command) {
100 HDPowerViewHubHandler bridge = getBridgeHandler();
101 if (bridge == null) {
102 logger.warn("Missing bridge handler");
105 HDPowerViewWebTargets webTargets = bridge.getWebTargets();
106 if (webTargets == null) {
107 logger.warn("Web targets not initialized");
112 RepeaterData repeaterData;
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);
125 logger.warn("Unsupported command: {}. Supported commands are: " + COMMAND_IDENTIFY,
130 case CHANNEL_REPEATER_BLINKING_ENABLED:
131 repeaterData = webTargets.enableRepeaterBlinking(repeaterId, OnOffType.ON == command);
132 scheduler.submit(() -> updatePropertyAndState(repeaterData));
135 } catch (HubInvalidResponseException e) {
136 Throwable cause = e.getCause();
138 logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
140 logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
142 } catch (HubMaintenanceException e) {
143 // exceptions are logged in HDPowerViewWebTargets
144 } catch (HubException e) {
145 logger.warn("Unexpected error: {}", e.getMessage());
149 private void cancelResetIdentifyStateJob() {
150 ScheduledFuture<?> scheduledJob = resetIdentifyStateFuture;
151 if (scheduledJob != null) {
152 scheduledJob.cancel(true);
154 resetIdentifyStateFuture = null;
157 private void scheduleRefreshJob() {
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,
165 private void cancelRefreshJob() {
166 ScheduledFuture<?> future = this.refreshStatusFuture;
167 if (future != null) {
168 future.cancel(false);
170 this.refreshStatusFuture = null;
173 private synchronized void poll() {
174 HDPowerViewHubHandler bridge = getBridgeHandler();
175 if (bridge == null) {
176 logger.warn("Missing bridge handler");
179 HDPowerViewWebTargets webTargets = bridge.getWebTargets();
180 if (webTargets == null) {
181 logger.warn("Web targets not initialized");
185 logger.debug("Polling for status information");
187 RepeaterData repeaterData = webTargets.getRepeater(repeaterId);
188 updatePropertyAndState(repeaterData);
190 } catch (HubInvalidResponseException e) {
191 Throwable cause = e.getCause();
193 logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
195 logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
197 } catch (HubMaintenanceException e) {
198 // exceptions are logged in HDPowerViewWebTargets
199 } catch (HubException e) {
200 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.getMessage());
204 private void updatePropertyAndState(RepeaterData repeaterData) {
205 updateStatus(ThingStatus.ONLINE);
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());
212 logger.warn("Repeater firmware version missing in response");
215 updateState(CHANNEL_REPEATER_BLINKING_ENABLED, repeaterData.blinkEnabled ? OnOffType.ON : OnOffType.OFF);