]> git.basschouten.com Git - openhab-addons.git/blob
a4df91d677456391656bea3d50951f6eac79263d
[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.SIUnits.CELSIUS;
17 import static org.openhab.core.library.unit.Units.PERCENT;
18
19 import java.math.BigDecimal;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Set;
24
25 import javax.measure.quantity.Temperature;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.deconz.internal.dto.SensorConfig;
30 import org.openhab.binding.deconz.internal.dto.SensorState;
31 import org.openhab.binding.deconz.internal.dto.ThermostatConfig;
32 import org.openhab.binding.deconz.internal.types.ThermostatMode;
33 import org.openhab.core.library.types.DecimalType;
34 import org.openhab.core.library.types.QuantityType;
35 import org.openhab.core.library.types.StringType;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import com.google.gson.Gson;
45
46 /**
47  * This sensor Thermostat Thing doesn't establish any connections, that is done by the bridge Thing.
48  *
49  * It waits for the bridge to come online, grab the websocket connection and bridge configuration
50  * and registers to the websocket connection as a listener.
51  *
52  * A REST API call is made to get the initial sensor state.
53  *
54  * Only the Thermostat is supported by this Thing, because a unified state is kept
55  * in {@link #sensorState}. Every field that got received by the REST API for this specific
56  * sensor is published to the framework.
57  *
58  * @author Lukas Agethen - Initial contribution
59  */
60 @NonNullByDefault
61 public class SensorThermostatThingHandler extends SensorBaseThingHandler {
62     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_THERMOSTAT);
63
64     private static final List<String> CONFIG_CHANNELS = Arrays.asList(CHANNEL_BATTERY_LEVEL, CHANNEL_BATTERY_LOW,
65             CHANNEL_HEATSETPOINT, CHANNEL_TEMPERATURE_OFFSET, CHANNEL_THERMOSTAT_MODE);
66
67     private final Logger logger = LoggerFactory.getLogger(SensorThermostatThingHandler.class);
68
69     public SensorThermostatThingHandler(Thing thing, Gson gson) {
70         super(thing, gson);
71     }
72
73     @Override
74     public void handleCommand(ChannelUID channelUID, Command command) {
75         if (command instanceof RefreshType) {
76             sensorState.buttonevent = null;
77             valueUpdated(channelUID.getId(), sensorState, false);
78             return;
79         }
80         ThermostatConfig newConfig = new ThermostatConfig();
81         String channelId = channelUID.getId();
82         switch (channelId) {
83             case CHANNEL_HEATSETPOINT:
84                 Integer newHeatsetpoint = getTemperatureFromCommand(command);
85                 if (newHeatsetpoint == null) {
86                     logger.warn("Heatsetpoint must not be null.");
87                     return;
88                 }
89                 newConfig.heatsetpoint = newHeatsetpoint;
90                 break;
91             case CHANNEL_TEMPERATURE_OFFSET:
92                 Integer newOffset = getTemperatureFromCommand(command);
93                 if (newOffset == null) {
94                     logger.warn("Offset must not be null.");
95                     return;
96                 }
97                 newConfig.offset = newOffset;
98                 break;
99             case CHANNEL_THERMOSTAT_MODE:
100                 if (command instanceof StringType) {
101                     String thermostatMode = ((StringType) command).toString();
102                     try {
103                         newConfig.mode = ThermostatMode.valueOf(thermostatMode);
104                     } catch (IllegalArgumentException ex) {
105                         logger.warn("Invalid thermostat mode: {}. Valid values: {}", thermostatMode,
106                                 ThermostatMode.values());
107                         return;
108                     }
109                     if (newConfig.mode == ThermostatMode.UNKNOWN) {
110                         logger.warn("Invalid thermostat mode: {}. Valid values: {}", thermostatMode,
111                                 ThermostatMode.values());
112                         return;
113                     }
114                 } else {
115                     return;
116                 }
117                 break;
118             default:
119                 // no supported command
120                 return;
121
122         }
123
124         sendCommand(newConfig, command, channelUID, null);
125     }
126
127     @Override
128     protected void valueUpdated(ChannelUID channelUID, SensorConfig newConfig) {
129         super.valueUpdated(channelUID, newConfig);
130         ThermostatMode thermostatMode = newConfig.mode;
131         String mode = thermostatMode != null ? thermostatMode.name() : ThermostatMode.UNKNOWN.name();
132         String channelID = channelUID.getId();
133         switch (channelID) {
134             case CHANNEL_HEATSETPOINT:
135                 updateQuantityTypeChannel(channelID, newConfig.heatsetpoint, CELSIUS, 1.0 / 100);
136                 break;
137             case CHANNEL_TEMPERATURE_OFFSET:
138                 updateQuantityTypeChannel(channelID, newConfig.offset, CELSIUS, 1.0 / 100);
139                 break;
140             case CHANNEL_THERMOSTAT_MODE:
141                 updateState(channelUID, new StringType(mode));
142                 break;
143         }
144     }
145
146     @Override
147     protected void valueUpdated(String channelID, SensorState newState, boolean initializing) {
148         super.valueUpdated(channelID, newState, initializing);
149         switch (channelID) {
150             case CHANNEL_TEMPERATURE:
151                 updateQuantityTypeChannel(channelID, newState.temperature, CELSIUS, 1.0 / 100);
152                 break;
153             case CHANNEL_VALVE_POSITION:
154                 updateQuantityTypeChannel(channelID, newState.valve, PERCENT, 100.0 / 255);
155                 break;
156         }
157     }
158
159     @Override
160     protected void createTypeSpecificChannels(SensorConfig sensorConfig, SensorState sensorState) {
161     }
162
163     @Override
164     protected List<String> getConfigChannels() {
165         return CONFIG_CHANNELS;
166     }
167
168     private @Nullable Integer getTemperatureFromCommand(Command command) {
169         BigDecimal newTemperature;
170         if (command instanceof DecimalType) {
171             newTemperature = ((DecimalType) command).toBigDecimal();
172         } else if (command instanceof QuantityType) {
173             @SuppressWarnings("unchecked")
174             QuantityType<Temperature> temperatureCelsius = ((QuantityType<Temperature>) command).toUnit(CELSIUS);
175             if (temperatureCelsius != null) {
176                 newTemperature = temperatureCelsius.toBigDecimal();
177             } else {
178                 return null;
179             }
180         } else {
181             return null;
182         }
183         return newTemperature.scaleByPowerOfTen(2).intValue();
184     }
185 }