2 * Copyright (c) 2010-2023 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.neohub.internal;
15 import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
17 import javax.measure.Unit;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
22 import org.openhab.core.config.core.Configuration;
23 import org.openhab.core.library.types.OnOffType;
24 import org.openhab.core.library.unit.SIUnits;
25 import org.openhab.core.thing.Bridge;
26 import org.openhab.core.thing.Channel;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseThingHandler;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.openhab.core.types.State;
35 import org.openhab.core.types.UnDefType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * The {@link NeoBaseHandler} is the openHAB Handler for NeoPlug devices
42 * @author Andrew Fiddian-Green - Initial contribution
46 public class NeoBaseHandler extends BaseThingHandler {
48 protected final Logger logger = LoggerFactory.getLogger(NeoBaseHandler.class);
50 protected @Nullable NeoBaseConfiguration config;
55 private static final String MSG_FMT_DEVICE_CONFIG = "device \"{}\" needs to configured in hub!";
56 private static final String MSG_FMT_DEVICE_COMM = "device \"{}\" not communicating with hub!";
57 private static final String MSG_FMT_COMMAND_OK = "command for \"{}\" succeeded.";
58 private static final String MSG_FMT_COMMAND_BAD = "\"{}\" is an invalid or empty command!";
59 private static final String MSG_DEVICE_NAME_NOT_CONFIGURED = "the parameter \"deviceNameInHub\" is not configured";
62 * an object used to de-bounce state changes between openHAB and the NeoHub
64 protected NeoHubDebouncer debouncer = new NeoHubDebouncer();
66 public NeoBaseHandler(Thing thing) {
70 // ======== BaseThingHandler methods that are overridden =============
73 public void handleCommand(ChannelUID channelUID, Command command) {
77 if ((hub = getNeoHub()) != null) {
78 if (command == RefreshType.REFRESH) {
79 hub.startFastPollingBurst();
84 toNeoHubSendCommandSet(channelUID.getId(), command);
88 public void initialize() {
89 NeoBaseConfiguration config = getConfigAs(NeoBaseConfiguration.class);
91 if (config.deviceNameInHub.isEmpty()) {
92 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, MSG_DEVICE_NAME_NOT_CONFIGURED);
98 NeoHubHandler hub = getNeoHub();
100 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, MSG_HUB_CONFIG);
104 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING);
107 // ======== helper methods used by this class or descendants ===========
110 * this method is called back by the NeoHub handler to inform this handler about
111 * polling results from the hub handler
113 public void toBaseSendPollResponse(NeoHubAbstractDeviceData deviceData) {
114 NeoBaseConfiguration config = this.config;
115 if (config == null) {
119 AbstractRecord deviceRecord = deviceData.getDeviceRecord(config.deviceNameInHub);
121 if (deviceRecord == null) {
122 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
123 logger.warn(MSG_FMT_DEVICE_CONFIG, thing.getLabel());
127 ThingStatus thingStatus = getThing().getStatus();
128 if (deviceRecord.offline() && (thingStatus == ThingStatus.ONLINE)) {
129 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
130 logger.debug(MSG_FMT_DEVICE_COMM, thing.getLabel());
134 if ((!deviceRecord.offline()) && (thingStatus != ThingStatus.ONLINE)) {
135 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
138 toOpenHabSendChannelValues(deviceRecord);
142 * internal method used by by sendChannelValuesToOpenHab(); it checks the
143 * de-bouncer before actually sending the channel value to openHAB; or if the
144 * device has lost its connection to the RF mesh, either a) send no updates to
145 * OpenHAB or b) send state = undefined, depending on the value of a
146 * Configuration Parameter
148 protected void toOpenHabSendValueDebounced(String channelId, State state, boolean offline) {
150 * if the device has been lost from the RF mesh network there are two possible
151 * behaviors: either a) do not report a state value, or b) show an undefined
152 * state; the choice of a) or b) depends on whether the channel has the
153 * Configuration Parameter holdOnlineState=true
156 if (debouncer.timeExpired(channelId)) {
158 * in normal circumstances just forward the hub's reported state to OpenHAB
160 updateState(channelId, state);
163 ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
164 Channel channel = thing.getChannel(channelUID);
165 if (channel != null) {
166 Configuration config = channel.getConfiguration();
167 Object holdOnlineState = config.get(PARAM_HOLD_ONLINE_STATE);
168 if (holdOnlineState instanceof Boolean booleanValue && booleanValue.booleanValue()) {
170 * the Configuration Parameter "holdOnlineState" is True so do NOT send a
171 * state update to OpenHAB
177 * the Configuration Parameter "holdOnlineState" is either not existing or
178 * it is False so send a state=undefined update to OpenHAB
180 updateState(channelUID, UnDefType.UNDEF);
185 * sends a channel command & value from openHAB => NeoHub. It delegates upwards
186 * to the NeoHub to handle the command
188 protected void toNeoHubSendCommand(String channelId, Command command) {
189 String cmdStr = toNeoHubBuildCommandString(channelId, command);
191 if (!cmdStr.isEmpty()) {
192 NeoHubHandler hub = getNeoHub();
196 * issue command, check result, and update status accordingly
198 switch (hub.toNeoHubSendChannelValue(cmdStr)) {
200 logger.debug(MSG_FMT_COMMAND_OK, getThing().getLabel());
202 if (getThing().getStatus() != ThingStatus.ONLINE) {
203 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
206 // initialize the de-bouncer for this channel
207 debouncer.initialize(channelId);
211 case ERR_COMMUNICATION:
212 logger.debug(MSG_HUB_COMM, hub.getThing().getUID());
213 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
216 case ERR_INITIALIZATION:
217 logger.warn(MSG_HUB_CONFIG, hub.getThing().getUID());
218 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
222 logger.debug(MSG_HUB_CONFIG, "unknown");
225 logger.debug(MSG_FMT_COMMAND_BAD, command.toString());
230 * internal getter returns the NeoHub handler
232 * @return the neohub handler or null
234 protected @Nullable NeoHubHandler getNeoHub() {
238 if ((b = getBridge()) != null && (b.getHandler() instanceof NeoHubHandler neoHubHandler)) {
239 return neoHubHandler;
245 // ========= methods that MAY / MUST be overridden in descendants ============
248 * NOTE: descendant classes MUST override this method. It builds the command
249 * string to be sent to the NeoHub
251 protected String toNeoHubBuildCommandString(String channelId, Command command) {
256 * NOTE: descendant classes MAY override this method e.g. to send additional
257 * commands for dependent channels (if any)
259 protected void toNeoHubSendCommandSet(String channelId, Command command) {
260 toNeoHubSendCommand(channelId, command);
264 * NOTE: descendant classes MUST override this method method by which the
265 * handler informs openHAB about channel state changes
267 protected void toOpenHabSendChannelValues(AbstractRecord deviceRecord) {
270 protected OnOffType invert(OnOffType value) {
271 return OnOffType.from(value == OnOffType.OFF);
274 protected Unit<?> getTemperatureUnit() {
276 NeoHubHandler hub = getNeoHub();
278 return hub.getTemperatureUnit();
280 return SIUnits.CELSIUS;