]> git.basschouten.com Git - openhab-addons.git/blob
c6231ba1a654240b7eb6049f3d549146561aa982
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.tado.internal.adapter;
14
15 import java.math.BigDecimal;
16 import java.math.RoundingMode;
17 import java.time.OffsetDateTime;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
22 import org.openhab.binding.tado.internal.TadoBindingConstants.OperationMode;
23 import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
24 import org.openhab.binding.tado.internal.api.model.ACFanLevel;
25 import org.openhab.binding.tado.internal.api.model.ACHorizontalSwing;
26 import org.openhab.binding.tado.internal.api.model.ACVerticalSwing;
27 import org.openhab.binding.tado.internal.api.model.AcFanSpeed;
28 import org.openhab.binding.tado.internal.api.model.AcPowerDataPoint;
29 import org.openhab.binding.tado.internal.api.model.ActivityDataPoints;
30 import org.openhab.binding.tado.internal.api.model.CoolingZoneSetting;
31 import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
32 import org.openhab.binding.tado.internal.api.model.HeatingZoneSetting;
33 import org.openhab.binding.tado.internal.api.model.HotWaterZoneSetting;
34 import org.openhab.binding.tado.internal.api.model.Overlay;
35 import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionType;
36 import org.openhab.binding.tado.internal.api.model.PercentageDataPoint;
37 import org.openhab.binding.tado.internal.api.model.Power;
38 import org.openhab.binding.tado.internal.api.model.SensorDataPoints;
39 import org.openhab.binding.tado.internal.api.model.TadoSystemType;
40 import org.openhab.binding.tado.internal.api.model.TemperatureDataPoint;
41 import org.openhab.binding.tado.internal.api.model.TemperatureObject;
42 import org.openhab.binding.tado.internal.api.model.TimerTerminationCondition;
43 import org.openhab.binding.tado.internal.api.model.ZoneState;
44 import org.openhab.core.library.types.DateTimeType;
45 import org.openhab.core.library.types.DecimalType;
46 import org.openhab.core.library.types.OnOffType;
47 import org.openhab.core.library.types.QuantityType;
48 import org.openhab.core.library.types.StringType;
49 import org.openhab.core.library.unit.ImperialUnits;
50 import org.openhab.core.library.unit.SIUnits;
51 import org.openhab.core.types.State;
52 import org.openhab.core.types.UnDefType;
53
54 /**
55  * Adapter from API-level zone state to the binding's item-based zone state.
56  *
57  * @author Dennis Frommknecht - Initial contribution
58  * @author Andrew Fiddian-Green - Added Low Battery Alarm, A/C Power and Open Window channels
59  *
60  */
61 @NonNullByDefault
62 public class TadoZoneStateAdapter {
63     private final ZoneState zoneState;
64     private final TemperatureUnit temperatureUnit;
65
66     public TadoZoneStateAdapter(ZoneState zoneState, TemperatureUnit temperatureUnit) {
67         this.zoneState = zoneState;
68         this.temperatureUnit = temperatureUnit;
69     }
70
71     public State getInsideTemperature() {
72         SensorDataPoints sensorDataPoints = zoneState.getSensorDataPoints();
73         return toTemperatureState(sensorDataPoints.getInsideTemperature(), temperatureUnit);
74     }
75
76     public State getHumidity() {
77         PercentageDataPoint humidity = zoneState.getSensorDataPoints().getHumidity();
78         return humidity != null ? toDecimalType(humidity.getPercentage()) : UnDefType.UNDEF;
79     }
80
81     public DecimalType getHeatingPower() {
82         ActivityDataPoints dataPoints = zoneState.getActivityDataPoints();
83         return dataPoints.getHeatingPower() != null ? toDecimalType(dataPoints.getHeatingPower().getPercentage())
84                 : DecimalType.ZERO;
85     }
86
87     public State getAcPower() {
88         ActivityDataPoints dataPoints = zoneState.getActivityDataPoints();
89         AcPowerDataPoint acPower = dataPoints.getAcPower();
90         if (acPower != null) {
91             String acPowerValue = acPower.getValue();
92             if (acPowerValue != null) {
93                 return OnOffType.from(acPowerValue);
94             }
95         }
96         return UnDefType.UNDEF;
97     }
98
99     public StringType getMode() {
100         GenericZoneSetting setting = zoneState.getSetting();
101
102         if (!isPowerOn()) {
103             return StringType.valueOf(HvacMode.OFF.name());
104         } else if (setting.getType() == TadoSystemType.HEATING || setting.getType() == TadoSystemType.HOT_WATER) {
105             return StringType.valueOf(HvacMode.HEAT.name());
106         } else {
107             return StringType.valueOf(((CoolingZoneSetting) setting).getMode().getValue());
108         }
109     }
110
111     public State getTargetTemperature() {
112         if (!isPowerOn()) {
113             return UnDefType.UNDEF;
114         }
115         switch (zoneState.getSetting().getType()) {
116             case HEATING:
117                 return toTemperatureState(((HeatingZoneSetting) zoneState.getSetting()).getTemperature(),
118                         temperatureUnit);
119             case AIR_CONDITIONING:
120                 return toTemperatureState(((CoolingZoneSetting) zoneState.getSetting()).getTemperature(),
121                         temperatureUnit);
122             case HOT_WATER:
123                 return toTemperatureState(((HotWaterZoneSetting) zoneState.getSetting()).getTemperature(),
124                         temperatureUnit);
125             default:
126                 return UnDefType.UNDEF;
127         }
128     }
129
130     public State getFanSpeed() {
131         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
132             AcFanSpeed result = ((CoolingZoneSetting) zoneState.getSetting()).getFanSpeed();
133             return result != null ? StringType.valueOf(result.getValue()) : UnDefType.NULL;
134         }
135         return UnDefType.UNDEF;
136     }
137
138     public State getSwing() {
139         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
140             Power result = ((CoolingZoneSetting) zoneState.getSetting()).getSwing();
141             return result != null ? OnOffType.from(result == Power.ON) : UnDefType.NULL;
142         }
143         return UnDefType.UNDEF;
144     }
145
146     public State getFanLevel() {
147         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
148             ACFanLevel result = ((CoolingZoneSetting) zoneState.getSetting()).getFanLevel();
149             return result != null ? StringType.valueOf(result.getValue()) : UnDefType.NULL;
150         }
151         return UnDefType.UNDEF;
152     }
153
154     public State getHorizontalSwing() {
155         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
156             ACHorizontalSwing result = ((CoolingZoneSetting) zoneState.getSetting()).getHorizontalSwing();
157             return result != null ? StringType.valueOf(result.getValue()) : UnDefType.NULL;
158         }
159         return UnDefType.UNDEF;
160     }
161
162     public State getVerticalSwing() {
163         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
164             ACVerticalSwing result = ((CoolingZoneSetting) zoneState.getSetting()).getVerticalSwing();
165             return result != null ? StringType.valueOf(result.getValue()) : UnDefType.NULL;
166         }
167         return UnDefType.UNDEF;
168     }
169
170     public StringType getOperationMode() {
171         Overlay overlay = zoneState.getOverlay();
172         if (overlay != null) {
173             switch (overlay.getTermination().getType()) {
174                 case MANUAL:
175                     return new StringType(OperationMode.MANUAL.name());
176                 case TIMER:
177                     return new StringType(OperationMode.TIMER.name());
178                 case TADO_MODE:
179                     return new StringType(OperationMode.UNTIL_CHANGE.name());
180             }
181         }
182
183         return new StringType(OperationMode.SCHEDULE.name());
184     }
185
186     public DecimalType getRemainingTimerDuration() {
187         Overlay overlay = zoneState.getOverlay();
188         if (overlay != null && overlay.getTermination().getType() == OverlayTerminationConditionType.TIMER) {
189             TimerTerminationCondition timerTerminationCondition = (TimerTerminationCondition) overlay.getTermination();
190
191             Integer remainingTimeInSeconds = timerTerminationCondition.getRemainingTimeInSeconds();
192             // If there's a timer overlay, then the timer should never be smaller than 1
193             return new DecimalType((int) Math.max(1.0, Math.round(remainingTimeInSeconds / 60.0)));
194         }
195
196         return new DecimalType();
197     }
198
199     public State getOverlayExpiration() {
200         Overlay overlay = zoneState.getOverlay();
201         if (overlay == null || overlay.getTermination().getProjectedExpiry() == null) {
202             return UnDefType.UNDEF;
203         }
204
205         return toDateTimeType(overlay.getTermination().getProjectedExpiry());
206     }
207
208     public boolean isPowerOn() {
209         Power power = Power.OFF;
210         GenericZoneSetting setting = zoneState.getSetting();
211
212         switch (setting.getType()) {
213             case HEATING:
214                 power = ((HeatingZoneSetting) setting).getPower();
215                 break;
216             case AIR_CONDITIONING:
217                 power = ((CoolingZoneSetting) setting).getPower();
218                 break;
219             case HOT_WATER:
220                 power = ((HotWaterZoneSetting) setting).getPower();
221                 break;
222         }
223
224         return "ON".equals(power.getValue());
225     }
226
227     private static DecimalType toDecimalType(double value) {
228         BigDecimal decimal = new BigDecimal(value).setScale(2, RoundingMode.HALF_UP);
229         return new DecimalType(decimal);
230     }
231
232     private static DateTimeType toDateTimeType(OffsetDateTime offsetDateTime) {
233         return new DateTimeType(offsetDateTime.toZonedDateTime());
234     }
235
236     private static State toTemperatureState(@Nullable TemperatureObject temperature, TemperatureUnit temperatureUnit) {
237         if (temperature == null || (temperature.getCelsius() == null && temperature.getFahrenheit() == null)) {
238             return UnDefType.UNDEF;
239         }
240         return temperatureUnit == TemperatureUnit.FAHRENHEIT
241                 ? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
242                 : new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
243     }
244
245     private static State toTemperatureState(@Nullable TemperatureDataPoint temperature,
246             TemperatureUnit temperatureUnit) {
247         if (temperature == null || (temperature.getCelsius() == null && temperature.getFahrenheit() == null)) {
248             return UnDefType.UNDEF;
249         }
250         return temperatureUnit == TemperatureUnit.FAHRENHEIT
251                 ? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
252                 : new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
253     }
254
255     public State getOpenWindowDetected() {
256         Boolean openWindowDetected = zoneState.isOpenWindowDetected();
257         if (openWindowDetected != null) {
258             return OnOffType.from(openWindowDetected);
259         }
260         return OnOffType.OFF;
261     }
262
263     public State getLight() {
264         if (zoneState.getSetting().getType() == TadoSystemType.AIR_CONDITIONING) {
265             Power result = ((CoolingZoneSetting) zoneState.getSetting()).getLight();
266             return result != null ? OnOffType.from(result == Power.ON) : UnDefType.NULL;
267         }
268         return UnDefType.UNDEF;
269     }
270 }