]> git.basschouten.com Git - openhab-addons.git/blob
5559b02ea272864b4d9e6436403f8f9bae2565d1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.ecobee.internal.handler;
14
15 import static org.openhab.binding.ecobee.internal.EcobeeBindingConstants.*;
16
17 import java.util.Map;
18 import java.util.concurrent.ConcurrentHashMap;
19
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;
42
43 /**
44  * The {@link EcobeeSensorThingHandler} is responsible for updating the channels associated
45  * with an Ecobee remote sensor.
46  *
47  * @author Mark Hilbush - Initial contribution
48  */
49 @NonNullByDefault
50 public class EcobeeSensorThingHandler extends BaseThingHandler {
51
52     public static final String CAPABILITY_ADC = "adc";
53     public static final String CAPABILITY_AIR_PRESSURE = "airPressure";
54     public static final String CAPABILITY_AIR_QUALITY = "airQuality";
55     public static final String CAPABILITY_AIR_QUALITY_ACCURACY = "airQualityAccuracy";
56     public static final String CAPABILITY_CO2 = "co2";
57     public static final String CAPABILITY_CO2_PPM = "co2PPM";
58     public static final String CAPABILITY_DRY_CONTACT = "dryContact";
59     public static final String CAPABILITY_HUMIDITY = "humidity";
60     public static final String CAPABILITY_OCCUPANCY = "occupancy";
61     public static final String CAPABILITY_TEMPERATURE = "temperature";
62     public static final String CAPABILITY_VOC_PPM = "vocPPM";
63     public static final String CAPABILITY_UNKNOWN = "unknown";
64
65     private final Logger logger = LoggerFactory.getLogger(EcobeeSensorThingHandler.class);
66
67     private @NonNullByDefault({}) String sensorId;
68
69     private Map<String, State> stateCache = new ConcurrentHashMap<>();
70
71     public EcobeeSensorThingHandler(Thing thing) {
72         super(thing);
73     }
74
75     @Override
76     public void initialize() {
77         sensorId = getConfigAs(EcobeeSensorConfiguration.class).sensorId;
78         logger.debug("SensorThing: Initializing sensor '{}'", sensorId);
79         clearSavedState();
80         updateStatus(EcobeeUtils.isBridgeOnline(getBridge()) ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
81     }
82
83     @Override
84     public void dispose() {
85         logger.debug("SensorThing: Disposing sensor '{}'", sensorId);
86     }
87
88     @Override
89     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
90         if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
91             updateStatus(ThingStatus.ONLINE);
92         } else {
93             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
94         }
95     }
96
97     @SuppressWarnings("null")
98     @Override
99     public void handleCommand(ChannelUID channelUID, Command command) {
100         if (command instanceof RefreshType) {
101             State state = stateCache.get(channelUID.getId());
102             if (state != null) {
103                 updateState(channelUID.getId(), state);
104             }
105             return;
106         }
107     }
108
109     public void updateChannels(RemoteSensorDTO sensor) {
110         logger.debug("SensorThing: Updating channels for sensor '{}({})'", sensor.id, sensor.name);
111         updateChannel(CH_SENSOR_ID, EcobeeUtils.undefOrString(sensor.id));
112         updateChannel(CH_SENSOR_NAME, EcobeeUtils.undefOrString(sensor.name));
113         updateChannel(CH_SENSOR_TYPE, EcobeeUtils.undefOrString(sensor.type));
114         updateChannel(CH_SENSOR_CODE, EcobeeUtils.undefOrString(sensor.code));
115         updateChannel(CH_SENSOR_IN_USE, EcobeeUtils.undefOrOnOff(sensor.inUse));
116         for (RemoteSensorCapabilityDTO capability : sensor.capability) {
117             updateCapabilityChannels(capability);
118         }
119     }
120
121     private void updateCapabilityChannels(RemoteSensorCapabilityDTO capability) {
122         ChannelUID uid = new ChannelUID(thing.getUID(), capability.type);
123         Channel channel = thing.getChannel(uid);
124         if (channel == null) {
125             logger.debug("SensorThing: Create channel '{}'", uid);
126             ThingBuilder thingBuilder;
127             thingBuilder = editThing();
128             channel = ChannelBuilder.create(uid, getAcceptedItemType(capability.type))
129                     .withLabel("Sensor " + WordUtils.capitalize(capability.type))
130                     .withType(getChannelTypeUID(capability.type)).build();
131             thingBuilder.withChannel(channel);
132             updateThing(thingBuilder.build());
133         }
134         logger.trace("Capability '{}' has type '{}' with value '{}'", capability.id, capability.type, capability.value);
135         updateCapabilityState(capability.type, capability.value);
136     }
137
138     // adc, co2, dryContact, humidity, temperature, occupancy, unknown.
139     private String getAcceptedItemType(String capabilityType) {
140         String acceptedItemType;
141         switch (capabilityType) {
142             case CAPABILITY_TEMPERATURE:
143                 acceptedItemType = "Number:Temperature";
144                 break;
145             case CAPABILITY_HUMIDITY:
146                 acceptedItemType = "Number:Dimensionless";
147                 break;
148             case CAPABILITY_OCCUPANCY:
149                 acceptedItemType = "Switch";
150                 break;
151             case CAPABILITY_ADC:
152             case CAPABILITY_AIR_PRESSURE:
153             case CAPABILITY_AIR_QUALITY:
154             case CAPABILITY_AIR_QUALITY_ACCURACY:
155             case CAPABILITY_CO2:
156             case CAPABILITY_CO2_PPM:
157             case CAPABILITY_DRY_CONTACT:
158             case CAPABILITY_UNKNOWN:
159             case CAPABILITY_VOC_PPM:
160             default:
161                 acceptedItemType = "String";
162                 break;
163         }
164         return acceptedItemType;
165     }
166
167     private ChannelTypeUID getChannelTypeUID(String capabilityType) {
168         ChannelTypeUID channelTypeUID;
169         switch (capabilityType) {
170             case CAPABILITY_TEMPERATURE:
171                 channelTypeUID = CHANNELTYPEUID_TEMPERATURE;
172                 break;
173             case CAPABILITY_HUMIDITY:
174                 channelTypeUID = CHANNELTYPEUID_HUMIDITY;
175                 break;
176             case CAPABILITY_OCCUPANCY:
177                 channelTypeUID = CHANNELTYPEUID_OCCUPANCY;
178                 break;
179             case CAPABILITY_ADC:
180             case CAPABILITY_AIR_PRESSURE:
181             case CAPABILITY_AIR_QUALITY:
182             case CAPABILITY_AIR_QUALITY_ACCURACY:
183             case CAPABILITY_CO2:
184             case CAPABILITY_CO2_PPM:
185             case CAPABILITY_DRY_CONTACT:
186             case CAPABILITY_UNKNOWN:
187             case CAPABILITY_VOC_PPM:
188             default:
189                 channelTypeUID = CHANNELTYPEUID_GENERIC;
190                 break;
191         }
192         return channelTypeUID;
193     }
194
195     private void updateCapabilityState(String capabilityType, String value) {
196         State state;
197         switch (capabilityType) {
198             case CAPABILITY_TEMPERATURE:
199                 try {
200                     state = EcobeeUtils.undefOrTemperature(Integer.parseInt(value));
201                 } catch (NumberFormatException e) {
202                     state = UnDefType.UNDEF;
203                 }
204                 break;
205             case CAPABILITY_HUMIDITY:
206                 try {
207                     state = EcobeeUtils.undefOrQuantity(Integer.parseInt(value), Units.PERCENT);
208                 } catch (NumberFormatException e) {
209                     state = UnDefType.UNDEF;
210                 }
211                 break;
212             case CAPABILITY_OCCUPANCY:
213                 state = EcobeeUtils.undefOrOnOff("true".equals(value));
214                 break;
215             case CAPABILITY_ADC:
216             case CAPABILITY_AIR_PRESSURE:
217             case CAPABILITY_AIR_QUALITY:
218             case CAPABILITY_AIR_QUALITY_ACCURACY:
219             case CAPABILITY_CO2:
220             case CAPABILITY_CO2_PPM:
221             case CAPABILITY_DRY_CONTACT:
222             case CAPABILITY_UNKNOWN:
223             case CAPABILITY_VOC_PPM:
224             default:
225                 state = EcobeeUtils.undefOrString(value);
226                 break;
227         }
228         updateChannel(capabilityType, state);
229     }
230
231     private void updateChannel(String channelId, State state) {
232         updateState(channelId, state);
233         stateCache.put(channelId, state);
234     }
235
236     private void clearSavedState() {
237         stateCache.clear();
238     }
239 }