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