]> git.basschouten.com Git - openhab-addons.git/blob
21217ed21f1b4930c1f80b9f6c4d95914bcba277
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.deconz.internal.handler;
14
15 import static org.openhab.binding.deconz.internal.BindingConstants.*;
16 import static org.openhab.core.library.unit.MetricPrefix.*;
17 import static org.openhab.core.library.unit.SIUnits.*;
18 import static org.openhab.core.library.unit.SmartHomeUnits.*;
19
20 import java.util.Arrays;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.deconz.internal.dto.*;
27 import org.openhab.core.library.types.HSBType;
28 import org.openhab.core.library.types.OpenClosedType;
29 import org.openhab.core.library.types.QuantityType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingTypeUID;
34 import org.openhab.core.thing.type.ChannelKind;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.RefreshType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.google.gson.Gson;
41
42 /**
43  * This sensor Thing doesn't establish any connections, that is done by the bridge Thing.
44  *
45  * It waits for the bridge to come online, grab the websocket connection and bridge configuration
46  * and registers to the websocket connection as a listener.
47  *
48  * A REST API call is made to get the initial sensor state.
49  *
50  * Every sensor and switch is supported by this Thing, because a unified state is kept
51  * in {@link #sensorState}. Every field that got received by the REST API for this specific
52  * sensor is published to the framework.
53  *
54  * @author David Graeff - Initial contribution
55  */
56 @NonNullByDefault
57 public class SensorThingHandler extends SensorBaseThingHandler {
58     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_PRESENCE_SENSOR,
59             THING_TYPE_DAYLIGHT_SENSOR, THING_TYPE_POWER_SENSOR, THING_TYPE_CONSUMPTION_SENSOR, THING_TYPE_LIGHT_SENSOR,
60             THING_TYPE_TEMPERATURE_SENSOR, THING_TYPE_HUMIDITY_SENSOR, THING_TYPE_PRESSURE_SENSOR, THING_TYPE_SWITCH,
61             THING_TYPE_OPENCLOSE_SENSOR, THING_TYPE_WATERLEAKAGE_SENSOR, THING_TYPE_FIRE_SENSOR,
62             THING_TYPE_ALARM_SENSOR, THING_TYPE_VIBRATION_SENSOR, THING_TYPE_BATTERY_SENSOR,
63             THING_TYPE_CARBONMONOXIDE_SENSOR, THING_TYPE_COLOR_CONTROL);
64
65     private static final List<String> CONFIG_CHANNELS = Arrays.asList(CHANNEL_BATTERY_LEVEL, CHANNEL_BATTERY_LOW,
66             CHANNEL_TEMPERATURE);
67
68     private final Logger logger = LoggerFactory.getLogger(SensorThingHandler.class);
69
70     public SensorThingHandler(Thing thing, Gson gson) {
71         super(thing, gson);
72     }
73
74     @Override
75     public void handleCommand(ChannelUID channelUID, Command command) {
76         if (!(command instanceof RefreshType)) {
77             return;
78         }
79
80         sensorState.buttonevent = null;
81         valueUpdated(channelUID.getId(), sensorState, false);
82     }
83
84     @Override
85     protected void valueUpdated(ChannelUID channelUID, SensorConfig newConfig) {
86         super.valueUpdated(channelUID, newConfig);
87         Float temperature = newConfig.temperature;
88
89         switch (channelUID.getId()) {
90             case CHANNEL_TEMPERATURE:
91                 if (temperature != null) {
92                     updateState(channelUID, new QuantityType<>(temperature / 100, CELSIUS));
93                 }
94                 break;
95         }
96     }
97
98     @Override
99     protected void valueUpdated(String channelID, SensorState newState, boolean initializing) {
100         super.valueUpdated(channelID, newState, initializing);
101         switch (channelID) {
102             case CHANNEL_BATTERY_LEVEL:
103                 updateDecimalTypeChannel(channelID, newState.battery);
104                 break;
105             case CHANNEL_LIGHT:
106                 Boolean dark = newState.dark;
107                 if (dark != null) {
108                     Boolean daylight = newState.daylight;
109                     if (dark) { // if it's dark, it's dark ;)
110                         updateState(channelID, new StringType("Dark"));
111                     } else if (daylight != null) { // if its not dark, it might be between darkness and daylight
112                         if (daylight) {
113                             updateState(channelID, new StringType("Daylight"));
114                         } else {
115                             updateState(channelID, new StringType("Sunset"));
116                         }
117                     } else { // if no daylight value is known, we assume !dark means daylight
118                         updateState(channelID, new StringType("Daylight"));
119                     }
120                 }
121                 break;
122             case CHANNEL_POWER:
123                 updateQuantityTypeChannel(channelID, newState.power, WATT);
124                 break;
125             case CHANNEL_CONSUMPTION:
126                 updateQuantityTypeChannel(channelID, newState.consumption, WATT_HOUR);
127                 break;
128             case CHANNEL_VOLTAGE:
129                 updateQuantityTypeChannel(channelID, newState.voltage, VOLT);
130                 break;
131             case CHANNEL_CURRENT:
132                 updateQuantityTypeChannel(channelID, newState.current, MILLI(AMPERE));
133                 break;
134             case CHANNEL_LIGHT_LUX:
135                 updateQuantityTypeChannel(channelID, newState.lux, LUX);
136                 break;
137             case CHANNEL_COLOR:
138                 final double @Nullable [] xy = newState.xy;
139                 if (xy != null && xy.length == 2) {
140                     updateState(channelID, HSBType.fromXY((float) xy[0], (float) xy[1]));
141                 }
142                 break;
143             case CHANNEL_LIGHT_LEVEL:
144                 updateDecimalTypeChannel(channelID, newState.lightlevel);
145                 break;
146             case CHANNEL_DARK:
147                 updateSwitchChannel(channelID, newState.dark);
148                 break;
149             case CHANNEL_DAYLIGHT:
150                 updateSwitchChannel(channelID, newState.daylight);
151                 break;
152             case CHANNEL_TEMPERATURE:
153                 updateQuantityTypeChannel(channelID, newState.temperature, CELSIUS, 1.0 / 100);
154                 break;
155             case CHANNEL_HUMIDITY:
156                 updateQuantityTypeChannel(channelID, newState.humidity, PERCENT, 1.0 / 100);
157                 break;
158             case CHANNEL_PRESSURE:
159                 updateQuantityTypeChannel(channelID, newState.pressure, HECTO(PASCAL));
160                 break;
161             case CHANNEL_PRESENCE:
162                 updateSwitchChannel(channelID, newState.presence);
163                 break;
164             case CHANNEL_VALUE:
165                 updateDecimalTypeChannel(channelID, newState.status);
166                 break;
167             case CHANNEL_OPENCLOSE:
168                 Boolean open = newState.open;
169                 if (open != null) {
170                     updateState(channelID, open ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
171                 }
172                 break;
173             case CHANNEL_WATERLEAKAGE:
174                 updateSwitchChannel(channelID, newState.water);
175                 break;
176             case CHANNEL_FIRE:
177                 updateSwitchChannel(channelID, newState.fire);
178                 break;
179             case CHANNEL_ALARM:
180                 updateSwitchChannel(channelID, newState.alarm);
181                 break;
182             case CHANNEL_TAMPERED:
183                 updateSwitchChannel(channelID, newState.tampered);
184                 break;
185             case CHANNEL_VIBRATION:
186                 updateSwitchChannel(channelID, newState.vibration);
187                 break;
188             case CHANNEL_CARBONMONOXIDE:
189                 updateSwitchChannel(channelID, newState.carbonmonoxide);
190                 break;
191             case CHANNEL_BUTTON:
192                 updateDecimalTypeChannel(channelID, newState.buttonevent);
193                 break;
194             case CHANNEL_BUTTONEVENT:
195                 Integer buttonevent = newState.buttonevent;
196                 if (buttonevent != null && !initializing) {
197                     triggerChannel(channelID, String.valueOf(buttonevent));
198                 }
199                 break;
200             case CHANNEL_GESTURE:
201                 updateDecimalTypeChannel(channelID, newState.gesture);
202                 break;
203             case CHANNEL_GESTUREEVENT:
204                 Integer gesture = newState.gesture;
205                 if (gesture != null && !initializing) {
206                     triggerChannel(channelID, String.valueOf(gesture));
207                 }
208                 break;
209         }
210     }
211
212     @Override
213     protected void createTypeSpecificChannels(SensorConfig sensorConfig, SensorState sensorState) {
214         // some Xiaomi sensors
215         if (sensorConfig.temperature != null) {
216             createChannel(CHANNEL_TEMPERATURE, ChannelKind.STATE);
217         }
218
219         // ZHAPresence - e.g. IKEA TRÅDFRI motion sensor
220         if (sensorState.dark != null) {
221             createChannel(CHANNEL_DARK, ChannelKind.STATE);
222         }
223
224         // ZHAConsumption - e.g Bitron 902010/25 or Heiman SmartPlug
225         if (sensorState.power != null) {
226             createChannel(CHANNEL_POWER, ChannelKind.STATE);
227         }
228
229         // ZHAPower - e.g. Heiman SmartPlug
230         if (sensorState.voltage != null) {
231             createChannel(CHANNEL_VOLTAGE, ChannelKind.STATE);
232         }
233         if (sensorState.current != null) {
234             createChannel(CHANNEL_CURRENT, ChannelKind.STATE);
235         }
236
237         // IAS Zone sensor - e.g. Heiman HS1MS motion sensor
238         if (sensorState.tampered != null) {
239             createChannel(CHANNEL_TAMPERED, ChannelKind.STATE);
240         }
241
242         // e.g. Aqara Cube
243         if (sensorState.gesture != null) {
244             createChannel(CHANNEL_GESTURE, ChannelKind.STATE);
245             createChannel(CHANNEL_GESTUREEVENT, ChannelKind.TRIGGER);
246         }
247     }
248
249     @Override
250     protected List<String> getConfigChannels() {
251         return CONFIG_CHANNELS;
252     }
253 }