]> git.basschouten.com Git - openhab-addons.git/blob
a96dd1d952f9eb07c24608e293b8c1169c16fbcc
[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.daikin.internal.handler;
14
15 import java.math.BigDecimal;
16 import java.util.Optional;
17 import java.util.stream.IntStream;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.eclipse.jetty.client.HttpClient;
22 import org.openhab.binding.daikin.internal.DaikinBindingConstants;
23 import org.openhab.binding.daikin.internal.DaikinCommunicationException;
24 import org.openhab.binding.daikin.internal.DaikinDynamicStateDescriptionProvider;
25 import org.openhab.binding.daikin.internal.DaikinWebTargets;
26 import org.openhab.binding.daikin.internal.api.ControlInfo;
27 import org.openhab.binding.daikin.internal.api.EnergyInfoDayAndWeek;
28 import org.openhab.binding.daikin.internal.api.EnergyInfoYear;
29 import org.openhab.binding.daikin.internal.api.Enums.FanMovement;
30 import org.openhab.binding.daikin.internal.api.Enums.FanSpeed;
31 import org.openhab.binding.daikin.internal.api.Enums.HomekitMode;
32 import org.openhab.binding.daikin.internal.api.Enums.Mode;
33 import org.openhab.binding.daikin.internal.api.Enums.SpecialModeKind;
34 import org.openhab.binding.daikin.internal.api.SensorInfo;
35 import org.openhab.core.library.types.DecimalType;
36 import org.openhab.core.library.types.OnOffType;
37 import org.openhab.core.library.types.QuantityType;
38 import org.openhab.core.library.types.StringType;
39 import org.openhab.core.library.unit.Units;
40 import org.openhab.core.thing.ChannelUID;
41 import org.openhab.core.thing.Thing;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.types.State;
44 import org.openhab.core.types.UnDefType;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * Handles communicating with a Daikin air conditioning unit.
50  *
51  * @author Tim Waterhouse - Initial Contribution
52  * @author Paul Smedley - Modifications to support Airbase Controllers
53  * @author Lukas Agethen - Added support for Energy Year reading, compressor frequency and powerful mode
54  * @author Wouter Denayer - Added to support for weekly & daily energy reading
55  *
56  */
57 @NonNullByDefault
58 public class DaikinAcUnitHandler extends DaikinBaseHandler {
59     private final Logger logger = LoggerFactory.getLogger(DaikinAcUnitHandler.class);
60
61     public DaikinAcUnitHandler(Thing thing, DaikinDynamicStateDescriptionProvider stateDescriptionProvider,
62             @Nullable HttpClient httpClient) {
63         super(thing, stateDescriptionProvider, httpClient);
64     }
65
66     @Override
67     protected void pollStatus() throws DaikinCommunicationException {
68         ControlInfo controlInfo = webTargets.getControlInfo();
69         if (!"OK".equals(controlInfo.ret)) {
70             throw new DaikinCommunicationException("Invalid response from host");
71         }
72         updateState(DaikinBindingConstants.CHANNEL_AC_POWER, controlInfo.power ? OnOffType.ON : OnOffType.OFF);
73         updateTemperatureChannel(DaikinBindingConstants.CHANNEL_AC_TEMP, controlInfo.temp);
74
75         updateState(DaikinBindingConstants.CHANNEL_AC_MODE, new StringType(controlInfo.mode.name()));
76         updateState(DaikinBindingConstants.CHANNEL_AC_FAN_SPEED, new StringType(controlInfo.fanSpeed.name()));
77         updateState(DaikinBindingConstants.CHANNEL_AC_FAN_DIR, new StringType(controlInfo.fanMovement.name()));
78
79         if (!controlInfo.power) {
80             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.OFF.getValue()));
81         } else if (controlInfo.mode == Mode.COLD) {
82             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.COOL.getValue()));
83         } else if (controlInfo.mode == Mode.HEAT) {
84             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.HEAT.getValue()));
85         } else if (controlInfo.mode == Mode.AUTO) {
86             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.AUTO.getValue()));
87         }
88
89         updateState(DaikinBindingConstants.CHANNEL_AC_SPECIALMODE, new StringType(controlInfo.specialMode.name()));
90
91         if (controlInfo.specialMode.isUndefined()) {
92             updateState(DaikinBindingConstants.CHANNEL_AC_SPECIALMODE_POWERFUL, UnDefType.UNDEF);
93         } else {
94             updateState(DaikinBindingConstants.CHANNEL_AC_SPECIALMODE_POWERFUL,
95                     controlInfo.specialMode.isPowerfulActive() ? OnOffType.ON : OnOffType.OFF);
96         }
97
98         SensorInfo sensorInfo = webTargets.getSensorInfo();
99         updateTemperatureChannel(DaikinBindingConstants.CHANNEL_INDOOR_TEMP, sensorInfo.indoortemp);
100
101         updateTemperatureChannel(DaikinBindingConstants.CHANNEL_OUTDOOR_TEMP, sensorInfo.outdoortemp);
102
103         if (sensorInfo.indoorhumidity.isPresent()) {
104             updateState(DaikinBindingConstants.CHANNEL_HUMIDITY,
105                     new QuantityType<>(sensorInfo.indoorhumidity.get(), Units.PERCENT));
106         } else {
107             updateState(DaikinBindingConstants.CHANNEL_HUMIDITY, UnDefType.UNDEF);
108         }
109
110         if (sensorInfo.compressorfrequency.isPresent()) {
111             updateState(DaikinBindingConstants.CHANNEL_CMP_FREQ,
112                     new QuantityType<>(sensorInfo.compressorfrequency.get(), Units.PERCENT));
113         } else {
114             updateState(DaikinBindingConstants.CHANNEL_CMP_FREQ, UnDefType.UNDEF);
115         }
116
117         try {
118             EnergyInfoYear energyInfoYear = webTargets.getEnergyInfoYear();
119
120             if (energyInfoYear.energyHeatingThisYear.isPresent()) {
121                 updateEnergyYearChannel(DaikinBindingConstants.CHANNEL_ENERGY_HEATING_CURRENTYEAR,
122                         energyInfoYear.energyHeatingThisYear);
123             }
124             if (energyInfoYear.energyCoolingThisYear.isPresent()) {
125                 updateEnergyYearChannel(DaikinBindingConstants.CHANNEL_ENERGY_COOLING_CURRENTYEAR,
126                         energyInfoYear.energyCoolingThisYear);
127             }
128         } catch (DaikinCommunicationException e) {
129             // Suppress any error if energy info is not supported.
130             logger.debug("getEnergyInfoYear() error: {}", e.getMessage());
131         }
132
133         try {
134             EnergyInfoDayAndWeek energyInfoDayAndWeek = webTargets.getEnergyInfoDayAndWeek();
135
136             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_HEATING_TODAY,
137                     energyInfoDayAndWeek.energyHeatingToday);
138             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_HEATING_THISWEEK,
139                     energyInfoDayAndWeek.energyHeatingThisWeek);
140             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_HEATING_LASTWEEK,
141                     energyInfoDayAndWeek.energyHeatingLastWeek);
142             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_COOLING_TODAY,
143                     energyInfoDayAndWeek.energyCoolingToday);
144             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_COOLING_THISWEEK,
145                     energyInfoDayAndWeek.energyCoolingThisWeek);
146             updateEnergyDayAndWeekChannel(DaikinBindingConstants.CHANNEL_ENERGY_COOLING_LASTWEEK,
147                     energyInfoDayAndWeek.energyCoolingLastWeek);
148         } catch (DaikinCommunicationException e) {
149             // Suppress any error if energy info is not supported.
150             logger.debug("getEnergyInfoDayAndWeek() error: {}", e.getMessage());
151         }
152     }
153
154     @Override
155     protected boolean handleCommandInternal(ChannelUID channelUID, Command command)
156             throws DaikinCommunicationException {
157         switch (channelUID.getId()) {
158             case DaikinBindingConstants.CHANNEL_AC_FAN_DIR:
159                 if (command instanceof StringType) {
160                     changeFanDir(((StringType) command).toString());
161                     return true;
162                 }
163                 break;
164             case DaikinBindingConstants.CHANNEL_AC_SPECIALMODE_POWERFUL:
165                 if (command instanceof OnOffType) {
166                     changeSpecialModePowerful(((OnOffType) command).equals(OnOffType.ON));
167                     return true;
168                 }
169                 break;
170         }
171         return false;
172     }
173
174     @Override
175     protected void changePower(boolean power) throws DaikinCommunicationException {
176         DaikinWebTargets webTargets = this.webTargets;
177         if (webTargets == null) {
178             return;
179         }
180         ControlInfo info = webTargets.getControlInfo();
181         info.power = power;
182         webTargets.setControlInfo(info);
183     }
184
185     @Override
186     protected void changeSetPoint(double newTemperature) throws DaikinCommunicationException {
187         DaikinWebTargets webTargets = this.webTargets;
188         if (webTargets == null) {
189             return;
190         }
191         ControlInfo info = webTargets.getControlInfo();
192         info.temp = Optional.of(newTemperature);
193         webTargets.setControlInfo(info);
194     }
195
196     @Override
197     protected void changeMode(String mode) throws DaikinCommunicationException {
198         DaikinWebTargets webTargets = this.webTargets;
199         if (webTargets == null) {
200             return;
201         }
202         Mode newMode;
203         try {
204             newMode = Mode.valueOf(mode);
205         } catch (IllegalArgumentException ex) {
206             logger.warn("Invalid mode: {}. Valid values: {}", mode, Mode.values());
207             return;
208         }
209         ControlInfo info = webTargets.getControlInfo();
210         info.mode = newMode;
211         webTargets.setControlInfo(info);
212     }
213
214     @Override
215     protected void changeFanSpeed(String fanSpeed) throws DaikinCommunicationException {
216         DaikinWebTargets webTargets = this.webTargets;
217         if (webTargets == null) {
218             return;
219         }
220         FanSpeed newSpeed;
221         try {
222             newSpeed = FanSpeed.valueOf(fanSpeed);
223         } catch (IllegalArgumentException ex) {
224             logger.warn("Invalid fan speed: {}. Valid values: {}", fanSpeed, FanSpeed.values());
225             return;
226         }
227         ControlInfo info = webTargets.getControlInfo();
228         info.fanSpeed = newSpeed;
229         webTargets.setControlInfo(info);
230     }
231
232     protected void changeFanDir(String fanDir) throws DaikinCommunicationException {
233         DaikinWebTargets webTargets = this.webTargets;
234         if (webTargets == null) {
235             return;
236         }
237         FanMovement newMovement;
238         try {
239             newMovement = FanMovement.valueOf(fanDir);
240         } catch (IllegalArgumentException ex) {
241             logger.warn("Invalid fan direction: {}. Valid values: {}", fanDir, FanMovement.values());
242             return;
243         }
244         ControlInfo info = webTargets.getControlInfo();
245         info.fanMovement = newMovement;
246         webTargets.setControlInfo(info);
247     }
248
249     /**
250      *
251      * @param powerfulMode
252      * @return Is change successful
253      * @throws DaikinCommunicationException
254      */
255     protected boolean changeSpecialModePowerful(boolean powerfulMode) throws DaikinCommunicationException {
256         DaikinWebTargets webTargets = this.webTargets;
257         if (webTargets == null) {
258             return false;
259         }
260         return webTargets.setSpecialMode(SpecialModeKind.POWERFUL, powerfulMode);
261     }
262
263     /**
264      * Updates energy year channels. Values are provided in hundreds of Watt
265      *
266      * @param channel
267      * @param maybePower
268      */
269     protected void updateEnergyYearChannel(String channel, Optional<Integer[]> maybePower) {
270         IntStream.range(1, 13).forEach(i -> updateState(
271                 String.format(DaikinBindingConstants.CHANNEL_ENERGY_STRING_FORMAT, channel, i),
272                 maybePower.<State> map(
273                         t -> new QuantityType<>(BigDecimal.valueOf(t[i - 1].longValue(), 1), Units.KILOWATT_HOUR))
274                         .orElse(UnDefType.UNDEF))
275
276         );
277     }
278
279     /**
280      *
281      * @param channel
282      * @param maybePower
283      */
284     protected void updateEnergyDayAndWeekChannel(String channel, Optional<Double> maybePower) {
285         if (maybePower.isPresent()) {
286             updateState(channel,
287                     maybePower.<State> map(t -> new QuantityType<>(new DecimalType(t), Units.KILOWATT_HOUR))
288                             .orElse(UnDefType.UNDEF));
289         }
290     }
291
292     @Override
293     protected void registerUuid(@Nullable String key) {
294         if (key == null) {
295             return;
296         }
297         try {
298             DaikinWebTargets webTargets = this.webTargets;
299             if (webTargets == null) {
300                 return;
301             }
302             webTargets.registerUuid(key);
303         } catch (DaikinCommunicationException e) {
304             // suppress exceptions
305             logger.debug("registerUuid({}) error: {}", key, e.getMessage());
306         }
307     }
308 }