]> git.basschouten.com Git - openhab-addons.git/blob
437af5088f12f18246ee6aad16de100bcc1f0e00
[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.somfytahoma.internal.handler;
14
15 import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.*;
16
17 import java.util.Map;
18 import java.util.concurrent.TimeUnit;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaState;
22 import org.openhab.core.library.types.DecimalType;
23 import org.openhab.core.library.types.OnOffType;
24 import org.openhab.core.thing.ChannelUID;
25 import org.openhab.core.thing.Thing;
26 import org.openhab.core.types.Command;
27 import org.openhab.core.types.RefreshType;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * The {@link SomfyTahomaWaterHeatingSystemHandler} is responsible for handling commands,
33  * which are sent to one of the channels of the Water Heating system thing.
34  *
35  * @author Benjamin Lafois - Initial contribution
36  */
37 @NonNullByDefault
38 public class SomfyTahomaWaterHeatingSystemHandler extends SomfyTahomaBaseThingHandler {
39
40     private final Logger logger = LoggerFactory.getLogger(SomfyTahomaWaterHeatingSystemHandler.class);
41
42     private boolean boostMode = false;
43     private boolean awayMode = false;
44
45     public SomfyTahomaWaterHeatingSystemHandler(Thing thing) {
46         super(thing);
47
48         stateNames.put(MIDDLEWATER_TEMPERATURE, MIDDLE_WATER_TEMPERATURE_STATE);
49         stateNames.put(TARGET_TEMPERATURE, TARGET_TEMPERATURE_STATE);
50         stateNames.put(WATER_HEATER_MODE, WATER_HEATER_MODE_STATE);
51
52         stateNames.put(BOOST_MODE_DURATION, BOOST_MODE_DURATION_STATE);
53         // override state type because the cloud sends consumption in percent
54         cacheStateType(BOOST_MODE_DURATION_STATE, TYPE_DECIMAL);
55
56         stateNames.put(AWAY_MODE_DURATION, AWAY_MODE_DURATION_STATE);
57         // override state type because the cloud sends consumption in percent
58         cacheStateType(AWAY_MODE_DURATION_STATE, TYPE_DECIMAL);
59
60         stateNames.put(HEAT_PUMP_OPERATING_TIME, HEAT_PUMP_OPERATING_TIME_STATE);
61         // override state type because the cloud sends consumption in percent
62         cacheStateType(HEAT_PUMP_OPERATING_TIME_STATE, TYPE_DECIMAL);
63
64         stateNames.put(ELECTRIC_BOOSTER_OPERATING_TIME, ELECTRIC_BOOSTER_OPERATING_TIME_STATE);
65         // override state type because the cloud sends consumption in percent
66         cacheStateType(ELECTRIC_BOOSTER_OPERATING_TIME_STATE, TYPE_DECIMAL);
67
68         stateNames.put(POWER_HEAT_PUMP, POWER_HEAT_PUMP_STATE);
69         // override state type because the cloud sends consumption in percent
70         cacheStateType(POWER_HEAT_PUMP_STATE, TYPE_DECIMAL);
71
72         stateNames.put(POWER_HEAT_ELEC, POWER_HEAT_ELEC_STATE);
73         // override state type because the cloud sends consumption in percent
74         cacheStateType(POWER_HEAT_ELEC_STATE, TYPE_DECIMAL);
75     }
76
77     @Override
78     public void updateThingChannels(SomfyTahomaState state) {
79         if (OPERATING_MODE_STATE.equals(state.getName()) && state.getValue() instanceof Map) {
80             logger.debug("Operating Mode State: {}  {}", state.getValue().getClass().getName(), state.getValue());
81
82             Map<String, String> data = (Map<String, String>) state.getValue();
83
84             Object relaunchValue = data.get("relaunch");
85             if (relaunchValue != null) {
86                 this.boostMode = "on".equalsIgnoreCase(relaunchValue.toString());
87                 logger.debug("Boost Value: {}", this.boostMode);
88                 updateState(BOOST_MODE, OnOffType.from(this.boostMode));
89             }
90
91             Object awayValue = data.get("absence");
92             if (awayValue != null) {
93                 this.awayMode = "on".equalsIgnoreCase(awayValue.toString());
94                 logger.debug("Away Value: {}", this.awayMode);
95                 updateState(AWAY_MODE, OnOffType.from(this.awayMode));
96             }
97         } else if (TARGET_TEMPERATURE_STATE.equals(state.getName())) {
98             logger.debug("Target Temperature: {}", state.getValue());
99             // 50 -> 3
100             // 54.5 -> 4
101             // 62 -> 5
102             Double temp = null;
103             try {
104                 temp = Double.parseDouble(state.getValue().toString());
105
106                 int v = 0;
107                 if (temp == 50) {
108                     v = 3;
109                 } else if (temp == 54.5) {
110                     v = 4;
111                 } else if (temp == 62) {
112                     v = 5;
113                 }
114
115                 updateState(SHOWERS, new DecimalType(v));
116             } catch (NumberFormatException e) {
117                 logger.warn("Unexpected pre-defined value for Target State Temperature: {}", state.getValue());
118                 return;
119             }
120
121         }
122
123         super.updateThingChannels(state);
124     }
125
126     private void sendOperatingMode() {
127         sendCommand(COMMAND_SET_CURRENT_OPERATING_MODE, String.format("[ { \"relaunch\":\"%s\", \"absence\":\"%s\"} ]",
128                 (this.boostMode ? "on" : "off"), (this.awayMode ? "on" : "off")));
129     }
130
131     private void sendBoostDuration(int duration) {
132         sendCommand(COMMAND_SET_BOOST_MODE_DURATION, "[ " + duration + " ]");
133     }
134
135     @Override
136     public void handleCommand(ChannelUID channelUID, Command command) {
137         super.handleCommand(channelUID, command);
138
139         if (command instanceof RefreshType) {
140             return;
141         } else {
142             logger.debug("Command received: {}/{}", channelUID.getId(), command.toString());
143
144             if (BOOST_MODE_DURATION.equals(channelUID.getId())) {
145                 int duration = 0;
146                 try {
147                     duration = Integer.parseInt(command.toString());
148                 } catch (NumberFormatException e) {
149                     logger.debug("Invalid value received for boost mode duration: {}", command);
150                     return;
151                 }
152                 if (duration == 0) {
153                     this.boostMode = false;
154                     sendOperatingMode();
155                 } else if (duration > 0 && duration < 8) {
156                     this.boostMode = true;
157                     sendOperatingMode();
158                     sendBoostDuration(duration);
159                 }
160             } else if (WATER_HEATER_MODE.equals(channelUID.getId())) {
161                 sendCommand(COMMAND_SET_WATER_HEATER_MODE, "[ \"" + command.toString() + "\" ]");
162             } else if (AWAY_MODE_DURATION.equals(channelUID.getId())) {
163                 sendCommand(COMMAND_SET_AWAY_MODE_DURATION, "[ \"" + command.toString() + "\" ]");
164             } else if (BOOST_MODE.equals(channelUID.getId()) && command instanceof OnOffType) {
165                 if (command == OnOffType.ON) {
166                     if (this.boostMode) {
167                         return;
168                     }
169                     this.boostMode = true;
170
171                     scheduler.execute(() -> {
172                         sendBoostDuration(1); // by default, boost for 1 day
173                     });
174
175                     scheduler.schedule(() -> {
176                         sendCommand(COMMAND_REFRESH_DHWMODE, "[ ]");
177                     }, 1, TimeUnit.SECONDS);
178
179                     scheduler.schedule(() -> {
180                         sendOperatingMode();
181                     }, 2, TimeUnit.SECONDS);
182
183                     scheduler.schedule(() -> {
184                         sendCommand(COMMAND_REFRESH_BOOST_MODE_DURATION, "[ ]");
185                     }, 3, TimeUnit.SECONDS);
186
187                 } else {
188                     this.boostMode = false;
189                     sendOperatingMode();
190                 }
191             } else if (AWAY_MODE.equals(channelUID.getId()) && command instanceof OnOffType) {
192                 if (command == OnOffType.ON) {
193                     this.boostMode = false;
194                     this.awayMode = true;
195                 } else {
196                     this.awayMode = false;
197                 }
198                 sendOperatingMode();
199             } else if (SHOWERS.equals(channelUID.getId())) {
200                 int showers = 0;
201                 try {
202                     showers = Integer.parseInt(command.toString());
203                 } catch (NumberFormatException e) {
204                     logger.info("Received an invalid value for desired number of showers: {}", command);
205                     return;
206                 }
207                 Double value = 0.0;
208
209                 switch (showers) {
210                     case 3:
211                         value = 50.0;
212                         break;
213                     case 4:
214                         value = 54.5;
215                         break;
216                     case 5:
217                         value = 62.0;
218                         break;
219                     default:
220                         break;
221                 }
222                 sendCommand(COMMAND_SET_TARGET_TEMPERATURE, "[ " + value.toString() + " ]");
223             }
224
225         }
226     }
227 }