]> git.basschouten.com Git - openhab-addons.git/blob
2d3462053488c45720865433db634f0c0f988ee4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.nest.internal.wwn.handler;
14
15 import static org.openhab.binding.nest.internal.wwn.WWNBindingConstants.*;
16 import static org.openhab.core.library.unit.SIUnits.CELSIUS;
17 import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION;
18 import static org.openhab.core.types.RefreshType.REFRESH;
19
20 import java.math.BigDecimal;
21 import java.math.RoundingMode;
22
23 import javax.measure.Unit;
24 import javax.measure.quantity.Temperature;
25 import javax.measure.quantity.Time;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.nest.internal.wwn.dto.WWNThermostat;
30 import org.openhab.binding.nest.internal.wwn.dto.WWNThermostat.Mode;
31 import org.openhab.core.library.types.OnOffType;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.types.StringType;
34 import org.openhab.core.library.unit.Units;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.State;
40 import org.openhab.core.types.UnDefType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link WWNThermostatHandler} is responsible for handling commands, which are
46  * sent to one of the channels for the thermostat.
47  *
48  * @author David Bennett - Initial contribution
49  * @author Wouter Born - Handle channel refresh command
50  */
51 @NonNullByDefault
52 public class WWNThermostatHandler extends WWNBaseHandler<WWNThermostat> {
53     private final Logger logger = LoggerFactory.getLogger(WWNThermostatHandler.class);
54
55     public WWNThermostatHandler(Thing thing) {
56         super(thing, WWNThermostat.class);
57     }
58
59     @Override
60     protected State getChannelState(ChannelUID channelUID, WWNThermostat thermostat) {
61         switch (channelUID.getId()) {
62             case CHANNEL_CAN_COOL:
63                 return getAsOnOffTypeOrNull(thermostat.isCanCool());
64             case CHANNEL_CAN_HEAT:
65                 return getAsOnOffTypeOrNull(thermostat.isCanHeat());
66             case CHANNEL_ECO_MAX_SET_POINT:
67                 return getAsQuantityTypeOrNull(thermostat.getEcoTemperatureHigh(), thermostat.getTemperatureUnit());
68             case CHANNEL_ECO_MIN_SET_POINT:
69                 return getAsQuantityTypeOrNull(thermostat.getEcoTemperatureLow(), thermostat.getTemperatureUnit());
70             case CHANNEL_FAN_TIMER_ACTIVE:
71                 return getAsOnOffTypeOrNull(thermostat.isFanTimerActive());
72             case CHANNEL_FAN_TIMER_DURATION:
73                 return getAsQuantityTypeOrNull(thermostat.getFanTimerDuration(), Units.MINUTE);
74             case CHANNEL_FAN_TIMER_TIMEOUT:
75                 return getAsDateTimeTypeOrNull(thermostat.getFanTimerTimeout());
76             case CHANNEL_HAS_FAN:
77                 return getAsOnOffTypeOrNull(thermostat.isHasFan());
78             case CHANNEL_HAS_LEAF:
79                 return getAsOnOffTypeOrNull(thermostat.isHasLeaf());
80             case CHANNEL_HUMIDITY:
81                 return getAsQuantityTypeOrNull(thermostat.getHumidity(), Units.PERCENT);
82             case CHANNEL_LAST_CONNECTION:
83                 return getAsDateTimeTypeOrNull(thermostat.getLastConnection());
84             case CHANNEL_LOCKED:
85                 return getAsOnOffTypeOrNull(thermostat.isLocked());
86             case CHANNEL_LOCKED_MAX_SET_POINT:
87                 return getAsQuantityTypeOrNull(thermostat.getLockedTempMax(), thermostat.getTemperatureUnit());
88             case CHANNEL_LOCKED_MIN_SET_POINT:
89                 return getAsQuantityTypeOrNull(thermostat.getLockedTempMin(), thermostat.getTemperatureUnit());
90             case CHANNEL_MAX_SET_POINT:
91                 return getAsQuantityTypeOrNull(thermostat.getTargetTemperatureHigh(), thermostat.getTemperatureUnit());
92             case CHANNEL_MIN_SET_POINT:
93                 return getAsQuantityTypeOrNull(thermostat.getTargetTemperatureLow(), thermostat.getTemperatureUnit());
94             case CHANNEL_MODE:
95                 return getAsStringTypeOrNull(thermostat.getMode());
96             case CHANNEL_PREVIOUS_MODE:
97                 Mode previousMode = thermostat.getPreviousHvacMode() != null ? thermostat.getPreviousHvacMode()
98                         : thermostat.getMode();
99                 return getAsStringTypeOrNull(previousMode);
100             case CHANNEL_STATE:
101                 return getAsStringTypeOrNull(thermostat.getHvacState());
102             case CHANNEL_SET_POINT:
103                 return getAsQuantityTypeOrNull(thermostat.getTargetTemperature(), thermostat.getTemperatureUnit());
104             case CHANNEL_SUNLIGHT_CORRECTION_ACTIVE:
105                 return getAsOnOffTypeOrNull(thermostat.isSunlightCorrectionActive());
106             case CHANNEL_SUNLIGHT_CORRECTION_ENABLED:
107                 return getAsOnOffTypeOrNull(thermostat.isSunlightCorrectionEnabled());
108             case CHANNEL_TEMPERATURE:
109                 return getAsQuantityTypeOrNull(thermostat.getAmbientTemperature(), thermostat.getTemperatureUnit());
110             case CHANNEL_TIME_TO_TARGET:
111                 return getAsQuantityTypeOrNull(thermostat.getTimeToTarget(), Units.MINUTE);
112             case CHANNEL_USING_EMERGENCY_HEAT:
113                 return getAsOnOffTypeOrNull(thermostat.isUsingEmergencyHeat());
114             default:
115                 logger.error("Unsupported channelId '{}'", channelUID.getId());
116                 return UnDefType.UNDEF;
117         }
118     }
119
120     /**
121      * Handle the command to do things to the thermostat, this will change the
122      * value of a channel by sending the request to Nest.
123      */
124     @Override
125     @SuppressWarnings("unchecked")
126     public void handleCommand(ChannelUID channelUID, Command command) {
127         if (REFRESH.equals(command)) {
128             WWNThermostat lastUpdate = getLastUpdate();
129             if (lastUpdate != null) {
130                 updateState(channelUID, getChannelState(channelUID, lastUpdate));
131             }
132         } else if (CHANNEL_FAN_TIMER_ACTIVE.equals(channelUID.getId())) {
133             if (command instanceof OnOffType) {
134                 // Update fan timer active to the command value
135                 addUpdateRequest("fan_timer_active", command == OnOffType.ON);
136             }
137         } else if (CHANNEL_FAN_TIMER_DURATION.equals(channelUID.getId())) {
138             if (command instanceof QuantityType) {
139                 // Update fan timer duration to the command value
140                 QuantityType<Time> minuteQuantity = ((QuantityType<Time>) command).toUnit(Units.MINUTE);
141                 if (minuteQuantity != null) {
142                     addUpdateRequest("fan_timer_duration", minuteQuantity.intValue());
143                 }
144             }
145         } else if (CHANNEL_MAX_SET_POINT.equals(channelUID.getId())) {
146             if (command instanceof QuantityType) {
147                 // Update maximum set point to the command value
148                 addTemperatureUpdateRequest("target_temperature_high_c", "target_temperature_high_f",
149                         (QuantityType<Temperature>) command);
150             }
151         } else if (CHANNEL_MIN_SET_POINT.equals(channelUID.getId())) {
152             if (command instanceof QuantityType) {
153                 // Update minimum set point to the command value
154                 addTemperatureUpdateRequest("target_temperature_low_c", "target_temperature_low_f",
155                         (QuantityType<Temperature>) command);
156             }
157         } else if (CHANNEL_MODE.equals(channelUID.getId())) {
158             if (command instanceof StringType) {
159                 // Update the HVAC mode to the command value
160                 addUpdateRequest("hvac_mode", Mode.valueOf(((StringType) command).toString()));
161             }
162         } else if (CHANNEL_SET_POINT.equals(channelUID.getId())) {
163             if (command instanceof QuantityType) {
164                 // Update set point to the command value
165                 addTemperatureUpdateRequest("target_temperature_c", "target_temperature_f",
166                         (QuantityType<Temperature>) command);
167             }
168         }
169     }
170
171     private void addUpdateRequest(String field, Object value) {
172         addUpdateRequest(NEST_THERMOSTAT_UPDATE_PATH, field, value);
173     }
174
175     private void addTemperatureUpdateRequest(String celsiusField, String fahrenheitField,
176             QuantityType<Temperature> quantity) {
177         Unit<Temperature> unit = getTemperatureUnit(quantity.getUnit());
178         BigDecimal value = quantityToRoundedTemperature(quantity, unit);
179         if (value != null) {
180             addUpdateRequest(NEST_THERMOSTAT_UPDATE_PATH, unit == CELSIUS ? celsiusField : fahrenheitField, value);
181         }
182     }
183
184     private Unit<Temperature> getTemperatureUnit(Unit<Temperature> fallbackUnit) {
185         WWNThermostat lastUpdate = getLastUpdate();
186         if (lastUpdate != null && lastUpdate.getTemperatureUnit() != null) {
187             return lastUpdate.getTemperatureUnit();
188         }
189
190         return fallbackUnit;
191     }
192
193     private @Nullable BigDecimal quantityToRoundedTemperature(QuantityType<Temperature> quantity,
194             Unit<Temperature> unit) throws IllegalArgumentException {
195         QuantityType<Temperature> temparatureQuantity = quantity.toUnit(unit);
196         if (temparatureQuantity == null) {
197             return null;
198         }
199
200         BigDecimal value = temparatureQuantity.toBigDecimal();
201         BigDecimal increment = CELSIUS == unit ? new BigDecimal("0.5") : new BigDecimal("1");
202         BigDecimal divisor = value.divide(increment, 0, RoundingMode.HALF_UP);
203         return divisor.multiply(increment);
204     }
205
206     @Override
207     protected void update(@Nullable WWNThermostat oldThermostat, WWNThermostat thermostat) {
208         logger.debug("Updating {}", getThing().getUID());
209
210         updateLinkedChannels(oldThermostat, thermostat);
211         updateProperty(PROPERTY_FIRMWARE_VERSION, thermostat.getSoftwareVersion());
212
213         ThingStatus newStatus = thermostat.isOnline() == null ? ThingStatus.UNKNOWN
214                 : thermostat.isOnline() ? ThingStatus.ONLINE : ThingStatus.OFFLINE;
215         if (newStatus != thing.getStatus()) {
216             updateStatus(newStatus);
217         }
218     }
219 }