]> git.basschouten.com Git - openhab-addons.git/blob
8f997a86d1a71e26eee6dc36c2b8b61e4264c1e7
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.io.homekit.internal.accessories;
14
15 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.CURRENT_HEATING_COOLING_STATE;
16 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE;
17
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.EnumMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Optional;
24 import java.util.concurrent.CompletableFuture;
25
26 import org.openhab.core.library.items.NumberItem;
27 import org.openhab.core.library.items.StringItem;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
31 import org.openhab.io.homekit.internal.HomekitCharacteristicType;
32 import org.openhab.io.homekit.internal.HomekitSettings;
33 import org.openhab.io.homekit.internal.HomekitTaggedItem;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import io.github.hapjava.accessories.ThermostatAccessory;
38 import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
39 import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateEnum;
40 import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateEnum;
41 import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
42 import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
43 import io.github.hapjava.services.impl.ThermostatService;
44
45 /**
46  * Implements Thermostat as a GroupedAccessory made up of multiple items:
47  * <ul>
48  * <li>Current Temperature: Number type</li>
49  * <li>Target Temperature: Number type</li>
50  * <li>Current Heating/Cooling Mode: String type (see HomekitSettings.thermostat*Mode)</li>
51  * <li>Target Heating/Cooling Mode: String type (see HomekitSettings.thermostat*Mode)</li>
52  * </ul>
53  *
54  * @author Andy Lintner - Initial contribution
55  */
56 class HomekitThermostatImpl extends AbstractHomekitAccessoryImpl implements ThermostatAccessory {
57     private final Logger logger = LoggerFactory.getLogger(HomekitThermostatImpl.class);
58     private final Map<CurrentHeatingCoolingStateEnum, String> currentHeatingCoolingStateMapping;
59     private final Map<TargetHeatingCoolingStateEnum, String> targetHeatingCoolingStateMapping;
60     private final List<CurrentHeatingCoolingStateEnum> customCurrentHeatingCoolingStateList;
61     private final List<TargetHeatingCoolingStateEnum> customTargetHeatingCoolingStateList;
62
63     public HomekitThermostatImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
64             HomekitAccessoryUpdater updater, HomekitSettings settings) {
65         super(taggedItem, mandatoryCharacteristics, updater, settings);
66         currentHeatingCoolingStateMapping = new EnumMap<>(CurrentHeatingCoolingStateEnum.class);
67         currentHeatingCoolingStateMapping.put(CurrentHeatingCoolingStateEnum.OFF, settings.thermostatCurrentModeOff);
68         currentHeatingCoolingStateMapping.put(CurrentHeatingCoolingStateEnum.COOL,
69                 settings.thermostatCurrentModeCooling);
70         currentHeatingCoolingStateMapping.put(CurrentHeatingCoolingStateEnum.HEAT,
71                 settings.thermostatCurrentModeHeating);
72         targetHeatingCoolingStateMapping = new EnumMap<>(TargetHeatingCoolingStateEnum.class);
73         targetHeatingCoolingStateMapping.put(TargetHeatingCoolingStateEnum.OFF, settings.thermostatTargetModeOff);
74         targetHeatingCoolingStateMapping.put(TargetHeatingCoolingStateEnum.COOL, settings.thermostatTargetModeCool);
75         targetHeatingCoolingStateMapping.put(TargetHeatingCoolingStateEnum.HEAT, settings.thermostatTargetModeHeat);
76         targetHeatingCoolingStateMapping.put(TargetHeatingCoolingStateEnum.AUTO, settings.thermostatTargetModeAuto);
77         customCurrentHeatingCoolingStateList = new ArrayList<>();
78         customTargetHeatingCoolingStateList = new ArrayList<>();
79         updateMapping(CURRENT_HEATING_COOLING_STATE, currentHeatingCoolingStateMapping,
80                 customCurrentHeatingCoolingStateList);
81         updateMapping(TARGET_HEATING_COOLING_STATE, targetHeatingCoolingStateMapping,
82                 customTargetHeatingCoolingStateList);
83         this.getServices().add(new ThermostatService(this));
84     }
85
86     @Override
87     public CurrentHeatingCoolingStateEnum[] getCurrentHeatingCoolingStateValidValues() {
88         return customCurrentHeatingCoolingStateList.isEmpty()
89                 ? currentHeatingCoolingStateMapping.keySet().toArray(new CurrentHeatingCoolingStateEnum[0])
90                 : customCurrentHeatingCoolingStateList.toArray(new CurrentHeatingCoolingStateEnum[0]);
91     }
92
93     @Override
94     public TargetHeatingCoolingStateEnum[] getTargetHeatingCoolingStateValidValues() {
95         return customTargetHeatingCoolingStateList.isEmpty()
96                 ? targetHeatingCoolingStateMapping.keySet().toArray(new TargetHeatingCoolingStateEnum[0])
97                 : customTargetHeatingCoolingStateList.toArray(new TargetHeatingCoolingStateEnum[0]);
98     }
99
100     @Override
101     public CompletableFuture<CurrentHeatingCoolingStateEnum> getCurrentState() {
102         return CompletableFuture.completedFuture(getKeyFromMapping(CURRENT_HEATING_COOLING_STATE,
103                 currentHeatingCoolingStateMapping, CurrentHeatingCoolingStateEnum.OFF));
104     }
105
106     @Override
107     public CompletableFuture<Double> getCurrentTemperature() {
108         DecimalType state = getStateAs(HomekitCharacteristicType.CURRENT_TEMPERATURE, DecimalType.class);
109         return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue()) : 0.0);
110     }
111
112     @Override
113     public double getMinCurrentTemperature() {
114         return getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
115                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue();
116     }
117
118     @Override
119     public double getMaxCurrentTemperature() {
120         return getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
121                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue();
122     }
123
124     @Override
125     public double getMinStepCurrentTemperature() {
126         return getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.STEP,
127                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_STEP)).doubleValue();
128     }
129
130     @Override
131     public CompletableFuture<TargetHeatingCoolingStateEnum> getTargetState() {
132         return CompletableFuture.completedFuture(getKeyFromMapping(TARGET_HEATING_COOLING_STATE,
133                 targetHeatingCoolingStateMapping, TargetHeatingCoolingStateEnum.OFF));
134     }
135
136     @Override
137     public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
138         return CompletableFuture
139                 .completedFuture(getSettings().useFahrenheitTemperature ? TemperatureDisplayUnitEnum.FAHRENHEIT
140                         : TemperatureDisplayUnitEnum.CELSIUS);
141     }
142
143     @Override
144     public void setTemperatureDisplayUnit(TemperatureDisplayUnitEnum value) {
145         // TODO: add support for display unit change
146     }
147
148     @Override
149     public CompletableFuture<Double> getTargetTemperature() {
150         DecimalType state = getStateAs(HomekitCharacteristicType.TARGET_TEMPERATURE, DecimalType.class);
151         return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue()) : 0.0);
152     }
153
154     @Override
155     public void setTargetState(TargetHeatingCoolingStateEnum mode) {
156         getItem(TARGET_HEATING_COOLING_STATE, StringItem.class)
157                 .ifPresent(item -> item.send(new StringType(targetHeatingCoolingStateMapping.get(mode))));
158     }
159
160     @Override
161     public void setTargetTemperature(Double value) {
162         final Optional<HomekitTaggedItem> characteristic = getCharacteristic(
163                 HomekitCharacteristicType.TARGET_TEMPERATURE);
164         if (characteristic.isPresent()) {
165             ((NumberItem) characteristic.get().getItem())
166                     .send(new DecimalType(BigDecimal.valueOf(convertFromCelsius(value))));
167         } else {
168             logger.warn("Missing mandatory characteristic {}", HomekitCharacteristicType.TARGET_TEMPERATURE);
169         }
170     }
171
172     @Override
173     public double getMinTargetTemperature() {
174         return getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
175                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue();
176     }
177
178     @Override
179     public double getMaxTargetTemperature() {
180         return getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
181                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue();
182     }
183
184     @Override
185     public double getMinStepTargetTemperature() {
186         return getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.STEP,
187                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_STEP)).doubleValue();
188     }
189
190     @Override
191     public void subscribeCurrentState(HomekitCharacteristicChangeCallback callback) {
192         subscribe(CURRENT_HEATING_COOLING_STATE, callback);
193     }
194
195     @Override
196     public void subscribeCurrentTemperature(HomekitCharacteristicChangeCallback callback) {
197         subscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE, callback);
198     }
199
200     @Override
201     public void subscribeTargetState(HomekitCharacteristicChangeCallback callback) {
202         subscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE, callback);
203     }
204
205     @Override
206     public void subscribeTargetTemperature(HomekitCharacteristicChangeCallback callback) {
207         subscribe(HomekitCharacteristicType.TARGET_TEMPERATURE, callback);
208     }
209
210     @Override
211     public void subscribeTemperatureDisplayUnit(HomekitCharacteristicChangeCallback callback) {
212         // TODO: add support for display unit change
213     }
214
215     @Override
216     public void unsubscribeCurrentState() {
217         unsubscribe(CURRENT_HEATING_COOLING_STATE);
218     }
219
220     @Override
221     public void unsubscribeCurrentTemperature() {
222         unsubscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE);
223     }
224
225     @Override
226     public void unsubscribeTemperatureDisplayUnit() {
227         // TODO: add support for display unit change
228     }
229
230     @Override
231     public void unsubscribeTargetState() {
232         unsubscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE);
233     }
234
235     @Override
236     public void unsubscribeTargetTemperature() {
237         unsubscribe(HomekitCharacteristicType.TARGET_TEMPERATURE);
238     }
239 }