]> git.basschouten.com Git - openhab-addons.git/blob
5c14a4ae9c9c5fe0a0e1bd7a49480c63ed0b701d
[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.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 convertToCelsius(
115                 getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
116                         BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
117     }
118
119     @Override
120     public double getMaxCurrentTemperature() {
121         return convertToCelsius(
122                 getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
123                         BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue());
124     }
125
126     @Override
127     public double getMinStepCurrentTemperature() {
128         return getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.STEP,
129                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_STEP)).doubleValue();
130     }
131
132     @Override
133     public CompletableFuture<TargetHeatingCoolingStateEnum> getTargetState() {
134         return CompletableFuture.completedFuture(getKeyFromMapping(TARGET_HEATING_COOLING_STATE,
135                 targetHeatingCoolingStateMapping, TargetHeatingCoolingStateEnum.OFF));
136     }
137
138     @Override
139     public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
140         return CompletableFuture
141                 .completedFuture(getSettings().useFahrenheitTemperature ? TemperatureDisplayUnitEnum.FAHRENHEIT
142                         : TemperatureDisplayUnitEnum.CELSIUS);
143     }
144
145     @Override
146     public void setTemperatureDisplayUnit(TemperatureDisplayUnitEnum value) {
147         // TODO: add support for display unit change
148     }
149
150     @Override
151     public CompletableFuture<Double> getTargetTemperature() {
152         DecimalType state = getStateAs(HomekitCharacteristicType.TARGET_TEMPERATURE, DecimalType.class);
153         return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue()) : 0.0);
154     }
155
156     @Override
157     public void setTargetState(TargetHeatingCoolingStateEnum mode) {
158         getItem(TARGET_HEATING_COOLING_STATE, StringItem.class)
159                 .ifPresent(item -> item.send(new StringType(targetHeatingCoolingStateMapping.get(mode))));
160     }
161
162     @Override
163     public void setTargetTemperature(Double value) {
164         final Optional<HomekitTaggedItem> characteristic = getCharacteristic(
165                 HomekitCharacteristicType.TARGET_TEMPERATURE);
166         if (characteristic.isPresent()) {
167             ((NumberItem) characteristic.get().getItem())
168                     .send(new DecimalType(BigDecimal.valueOf(convertFromCelsius(value))));
169         } else {
170             logger.warn("Missing mandatory characteristic {}", HomekitCharacteristicType.TARGET_TEMPERATURE);
171         }
172     }
173
174     @Override
175     public double getMinTargetTemperature() {
176         return convertToCelsius(
177                 getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
178                         BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
179     }
180
181     @Override
182     public double getMaxTargetTemperature() {
183         return convertToCelsius(
184                 getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
185                         BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue());
186     }
187
188     @Override
189     public double getMinStepTargetTemperature() {
190         return getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.STEP,
191                 BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_STEP)).doubleValue();
192     }
193
194     @Override
195     public void subscribeCurrentState(HomekitCharacteristicChangeCallback callback) {
196         subscribe(CURRENT_HEATING_COOLING_STATE, callback);
197     }
198
199     @Override
200     public void subscribeCurrentTemperature(HomekitCharacteristicChangeCallback callback) {
201         subscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE, callback);
202     }
203
204     @Override
205     public void subscribeTargetState(HomekitCharacteristicChangeCallback callback) {
206         subscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE, callback);
207     }
208
209     @Override
210     public void subscribeTargetTemperature(HomekitCharacteristicChangeCallback callback) {
211         subscribe(HomekitCharacteristicType.TARGET_TEMPERATURE, callback);
212     }
213
214     @Override
215     public void subscribeTemperatureDisplayUnit(HomekitCharacteristicChangeCallback callback) {
216         // TODO: add support for display unit change
217     }
218
219     @Override
220     public void unsubscribeCurrentState() {
221         unsubscribe(CURRENT_HEATING_COOLING_STATE);
222     }
223
224     @Override
225     public void unsubscribeCurrentTemperature() {
226         unsubscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE);
227     }
228
229     @Override
230     public void unsubscribeTemperatureDisplayUnit() {
231         // TODO: add support for display unit change
232     }
233
234     @Override
235     public void unsubscribeTargetState() {
236         unsubscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE);
237     }
238
239     @Override
240     public void unsubscribeTargetTemperature() {
241         unsubscribe(HomekitCharacteristicType.TARGET_TEMPERATURE);
242     }
243 }