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.ecobee.internal.handler;
15 import static org.openhab.binding.ecobee.internal.EcobeeBindingConstants.*;
18 import java.util.concurrent.ConcurrentHashMap;
20 import org.apache.commons.lang3.text.WordUtils;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.ecobee.internal.config.EcobeeSensorConfiguration;
23 import org.openhab.binding.ecobee.internal.dto.thermostat.RemoteSensorCapabilityDTO;
24 import org.openhab.binding.ecobee.internal.dto.thermostat.RemoteSensorDTO;
25 import org.openhab.core.library.unit.Units;
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.ThingStatusInfo;
32 import org.openhab.core.thing.binding.BaseThingHandler;
33 import org.openhab.core.thing.binding.builder.ChannelBuilder;
34 import org.openhab.core.thing.binding.builder.ThingBuilder;
35 import org.openhab.core.thing.type.ChannelTypeUID;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.RefreshType;
38 import org.openhab.core.types.State;
39 import org.openhab.core.types.UnDefType;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link EcobeeSensorThingHandler} is responsible for updating the channels associated
45 * with an Ecobee remote sensor.
47 * @author Mark Hilbush - Initial contribution
50 public class EcobeeSensorThingHandler extends BaseThingHandler {
52 public static final String CAPABILITY_ADC = "adc";
53 public static final String CAPABILITY_CO2 = "co2";
54 public static final String CAPABILITY_DRY_CONTACT = "dryContact";
55 public static final String CAPABILITY_HUMIDITY = "humidity";
56 public static final String CAPABILITY_OCCUPANCY = "occupancy";
57 public static final String CAPABILITY_TEMPERATURE = "temperature";
58 public static final String CAPABILITY_UNKNOWN = "unknown";
60 private final Logger logger = LoggerFactory.getLogger(EcobeeSensorThingHandler.class);
62 private @NonNullByDefault({}) String sensorId;
64 private Map<String, State> stateCache = new ConcurrentHashMap<>();
66 public EcobeeSensorThingHandler(Thing thing) {
71 public void initialize() {
72 sensorId = getConfigAs(EcobeeSensorConfiguration.class).sensorId;
73 logger.debug("SensorThing: Initializing sensor '{}'", sensorId);
75 updateStatus(EcobeeUtils.isBridgeOnline(getBridge()) ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
79 public void dispose() {
80 logger.debug("SensorThing: Disposing sensor '{}'", sensorId);
84 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
85 if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
86 updateStatus(ThingStatus.ONLINE);
88 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
92 @SuppressWarnings("null")
94 public void handleCommand(ChannelUID channelUID, Command command) {
95 if (command instanceof RefreshType) {
96 State state = stateCache.get(channelUID.getId());
98 updateState(channelUID.getId(), state);
104 public void updateChannels(RemoteSensorDTO sensor) {
105 logger.debug("SensorThing: Updating channels for sensor '{}({})'", sensor.id, sensor.name);
106 updateChannel(CH_SENSOR_ID, EcobeeUtils.undefOrString(sensor.id));
107 updateChannel(CH_SENSOR_NAME, EcobeeUtils.undefOrString(sensor.name));
108 updateChannel(CH_SENSOR_TYPE, EcobeeUtils.undefOrString(sensor.type));
109 updateChannel(CH_SENSOR_CODE, EcobeeUtils.undefOrString(sensor.code));
110 updateChannel(CH_SENSOR_IN_USE, EcobeeUtils.undefOrOnOff(sensor.inUse));
111 for (RemoteSensorCapabilityDTO capability : sensor.capability) {
112 updateCapabilityChannels(capability);
116 private void updateCapabilityChannels(RemoteSensorCapabilityDTO capability) {
117 ChannelUID uid = new ChannelUID(thing.getUID(), capability.type);
118 Channel channel = thing.getChannel(uid);
119 if (channel == null) {
120 logger.debug("SensorThing: Create channel '{}'", uid);
121 ThingBuilder thingBuilder;
122 thingBuilder = editThing();
123 channel = ChannelBuilder.create(uid, getAcceptedItemType(capability.type))
124 .withLabel("Sensor " + WordUtils.capitalize(capability.type))
125 .withType(getChannelTypeUID(capability.type)).build();
126 thingBuilder.withChannel(channel);
127 updateThing(thingBuilder.build());
129 logger.trace("Capability '{}' has type '{}' with value '{}'", capability.id, capability.type, capability.value);
130 updateCapabilityState(capability.type, capability.value);
133 // adc, co2, dryContact, humidity, temperature, occupancy, unknown.
134 private String getAcceptedItemType(String capabilityType) {
135 String acceptedItemType;
136 switch (capabilityType) {
137 case CAPABILITY_TEMPERATURE:
138 acceptedItemType = "Number:Temperature";
140 case CAPABILITY_HUMIDITY:
141 acceptedItemType = "Number:Dimensionless";
143 case CAPABILITY_OCCUPANCY:
144 acceptedItemType = "Switch";
148 case CAPABILITY_DRY_CONTACT:
149 case CAPABILITY_UNKNOWN:
151 acceptedItemType = "String";
154 return acceptedItemType;
157 private ChannelTypeUID getChannelTypeUID(String capabilityType) {
158 ChannelTypeUID channelTypeUID;
159 switch (capabilityType) {
160 case CAPABILITY_TEMPERATURE:
161 channelTypeUID = CHANNELTYPEUID_TEMPERATURE;
163 case CAPABILITY_HUMIDITY:
164 channelTypeUID = CHANNELTYPEUID_HUMIDITY;
166 case CAPABILITY_OCCUPANCY:
167 channelTypeUID = CHANNELTYPEUID_OCCUPANCY;
171 case CAPABILITY_DRY_CONTACT:
172 case CAPABILITY_UNKNOWN:
174 channelTypeUID = CHANNELTYPEUID_GENERIC;
177 return channelTypeUID;
180 private void updateCapabilityState(String capabilityType, String value) {
182 switch (capabilityType) {
183 case CAPABILITY_TEMPERATURE:
185 state = EcobeeUtils.undefOrTemperature(Integer.parseInt(value));
186 } catch (NumberFormatException e) {
187 state = UnDefType.UNDEF;
190 case CAPABILITY_HUMIDITY:
192 state = EcobeeUtils.undefOrQuantity(Integer.parseInt(value), Units.PERCENT);
193 } catch (NumberFormatException e) {
194 state = UnDefType.UNDEF;
197 case CAPABILITY_OCCUPANCY:
198 state = EcobeeUtils.undefOrOnOff("true".equals(value));
202 case CAPABILITY_DRY_CONTACT:
203 case CAPABILITY_UNKNOWN:
205 state = EcobeeUtils.undefOrString(value);
208 updateChannel(capabilityType, state);
211 private void updateChannel(String channelId, State state) {
212 updateState(channelId, state);
213 stateCache.put(channelId, state);
216 private void clearSavedState() {