]> git.basschouten.com Git - openhab-addons.git/blob
4bfe677f1d6c53f882daa0fba8dfdcdcc9ffce4f
[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.qbus.internal.handler;
14
15 import static org.openhab.binding.qbus.internal.QbusBindingConstants.*;
16 import static org.openhab.core.library.unit.SIUnits.CELSIUS;
17 import static org.openhab.core.types.RefreshType.REFRESH;
18
19 import java.io.IOException;
20 import java.util.Map;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.qbus.internal.QbusBridgeHandler;
25 import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
26 import org.openhab.binding.qbus.internal.protocol.QbusThermostat;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.types.Command;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link QbusThermostatHandler} is responsible for handling the Thermostat outputs of Qbus
39  *
40  * @author Koen Schockaert - Initial Contribution
41  */
42
43 @NonNullByDefault
44 public class QbusThermostatHandler extends QbusGlobalHandler {
45
46     private final Logger logger = LoggerFactory.getLogger(QbusThermostatHandler.class);
47
48     protected @Nullable QbusThingsConfig thermostatConfig = new QbusThingsConfig();
49
50     private @Nullable Integer thermostatId;
51
52     private @Nullable String sn;
53
54     public QbusThermostatHandler(Thing thing) {
55         super(thing);
56     }
57
58     /**
59      * Main initialization
60      */
61     @Override
62     public void initialize() {
63         readConfig();
64
65         this.thermostatId = getId();
66
67         setSN();
68
69         scheduler.submit(() -> {
70             QbusCommunication controllerComm;
71
72             if (this.thermostatId != null) {
73                 controllerComm = getCommunication("Thermostat", this.thermostatId);
74             } else {
75                 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for THERMOSTAT no set! " + this.thermostatId);
76                 return;
77             }
78
79             if (controllerComm == null) {
80                 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
81                         "ID for THERMOSTAT not known in controller " + this.thermostatId);
82                 return;
83             }
84
85             Map<Integer, QbusThermostat> thermostatlCommLocal = controllerComm.getThermostat();
86
87             QbusThermostat outputLocal = thermostatlCommLocal.get(this.thermostatId);
88
89             if (outputLocal == null) {
90                 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
91                         "Bridge could not initialize THERMOSTAT ID " + this.thermostatId);
92                 return;
93             }
94
95             outputLocal.setThingHandler(this);
96             handleStateUpdate(outputLocal);
97
98             QbusBridgeHandler qBridgeHandler = getBridgeHandler("Thermostat", this.thermostatId);
99
100             if (qBridgeHandler != null) {
101                 if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
102                     updateStatus(ThingStatus.ONLINE);
103                 } else {
104                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
105                             "Bridge offline for THERMOSTAT ID " + this.thermostatId);
106                 }
107             }
108         });
109     }
110
111     /**
112      * Handle the status update from the thermostat
113      */
114     @Override
115     public void handleCommand(ChannelUID channelUID, Command command) {
116         QbusCommunication qComm = getCommunication("Thermostat", this.thermostatId);
117
118         if (qComm == null) {
119             thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
120                     "ID for THERMOSTAT not known in controller " + this.thermostatId);
121             return;
122         } else {
123             Map<Integer, QbusThermostat> thermostatComm = qComm.getThermostat();
124
125             QbusThermostat qThermostat = thermostatComm.get(this.thermostatId);
126
127             if (qThermostat == null) {
128                 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
129                         "ID for THERMOSTAT not known in controller " + this.thermostatId);
130                 return;
131             } else {
132                 scheduler.submit(() -> {
133                     if (!qComm.communicationActive()) {
134                         restartCommunication(qComm, "Thermostat", this.thermostatId);
135                     }
136
137                     if (qComm.communicationActive()) {
138                         if (command == REFRESH) {
139                             handleStateUpdate(qThermostat);
140                             return;
141                         }
142
143                         switch (channelUID.getId()) {
144                             case CHANNEL_MODE:
145                                 try {
146                                     handleModeCommand(qThermostat, command);
147                                 } catch (IOException e) {
148                                     String message = e.getMessage();
149                                     logger.warn("Error on executing Mode for thermostat ID {}. IOException: {} ",
150                                             this.thermostatId, message);
151                                 } catch (InterruptedException e) {
152                                     String message = e.getMessage();
153                                     logger.warn(
154                                             "Error on executing Mode for thermostat ID {}. Interruptedexception {} ",
155                                             this.thermostatId, message);
156                                 }
157                                 break;
158
159                             case CHANNEL_SETPOINT:
160                                 try {
161                                     handleSetpointCommand(qThermostat, command);
162                                 } catch (IOException e) {
163                                     String message = e.getMessage();
164                                     logger.warn("Error on executing Setpoint for thermostat ID {}. IOException: {} ",
165                                             this.thermostatId, message);
166                                 } catch (InterruptedException e) {
167                                     String message = e.getMessage();
168                                     logger.warn(
169                                             "Error on executing Setpoint for thermostat ID {}. Interruptedexception {} ",
170                                             this.thermostatId, message);
171                                 }
172                                 break;
173
174                             default:
175                                 thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
176                                         "Unknown Channel " + channelUID.getId());
177                         }
178                     }
179                 });
180             }
181         }
182     }
183
184     /**
185      * Executes the Mode command
186      *
187      * @param qThermostat
188      * @param command
189      * @param snr
190      * @throws InterruptedException
191      * @throws IOException
192      */
193     private void handleModeCommand(QbusThermostat qThermostat, Command command)
194             throws InterruptedException, IOException {
195         String snr = getSN();
196         if (snr != null) {
197             if (command instanceof DecimalType) {
198                 int mode = ((DecimalType) command).intValue();
199                 qThermostat.executeMode(mode, snr);
200             }
201         }
202     }
203
204     /**
205      * Executes the Setpoint command
206      *
207      * @param qThermostat
208      * @param command
209      * @param snr
210      * @throws InterruptedException
211      * @throws IOException
212      */
213     private void handleSetpointCommand(QbusThermostat qThermostat, Command command)
214             throws InterruptedException, IOException {
215         String snr = getSN();
216         if (snr != null) {
217             if (command instanceof QuantityType<?>) {
218                 QuantityType<?> s = (QuantityType<?>) command;
219                 double sp = s.doubleValue();
220                 QuantityType<?> spCelcius = s.toUnit(CELSIUS);
221
222                 if (spCelcius != null) {
223                     qThermostat.executeSetpoint(sp, snr);
224                 } else {
225                     logger.warn("Could not set setpoint for thermostat (conversion failed)  {}", this.thermostatId);
226                 }
227             }
228         }
229     }
230
231     /**
232      * Method to update state of all channels, called from Qbus thermostat.
233      *
234      * @param qThermostat
235      */
236     public void handleStateUpdate(QbusThermostat qThermostat) {
237         Double measured = qThermostat.getMeasured();
238         if (measured != null) {
239             updateState(CHANNEL_MEASURED, new QuantityType<>(measured, CELSIUS));
240         }
241
242         Double setpoint = qThermostat.getSetpoint();
243         if (setpoint != null) {
244             updateState(CHANNEL_SETPOINT, new QuantityType<>(setpoint, CELSIUS));
245         }
246
247         Integer mode = qThermostat.getMode();
248         if (mode != null) {
249             updateState(CHANNEL_MODE, new DecimalType(mode));
250         }
251     }
252
253     /**
254      * Returns the serial number of the controller
255      *
256      * @return the serial nr
257      */
258     public @Nullable String getSN() {
259         return sn;
260     }
261
262     /**
263      * Sets the serial number of the controller
264      */
265     public void setSN() {
266         QbusBridgeHandler qBridgeHandler = getBridgeHandler("Thermostsat", this.thermostatId);
267         if (qBridgeHandler == null) {
268             thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
269                     "No communication with Qbus Bridge for THERMOSTAT " + this.thermostatId);
270             return;
271         }
272         sn = qBridgeHandler.getSn();
273     }
274
275     /**
276      * Read the configuration
277      */
278     protected synchronized void readConfig() {
279         thermostatConfig = getConfig().as(QbusThingsConfig.class);
280     }
281
282     /**
283      * Returns the Id from the configuration
284      *
285      * @return outputId
286      */
287     public @Nullable Integer getId() {
288         QbusThingsConfig localConfig = thermostatConfig;
289         if (localConfig != null) {
290             return localConfig.thermostatId;
291         } else {
292             return null;
293         }
294     }
295 }