]> git.basschouten.com Git - openhab-addons.git/blob
b4720e9326904733272d5ff091b1b7447f3b1e70
[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.binding.daikin.internal.handler;
14
15 import java.io.IOException;
16 import java.math.BigDecimal;
17 import java.util.Optional;
18 import java.util.stream.IntStream;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.eclipse.jetty.client.HttpClient;
23 import org.openhab.binding.daikin.internal.DaikinBindingConstants;
24 import org.openhab.binding.daikin.internal.DaikinCommunicationException;
25 import org.openhab.binding.daikin.internal.DaikinDynamicStateDescriptionProvider;
26 import org.openhab.binding.daikin.internal.DaikinWebTargets;
27 import org.openhab.binding.daikin.internal.api.ControlInfo;
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.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.thing.ThingStatus;
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 <paul@smedley.id.au> - Modifications to support Airbase Controllers
53  * @author Lukas Agethen - Added support for Energy Year reading, compressor frequency and powerful mode
54  */
55 @NonNullByDefault
56 public class DaikinAcUnitHandler extends DaikinBaseHandler {
57     private final Logger logger = LoggerFactory.getLogger(DaikinAcUnitHandler.class);
58
59     public DaikinAcUnitHandler(Thing thing, DaikinDynamicStateDescriptionProvider stateDescriptionProvider,
60             @Nullable HttpClient httpClient) {
61         super(thing, stateDescriptionProvider, httpClient);
62     }
63
64     @Override
65     protected void pollStatus() throws IOException {
66         DaikinWebTargets webTargets = this.webTargets;
67         if (webTargets == null) {
68             return;
69         }
70         ControlInfo controlInfo = webTargets.getControlInfo();
71         updateStatus(ThingStatus.ONLINE);
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_PREFIX,
122                         energyInfoYear.energyHeatingThisYear);
123             }
124             if (energyInfoYear.energyCoolingThisYear.isPresent()) {
125                 updateEnergyYearChannel(DaikinBindingConstants.CHANNEL_ENERGY_COOLING_CURRENTYEAR_PREFIX,
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
134     @Override
135     protected boolean handleCommandInternal(ChannelUID channelUID, Command command)
136             throws DaikinCommunicationException {
137         switch (channelUID.getId()) {
138             case DaikinBindingConstants.CHANNEL_AC_FAN_DIR:
139                 if (command instanceof StringType) {
140                     changeFanDir(((StringType) command).toString());
141                     return true;
142                 }
143                 break;
144             case DaikinBindingConstants.CHANNEL_AC_SPECIALMODE_POWERFUL:
145                 if (command instanceof OnOffType) {
146                     changeSpecialModePowerful(((OnOffType) command).equals(OnOffType.ON));
147                     return true;
148                 }
149                 break;
150         }
151         return false;
152     }
153
154     @Override
155     protected void changePower(boolean power) throws DaikinCommunicationException {
156         DaikinWebTargets webTargets = this.webTargets;
157         if (webTargets == null) {
158             return;
159         }
160         ControlInfo info = webTargets.getControlInfo();
161         info.power = power;
162         webTargets.setControlInfo(info);
163     }
164
165     @Override
166     protected void changeSetPoint(double newTemperature) throws DaikinCommunicationException {
167         DaikinWebTargets webTargets = this.webTargets;
168         if (webTargets == null) {
169             return;
170         }
171         ControlInfo info = webTargets.getControlInfo();
172         info.temp = Optional.of(newTemperature);
173         webTargets.setControlInfo(info);
174     }
175
176     @Override
177     protected void changeMode(String mode) throws DaikinCommunicationException {
178         DaikinWebTargets webTargets = this.webTargets;
179         if (webTargets == null) {
180             return;
181         }
182         Mode newMode;
183         try {
184             newMode = Mode.valueOf(mode);
185         } catch (IllegalArgumentException ex) {
186             logger.warn("Invalid mode: {}. Valid values: {}", mode, Mode.values());
187             return;
188         }
189         ControlInfo info = webTargets.getControlInfo();
190         info.mode = newMode;
191         webTargets.setControlInfo(info);
192     }
193
194     @Override
195     protected void changeFanSpeed(String fanSpeed) throws DaikinCommunicationException {
196         DaikinWebTargets webTargets = this.webTargets;
197         if (webTargets == null) {
198             return;
199         }
200         FanSpeed newSpeed;
201         try {
202             newSpeed = FanSpeed.valueOf(fanSpeed);
203         } catch (IllegalArgumentException ex) {
204             logger.warn("Invalid fan speed: {}. Valid values: {}", fanSpeed, FanSpeed.values());
205             return;
206         }
207         ControlInfo info = webTargets.getControlInfo();
208         info.fanSpeed = newSpeed;
209         webTargets.setControlInfo(info);
210     }
211
212     protected void changeFanDir(String fanDir) throws DaikinCommunicationException {
213         DaikinWebTargets webTargets = this.webTargets;
214         if (webTargets == null) {
215             return;
216         }
217         FanMovement newMovement;
218         try {
219             newMovement = FanMovement.valueOf(fanDir);
220         } catch (IllegalArgumentException ex) {
221             logger.warn("Invalid fan direction: {}. Valid values: {}", fanDir, FanMovement.values());
222             return;
223         }
224         ControlInfo info = webTargets.getControlInfo();
225         info.fanMovement = newMovement;
226         webTargets.setControlInfo(info);
227     }
228
229     /**
230      *
231      * @param powerfulMode
232      * @return Is change successful
233      * @throws DaikinCommunicationException
234      */
235     protected boolean changeSpecialModePowerful(boolean powerfulMode) throws DaikinCommunicationException {
236         DaikinWebTargets webTargets = this.webTargets;
237         if (webTargets == null) {
238             return false;
239         }
240         return webTargets.setSpecialMode(SpecialModeKind.POWERFUL, powerfulMode);
241     }
242
243     /**
244      * Updates energy year channels. Values are provided in hundreds of Watt
245      *
246      * @param channelPrefix
247      * @param maybePower
248      */
249     protected void updateEnergyYearChannel(String channelPrefix, Optional<Integer[]> maybePower) {
250         IntStream.range(1, 13).forEach(i -> updateState(
251                 String.format(DaikinBindingConstants.CHANNEL_ENERGY_STRING_FORMAT, channelPrefix, i),
252                 maybePower.<State> map(
253                         t -> new QuantityType<>(BigDecimal.valueOf(t[i - 1].longValue(), 1), Units.KILOWATT_HOUR))
254                         .orElse(UnDefType.UNDEF))
255
256         );
257     }
258
259     @Override
260     protected void registerUuid(@Nullable String key) {
261         if (key == null) {
262             return;
263         }
264         try {
265             DaikinWebTargets webTargets = this.webTargets;
266             if (webTargets == null) {
267                 return;
268             }
269             webTargets.registerUuid(key);
270         } catch (Exception e) {
271             // suppress exceptions
272             logger.debug("registerUuid({}) error: {}", key, e.getMessage());
273         }
274     }
275 }