2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.qbus.internal.handler;
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;
19 import java.io.IOException;
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;
38 * The {@link QbusThermostatHandler} is responsible for handling the Thermostat outputs of Qbus
40 * @author Koen Schockaert - Initial Contribution
44 public class QbusThermostatHandler extends QbusGlobalHandler {
46 private final Logger logger = LoggerFactory.getLogger(QbusThermostatHandler.class);
48 protected @Nullable QbusThingsConfig thermostatConfig = new QbusThingsConfig();
50 private @Nullable Integer thermostatId;
52 private @Nullable String sn;
54 public QbusThermostatHandler(Thing thing) {
62 public void initialize() {
65 this.thermostatId = getId();
69 scheduler.submit(() -> {
70 QbusCommunication controllerComm;
72 if (this.thermostatId != null) {
73 controllerComm = getCommunication("Thermostat", this.thermostatId);
75 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for THERMOSTAT no set! " + this.thermostatId);
79 if (controllerComm == null) {
80 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
81 "ID for THERMOSTAT not known in controller " + this.thermostatId);
85 Map<Integer, QbusThermostat> thermostatlCommLocal = controllerComm.getThermostat();
87 QbusThermostat outputLocal = thermostatlCommLocal.get(this.thermostatId);
89 if (outputLocal == null) {
90 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
91 "Bridge could not initialize THERMOSTAT ID " + this.thermostatId);
95 outputLocal.setThingHandler(this);
96 handleStateUpdate(outputLocal);
98 QbusBridgeHandler qBridgeHandler = getBridgeHandler("Thermostat", this.thermostatId);
100 if (qBridgeHandler != null) {
101 if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
102 updateStatus(ThingStatus.ONLINE);
104 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
105 "Bridge offline for THERMOSTAT ID " + this.thermostatId);
112 * Handle the status update from the thermostat
115 public void handleCommand(ChannelUID channelUID, Command command) {
116 QbusCommunication qComm = getCommunication("Thermostat", this.thermostatId);
119 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
120 "ID for THERMOSTAT not known in controller " + this.thermostatId);
123 Map<Integer, QbusThermostat> thermostatComm = qComm.getThermostat();
125 QbusThermostat qThermostat = thermostatComm.get(this.thermostatId);
127 if (qThermostat == null) {
128 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
129 "ID for THERMOSTAT not known in controller " + this.thermostatId);
132 scheduler.submit(() -> {
133 if (!qComm.communicationActive()) {
134 restartCommunication(qComm, "Thermostat", this.thermostatId);
137 if (qComm.communicationActive()) {
138 if (command == REFRESH) {
139 handleStateUpdate(qThermostat);
143 switch (channelUID.getId()) {
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();
154 "Error on executing Mode for thermostat ID {}. Interruptedexception {} ",
155 this.thermostatId, message);
159 case CHANNEL_SETPOINT:
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();
169 "Error on executing Setpoint for thermostat ID {}. Interruptedexception {} ",
170 this.thermostatId, message);
175 thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
176 "Unknown Channel " + channelUID.getId());
185 * Executes the Mode command
190 * @throws InterruptedException
191 * @throws IOException
193 private void handleModeCommand(QbusThermostat qThermostat, Command command)
194 throws InterruptedException, IOException {
195 String snr = getSN();
197 if (command instanceof DecimalType) {
198 int mode = ((DecimalType) command).intValue();
199 qThermostat.executeMode(mode, snr);
205 * Executes the Setpoint command
210 * @throws InterruptedException
211 * @throws IOException
213 private void handleSetpointCommand(QbusThermostat qThermostat, Command command)
214 throws InterruptedException, IOException {
215 String snr = getSN();
217 if (command instanceof QuantityType<?>) {
218 QuantityType<?> s = (QuantityType<?>) command;
219 double sp = s.doubleValue();
220 QuantityType<?> spCelcius = s.toUnit(CELSIUS);
222 if (spCelcius != null) {
223 qThermostat.executeSetpoint(sp, snr);
225 logger.warn("Could not set setpoint for thermostat (conversion failed) {}", this.thermostatId);
232 * Method to update state of all channels, called from Qbus thermostat.
236 public void handleStateUpdate(QbusThermostat qThermostat) {
237 Double measured = qThermostat.getMeasured();
238 if (measured != null) {
239 updateState(CHANNEL_MEASURED, new QuantityType<>(measured, CELSIUS));
242 Double setpoint = qThermostat.getSetpoint();
243 if (setpoint != null) {
244 updateState(CHANNEL_SETPOINT, new QuantityType<>(setpoint, CELSIUS));
247 Integer mode = qThermostat.getMode();
249 updateState(CHANNEL_MODE, new DecimalType(mode));
254 * Returns the serial number of the controller
256 * @return the serial nr
258 public @Nullable String getSN() {
263 * Sets the serial number of the controller
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);
272 sn = qBridgeHandler.getSn();
276 * Read the configuration
278 protected synchronized void readConfig() {
279 thermostatConfig = getConfig().as(QbusThingsConfig.class);
283 * Returns the Id from the configuration
287 public @Nullable Integer getId() {
288 QbusThingsConfig localConfig = thermostatConfig;
289 if (localConfig != null) {
290 return localConfig.thermostatId;