]> git.basschouten.com Git - openhab-addons.git/blob
698b0b39be4de7bbb4897c4f4f4e3257d13c3f20
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.api.ControlInfo;
26 import org.openhab.binding.daikin.internal.api.EnergyInfoDayAndWeek;
27 import org.openhab.binding.daikin.internal.api.EnergyInfoYear;
28 import org.openhab.binding.daikin.internal.api.Enums.FanMovement;
29 import org.openhab.binding.daikin.internal.api.Enums.FanSpeed;
30 import org.openhab.binding.daikin.internal.api.Enums.HomekitMode;
31 import org.openhab.binding.daikin.internal.api.Enums.Mode;
32 import org.openhab.binding.daikin.internal.api.Enums.SpecialMode;
33 import org.openhab.binding.daikin.internal.api.SensorInfo;
34 import org.openhab.core.library.types.DecimalType;
35 import org.openhab.core.library.types.OnOffType;
36 import org.openhab.core.library.types.QuantityType;
37 import org.openhab.core.library.types.StringType;
38 import org.openhab.core.library.unit.Units;
39 import org.openhab.core.thing.ChannelUID;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.types.Command;
42 import org.openhab.core.types.State;
43 import org.openhab.core.types.UnDefType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * Handles communicating with a Daikin air conditioning unit.
49  *
50  * @author Tim Waterhouse - Initial Contribution
51  * @author Paul Smedley - Modifications to support Airbase Controllers
52  * @author Lukas Agethen - Added support for Energy Year reading, compressor frequency and powerful mode
53  * @author Wouter Denayer - Added to support for weekly & daily energy reading
54  *
55  */
56 @NonNullByDefault
57 public class DaikinAcUnitHandler extends DaikinBaseHandler {
58     private final Logger logger = LoggerFactory.getLogger(DaikinAcUnitHandler.class);
59
60     public DaikinAcUnitHandler(Thing thing, DaikinDynamicStateDescriptionProvider stateDescriptionProvider,
61             @Nullable HttpClient httpClient) {
62         super(thing, stateDescriptionProvider, httpClient);
63     }
64
65     @Override
66     protected void pollStatus() throws DaikinCommunicationException {
67         ControlInfo controlInfo = webTargets.getControlInfo();
68         if (!"OK".equals(controlInfo.ret)) {
69             throw new DaikinCommunicationException("Invalid response from host");
70         }
71         updateState(DaikinBindingConstants.CHANNEL_AC_POWER, OnOffType.from(controlInfo.power));
72         updateTemperatureChannel(DaikinBindingConstants.CHANNEL_AC_TEMP, controlInfo.temp);
73
74         updateState(DaikinBindingConstants.CHANNEL_AC_MODE, new StringType(controlInfo.mode.name()));
75         updateState(DaikinBindingConstants.CHANNEL_AC_FAN_SPEED, new StringType(controlInfo.fanSpeed.name()));
76         updateState(DaikinBindingConstants.CHANNEL_AC_FAN_DIR, new StringType(controlInfo.fanMovement.name()));
77
78         if (!controlInfo.power) {
79             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.OFF.getValue()));
80         } else if (controlInfo.mode == Mode.COLD) {
81             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.COOL.getValue()));
82         } else if (controlInfo.mode == Mode.HEAT) {
83             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.HEAT.getValue()));
84         } else if (controlInfo.mode == Mode.AUTO) {
85             updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.AUTO.getValue()));
86         }
87
88         if (controlInfo.advancedMode.isUndefined()) {
89             updateState(DaikinBindingConstants.CHANNEL_AC_STREAMER, UnDefType.UNDEF);
90             updateState(DaikinBindingConstants.CHANNEL_AC_SPECIALMODE, UnDefType.UNDEF);
91         } else {
92             updateState(DaikinBindingConstants.CHANNEL_AC_STREAMER,
93                     OnOffType.from(controlInfo.advancedMode.isStreamerActive()));
94             updateState(DaikinBindingConstants.CHANNEL_AC_SPECIALMODE,
95                     new StringType(controlInfo.getSpecialMode().name()));
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:
165                 if (command instanceof StringType) {
166                     changeSpecialMode(((StringType) command).toString());
167                     return true;
168                 }
169                 break;
170             case DaikinBindingConstants.CHANNEL_AC_STREAMER:
171                 if (command instanceof OnOffType) {
172                     changeStreamer(((OnOffType) command).equals(OnOffType.ON));
173                     return true;
174                 }
175                 break;
176         }
177         return false;
178     }
179
180     @Override
181     protected void changePower(boolean power) throws DaikinCommunicationException {
182         ControlInfo info = webTargets.getControlInfo();
183         info.power = power;
184         webTargets.setControlInfo(info);
185     }
186
187     @Override
188     protected void changeSetPoint(double newTemperature) throws DaikinCommunicationException {
189         ControlInfo info = webTargets.getControlInfo();
190         info.temp = Optional.of(newTemperature);
191         webTargets.setControlInfo(info);
192     }
193
194     @Override
195     protected void changeMode(String mode) throws DaikinCommunicationException {
196         Mode newMode;
197         try {
198             newMode = Mode.valueOf(mode);
199         } catch (IllegalArgumentException ex) {
200             logger.warn("Invalid mode: {}. Valid values: {}", mode, Mode.values());
201             return;
202         }
203         ControlInfo info = webTargets.getControlInfo();
204         info.mode = newMode;
205         webTargets.setControlInfo(info);
206     }
207
208     @Override
209     protected void changeFanSpeed(String fanSpeed) throws DaikinCommunicationException {
210         FanSpeed newSpeed;
211         try {
212             newSpeed = FanSpeed.valueOf(fanSpeed);
213         } catch (IllegalArgumentException ex) {
214             logger.warn("Invalid fan speed: {}. Valid values: {}", fanSpeed, FanSpeed.values());
215             return;
216         }
217         ControlInfo info = webTargets.getControlInfo();
218         info.fanSpeed = newSpeed;
219         webTargets.setControlInfo(info);
220     }
221
222     protected void changeFanDir(String fanDir) throws DaikinCommunicationException {
223         FanMovement newMovement;
224         try {
225             newMovement = FanMovement.valueOf(fanDir);
226         } catch (IllegalArgumentException ex) {
227             logger.warn("Invalid fan direction: {}. Valid values: {}", fanDir, FanMovement.values());
228             return;
229         }
230         ControlInfo info = webTargets.getControlInfo();
231         info.fanMovement = newMovement;
232         webTargets.setControlInfo(info);
233     }
234
235     protected void changeSpecialMode(String specialMode) throws DaikinCommunicationException {
236         SpecialMode newMode;
237         try {
238             newMode = SpecialMode.valueOf(specialMode);
239         } catch (IllegalArgumentException e) {
240             logger.warn("Invalid specialmode: {}. Valid values: {}", specialMode, SpecialMode.values());
241             return;
242         }
243         webTargets.setSpecialMode(newMode);
244     }
245
246     protected void changeStreamer(boolean streamerMode) throws DaikinCommunicationException {
247         webTargets.setStreamerMode(streamerMode);
248     }
249
250     /**
251      * Updates energy year channels. Values are provided in hundreds of Watt
252      *
253      * @param channel
254      * @param maybePower
255      */
256     protected void updateEnergyYearChannel(String channel, Optional<Integer[]> maybePower) {
257         IntStream.range(1, 13).forEach(i -> updateState(
258                 String.format(DaikinBindingConstants.CHANNEL_ENERGY_STRING_FORMAT, channel, i),
259                 maybePower.<State> map(
260                         t -> new QuantityType<>(BigDecimal.valueOf(t[i - 1].longValue(), 1), Units.KILOWATT_HOUR))
261                         .orElse(UnDefType.UNDEF))
262
263         );
264     }
265
266     /**
267      *
268      * @param channel
269      * @param maybePower
270      */
271     protected void updateEnergyDayAndWeekChannel(String channel, Optional<Double> maybePower) {
272         if (maybePower.isPresent()) {
273             updateState(channel,
274                     maybePower.<State> map(t -> new QuantityType<>(new DecimalType(t), Units.KILOWATT_HOUR))
275                             .orElse(UnDefType.UNDEF));
276         }
277     }
278
279     @Override
280     protected void registerUuid(@Nullable String key) {
281         if (key == null) {
282             return;
283         }
284         try {
285             webTargets.registerUuid(key);
286         } catch (DaikinCommunicationException e) {
287             // suppress exceptions
288             logger.debug("registerUuid({}) error: {}", key, e.getMessage());
289         }
290     }
291 }