2 * Copyright (c) 2010-2024 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.openwebnet.internal.handler;
15 import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.*;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
24 import org.openhab.core.library.types.DecimalType;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.core.library.unit.SIUnits;
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.thing.ThingTypeUID;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.UnDefType;
36 import org.openwebnet4j.communication.OWNException;
37 import org.openwebnet4j.message.BaseOpenMessage;
38 import org.openwebnet4j.message.FrameException;
39 import org.openwebnet4j.message.MalformedFrameException;
40 import org.openwebnet4j.message.Thermoregulation;
41 import org.openwebnet4j.message.Thermoregulation.DimThermo;
42 import org.openwebnet4j.message.Thermoregulation.Function;
43 import org.openwebnet4j.message.Thermoregulation.OperationMode;
44 import org.openwebnet4j.message.Thermoregulation.WhatThermo;
45 import org.openwebnet4j.message.Thermoregulation.WhatThermoType;
46 import org.openwebnet4j.message.Where;
47 import org.openwebnet4j.message.WhereThermo;
48 import org.openwebnet4j.message.Who;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
53 * The {@link OpenWebNetThermoregulationHandler} is responsible for handling
54 * commands/messages for Thermoregulation Things. It extends the abstract
55 * {@link OpenWebNetThingHandler}.
57 * @author Massimo Valla - Initial contribution. Added support for 4-zones CU.
58 * Rafactoring and fixed CU state channels updates. Completed support
59 * for HOLIDAY/VACATION modes and refactored mode handling.
60 * @author Gilberto Cocchi - Initial contribution.
61 * @author Andrea Conte - Added support for 99-zone CU and CU state channels.
64 public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
66 private final Logger logger = LoggerFactory.getLogger(OpenWebNetThermoregulationHandler.class);
68 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.THERMOREGULATION_SUPPORTED_THING_TYPES;
70 private double currentSetPointTemp = 20.0d;
72 private Thermoregulation.@Nullable Function currentFunction = Function.HEATING;
73 private Thermoregulation.@Nullable OperationMode currentMode = OperationMode.PROTECTION;
74 private int currentWeeklyPrgNum = 1;
75 private int currentScenarioPrgNum = 1;
76 private int currentVacationDays = 1;
78 private boolean isStandAlone = true; // true if zone is not associated to a CU
79 private boolean isCentralUnit = false;
81 private boolean cuAtLeastOneProbeOff = false;
82 private boolean cuAtLeastOneProbeProtection = false;
83 private boolean cuAtLeastOneProbeManual = false;
84 private String cuBatteryStatus = CU_BATTERY_OK;
85 private boolean cuFailureDiscovered = false;
87 private @Nullable ScheduledFuture<?> cuStateChannelsUpdateSchedule;
89 public static final int CU_STATE_CHANNELS_UPDATE_DELAY = 1500; // msec
91 private static final String CU_REMOTE_CONTROL_ENABLED = "ENABLED";
92 private static final String CU_REMOTE_CONTROL_DISABLED = "DISABLED";
93 private static final String CU_BATTERY_OK = "OK";
94 private static final String CU_BATTERY_KO = "KO";
95 private static final String MODE_WEEKLY = "WEEKLY";
97 public OpenWebNetThermoregulationHandler(Thing thing) {
102 public void initialize() {
104 ThingTypeUID thingType = thing.getThingTypeUID();
105 isCentralUnit = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU.equals(thingType);
106 if (!isCentralUnit) {
107 if (!((WhereThermo) deviceWhere).isProbe()) {
108 Object standAloneConfig = getConfig().get(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE);
109 if (standAloneConfig != null) {
110 isStandAlone = Boolean.parseBoolean(standAloneConfig.toString());
112 logger.debug("@@@@ THERMO ZONE INITIALIZE isStandAlone={}", isStandAlone);
115 // central unit must have WHERE=#0 or WHERE=0 or WHERE=#0#n
116 String w = deviceWhere.value();
117 if (w == null || !("0".equals(w) || "#0".equals(w) || w.startsWith("#0#"))) {
118 logger.warn("initialize() Invalid WHERE={} for Central Unit.", deviceWhere.value());
119 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
120 "@text/offline.conf-error-where");
127 protected void handleChannelCommand(ChannelUID channel, Command command) {
128 switch (channel.getId()) {
129 case CHANNEL_TEMP_SETPOINT:
130 handleSetpoint(command);
132 case CHANNEL_FUNCTION:
133 handleFunction(command);
138 case CHANNEL_FAN_SPEED:
139 handleSetFanSpeed(command);
141 case CHANNEL_CU_WEEKLY_PROGRAM_NUMBER:
142 case CHANNEL_CU_SCENARIO_PROGRAM_NUMBER:
143 handleSetProgramNumber(channel, command);
145 case CHANNEL_CU_VACATION_DAYS:
146 handleVacationDays(channel, command);
149 logger.warn("handleChannelCommand() Unsupported ChannelUID {}", channel.getId());
155 protected void requestChannelState(ChannelUID channel) {
156 super.requestChannelState(channel);
157 refreshDevice(false);
161 protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
162 return new WhereThermo(wStr);
166 protected String ownIdPrefix() {
167 return Who.THERMOREGULATION.value().toString();
170 private void handleSetFanSpeed(Command command) {
171 if (command instanceof StringType) {
172 Where w = deviceWhere;
174 logger.warn("handleSetFanSpeed() Where is null for thing {}", getThing().getUID());
178 Thermoregulation.FanCoilSpeed speed = Thermoregulation.FanCoilSpeed.valueOf(command.toString());
179 send(Thermoregulation.requestWriteFanCoilSpeed(w.value(), speed));
180 } catch (OWNException e) {
181 logger.warn("handleSetFanSpeed() {}", e.getMessage());
182 } catch (IllegalArgumentException e) {
183 logger.warn("handleSetFanSpeed() Unsupported command {} for thing {}", command, getThing().getUID());
187 logger.warn("handleSetFanSpeed() Unsupported command {} for thing {}", command, getThing().getUID());
191 private void handleSetProgramNumber(ChannelUID channel, Command command) {
192 if (command instanceof DecimalType) {
193 if (!isCentralUnit) {
194 logger.warn("handleSetProgramNumber() This command can be sent only for a Central Unit.");
197 Where w = deviceWhere;
199 logger.warn("handleSetProgramNumber() Where is null for thing {}", getThing().getUID());
203 int programNumber = ((DecimalType) command).intValue();
204 boolean updateOpMode = false;
206 if (CHANNEL_CU_WEEKLY_PROGRAM_NUMBER.equals(channel.getId())) {
207 if (programNumber < 1 || programNumber > 3) {
208 logger.warn("handleSetProgramNumber() Invalid program number {} for thing {}", command,
209 getThing().getUID());
212 updateOpMode = (currentMode == Thermoregulation.OperationMode.WEEKLY);
213 currentWeeklyPrgNum = programNumber;
214 logger.debug("handleSetProgramNumber() currentWeeklyPrgNum changed to: {}", programNumber);
216 if (programNumber < 1 || programNumber > 16) {
217 logger.warn("handleSetProgramNumber() Invalid program number {} for thing {}", command,
218 getThing().getUID());
221 updateOpMode = (currentMode == Thermoregulation.OperationMode.SCENARIO);
222 currentScenarioPrgNum = programNumber;
223 logger.debug("handleSetProgramNumber() currentScenarioPrgNum changed to: {}", programNumber);
226 // force OperationMode update if we are already in SCENARIO or WEEKLY mode
229 send(Thermoregulation.requestWriteWeeklyScenarioMode(getWhere(w.value()), currentMode,
230 currentFunction, programNumber));
231 } catch (OWNException e) {
232 logger.warn("handleSetProgramNumber() {}", e.getMessage());
234 } else { // just update channel
235 updateState(channel, new DecimalType(programNumber));
238 logger.warn("handleSetProgramNumber() Unsupported command {} for thing {}", command, getThing().getUID());
242 private void handleVacationDays(ChannelUID channel, Command command) {
243 if (command instanceof DecimalType) {
244 Where w = deviceWhere;
246 logger.warn("handleVacationDays() Where is null for thing {}", getThing().getUID());
249 if (!isCentralUnit) {
250 logger.warn("handleVacationDays() This command can be sent only for a Central Unit.");
253 int vacationDays = ((DecimalType) command).intValue();
255 if (vacationDays < 1 || vacationDays > 255) {
256 logger.warn("handleVacationDays() vacation days must be between 1 and 255");
260 currentVacationDays = vacationDays;
261 logger.debug("handleVacationDays() currentVacationDays changed to: {}", currentVacationDays);
263 // force OperationMode update if we are already in VACATION mode
264 if (currentMode == Thermoregulation.OperationMode.VACATION) {
266 send(Thermoregulation.requestWriteVacationMode(getWhere(w.value()), currentFunction,
267 currentVacationDays, currentWeeklyPrgNum));
268 } catch (OWNException e) {
269 logger.warn("handleVacationDays() {}", e.getMessage());
270 } catch (IllegalArgumentException e) {
271 logger.warn("handleVacationDays() Unsupported command {} for thing {}", command,
272 getThing().getUID());
274 } else { // just update channel
275 updateState(channel, new DecimalType(currentVacationDays));
278 logger.warn("handleVacationDays() Unsupported command {} for thing {}", command, getThing().getUID());
282 private void handleSetpoint(Command command) {
283 if (command instanceof QuantityType || command instanceof DecimalType) {
284 Where w = deviceWhere;
286 logger.warn("handleSetpoint() Where is null for thing {}", getThing().getUID());
290 if (command instanceof QuantityType) {
291 QuantityType<?> tempCelsius = ((QuantityType<?>) command).toUnit(SIUnits.CELSIUS);
292 if (tempCelsius != null) {
293 newTemp = tempCelsius.doubleValue();
296 newTemp = ((DecimalType) command).doubleValue();
299 send(Thermoregulation.requestWriteSetpointTemperature(getWhere(w.value()), newTemp, currentFunction));
300 } catch (MalformedFrameException | OWNException e) {
301 logger.warn("handleSetpoint() {}", e.getMessage());
304 logger.warn("handleSetpoint() Unsupported command {} for thing {}", command, getThing().getUID());
308 private void handleMode(Command command) {
309 if (command instanceof StringType) {
310 Where w = deviceWhere;
312 logger.warn("handleMode() Where is null for thing {}", getThing().getUID());
316 String whStr = getWhere(w.value());
317 String cmdStr = command.toString().toUpperCase();
318 OperationMode newMode;
320 newMode = OperationMode.valueOf(cmdStr);
321 } catch (IllegalArgumentException e) {
322 logger.warn("handleMode() Unsupported command {} for thing {}", command, getThing().getUID());
325 Thermoregulation tMsg = null;
326 if (isCentralUnit) { // CU accepted modes: MANUAL, OFF, PROTECTION, WEEKLY, SCENARIO, HOLIDAY,
332 tMsg = Thermoregulation.requestWriteMode(whStr, newMode, currentFunction, currentSetPointTemp);
336 int programNumber = (MODE_WEEKLY.equals(cmdStr) ? currentWeeklyPrgNum : currentScenarioPrgNum);
337 tMsg = Thermoregulation.requestWriteWeeklyScenarioMode(whStr, newMode, currentFunction,
341 tMsg = Thermoregulation.requestWriteHolidayMode(whStr, currentFunction, currentWeeklyPrgNum);
344 tMsg = Thermoregulation.requestWriteVacationMode(whStr, currentFunction, currentVacationDays,
345 currentWeeklyPrgNum);
348 logger.warn("handleMode() Unsupported command {} for CU thing {}", command,
349 getThing().getUID());
351 } else {// Zone accepted modes: MANUAL, OFF, PROTECTION, AUTO
354 tMsg = Thermoregulation.requestWriteMode(whStr, newMode, currentFunction, currentSetPointTemp);
359 tMsg = Thermoregulation.requestWriteMode(whStr, newMode, Function.GENERIC, currentSetPointTemp);
362 logger.warn("handleMode() Unsupported command {} for ZONE thing {}", command,
363 getThing().getUID());
370 } catch (OWNException e) {
371 logger.warn("handleMode() {}", e.getMessage());
374 logger.warn("handleMode() Unsupported command {} for thing {}", command, getThing().getUID());
379 private String getWhere(String where) {
381 if (where.charAt(0) == '#') {
383 } else { // to support old configurations for CU with where="0"
387 return isStandAlone ? where : "#" + where;
391 private void handleFunction(Command command) {
392 if (command instanceof StringType) {
393 Where w = deviceWhere;
395 logger.warn("handleFunction() Where is null for thing {}", getThing().getUID());
399 Thermoregulation.Function function = Thermoregulation.Function.valueOf(command.toString());
400 send(Thermoregulation.requestWriteFunction(w.value(), function));
401 } catch (OWNException e) {
402 logger.warn("handleFunction() {}", e.getMessage());
403 } catch (IllegalArgumentException e) {
404 logger.warn("handleFunction() Unsupported command {} for thing {}", command, getThing().getUID());
408 logger.warn("handleFunction() Unsupported command {} for thing {}", command, getThing().getUID());
413 protected void handleMessage(BaseOpenMessage msg) {
414 super.handleMessage(msg);
415 logger.debug("@@@@ Thermo.handleMessage(): {}", msg.toStringVerbose());
416 Thermoregulation tmsg = (Thermoregulation) msg;
418 WhatThermo tWhat = (WhatThermo) msg.getWhat();
420 logger.debug("handleMessage() Ignoring unsupported WHAT {}. Frame={}", tWhat, msg);
423 if (tWhat.value() > 40) {
424 // it's a CU mode event, CU state events will follow shortly, so let's reset
428 switch (tWhat.getType()) {
429 case AT_LEAST_ONE_PROBE_ANTIFREEZE:
430 cuAtLeastOneProbeProtection = true;
432 case AT_LEAST_ONE_PROBE_MANUAL:
433 cuAtLeastOneProbeManual = true;
435 case AT_LEAST_ONE_PROBE_OFF:
436 cuAtLeastOneProbeOff = true;
439 cuBatteryStatus = CU_BATTERY_KO;
441 case FAILURE_DISCOVERED:
442 cuFailureDiscovered = true;
444 case RELEASE_SENSOR_LOCAL_ADJUST:
445 logger.debug("handleMessage(): Ignoring unsupported WHAT {}. Frame={}", tWhat, msg);
447 case REMOTE_CONTROL_DISABLED:
448 updateCURemoteControlStatus(CU_REMOTE_CONTROL_DISABLED);
450 case REMOTE_CONTROL_ENABLED:
451 updateCURemoteControlStatus(CU_REMOTE_CONTROL_ENABLED);
454 // check and update values of other channels (mode, function, temp)
455 updateModeAndFunction(tmsg);
456 updateSetpoint(tmsg);
462 if (tmsg.isCommand()) {
463 updateModeAndFunction(tmsg);
465 DimThermo dim = (DimThermo) tmsg.getDim();
468 case COMPLETE_PROBE_STATUS:
469 updateSetpoint(tmsg);
471 case PROBE_TEMPERATURE:
473 updateTemperature(tmsg);
475 case ACTUATOR_STATUS:
476 updateActuatorStatus(tmsg);
479 updateFanCoilSpeed(tmsg);
482 updateLocalOffset(tmsg);
485 updateValveStatus(tmsg);
488 logger.debug("handleMessage() Ignoring unsupported DIM {} for thing {}. Frame={}", tmsg.getDim(),
489 getThing().getUID(), tmsg);
495 private void updateModeAndFunction(Thermoregulation tmsg) {
496 if (tmsg.getWhat() == null) {
497 logger.warn("updateModeAndFunction() Could not parse What {} (WHAT is null)", tmsg.getFrameValue());
500 Thermoregulation.WhatThermo what = tmsg.new WhatThermo(tmsg.getWhat().value());
501 if (what.getMode() == null) {
502 logger.warn("updateModeAndFunction() Could not parse Mode from: {}", tmsg.getFrameValue());
505 if (what.getFunction() == null) {
506 logger.warn("updateModeAndFunction() Could not parse Function from: {}", tmsg.getFrameValue());
510 // update Function if it's not GENERIC
511 Thermoregulation.Function function = what.getFunction();
512 if (function != Function.GENERIC) {
513 updateState(CHANNEL_FUNCTION, new StringType(function.toString()));
514 currentFunction = function;
518 Thermoregulation.OperationMode operationMode = null;
519 if (what.getType() != WhatThermoType.HEATING && what.getType() != WhatThermoType.CONDITIONING) {
520 // *4*1*z## and *4*0*z## do not tell us which mode is the zone now
521 operationMode = what.getMode();
524 // set ProgramNumber/vacationDays channels when necessary
525 if (operationMode != null) {
526 switch (operationMode) {
528 updateVacationDays(tmsg);
532 updateProgramNumber(tmsg);
537 if (!isCentralUnit && !(operationMode == OperationMode.AUTO || operationMode == OperationMode.OFF
538 || operationMode == OperationMode.PROTECTION || operationMode == OperationMode.MANUAL)) {
539 logger.warn("updateModeAndFunction() Unsupported mode for zone {} from message: {}",
540 getThing().getUID(), tmsg.getFrameValue());
543 updateState(CHANNEL_MODE, new StringType(operationMode.name()));
544 currentMode = operationMode;
547 logger.debug("updateModeAndFunction() Unrecognized mode from message: {}", tmsg.getFrameValue());
551 private void updateVacationDays(Thermoregulation tmsg) {
553 Integer vDays = ((WhatThermo) tmsg.getWhat()).vacationDays();
555 logger.debug("{} - updateVacationDays() set VACATION DAYS to: {}", getThing().getUID(), vDays);
556 updateState(CHANNEL_CU_VACATION_DAYS, new DecimalType(vDays));
557 currentVacationDays = vDays;
561 private void updateProgramNumber(Thermoregulation tmsg) {
563 WhatThermo wt = (WhatThermo) tmsg.getWhat();
567 Integer prNum = wt.programNumber();
569 if (wt.getMode() == OperationMode.SCENARIO) {
570 logger.debug("{} - updateProgramNumber() set SCENARIO program to: {}", getThing().getUID(), prNum);
571 updateState(CHANNEL_CU_SCENARIO_PROGRAM_NUMBER, new DecimalType(prNum));
572 currentScenarioPrgNum = prNum;
573 } else if (wt.getMode() == OperationMode.WEEKLY) {
574 logger.debug("{} - updateProgramNumber() set WEEKLY program to: {}", getThing().getUID(), prNum);
575 updateState(CHANNEL_CU_WEEKLY_PROGRAM_NUMBER, new DecimalType(prNum));
576 currentWeeklyPrgNum = prNum;
581 private void updateTemperature(Thermoregulation tmsg) {
583 double temp = Thermoregulation.parseTemperature(tmsg);
584 updateState(CHANNEL_TEMPERATURE, getAsQuantityTypeOrNull(temp, SIUnits.CELSIUS));
585 } catch (FrameException e) {
586 logger.warn("updateTemperature() FrameException on frame {}: {}", tmsg, e.getMessage());
587 updateState(CHANNEL_TEMPERATURE, UnDefType.UNDEF);
591 private void updateSetpoint(Thermoregulation tmsg) {
595 WhatThermo tw = (WhatThermo) tmsg.getWhat();
597 logger.warn("updateSetpoint() Could not parse what from {} (what is null)", tmsg.getFrameValue());
600 String[] parameters = tmsg.getWhatParams();
601 if (parameters.length > 0 && tw.getType() == WhatThermoType.MANUAL) {
602 // it should be like *4*110#TTTT*#0##
603 newTemp = Thermoregulation.decodeTemperature(parameters[0]);
604 logger.debug("updateSetpoint() parsed temperature from {}: {} ---> {}", tmsg.toStringVerbose(),
605 parameters[0], newTemp);
608 newTemp = Thermoregulation.parseTemperature(tmsg);
611 updateState(CHANNEL_TEMP_SETPOINT, getAsQuantityTypeOrNull(newTemp, SIUnits.CELSIUS));
612 currentSetPointTemp = newTemp;
614 } catch (NumberFormatException e) {
615 logger.warn("updateSetpoint() NumberFormatException on frame {}: {}", tmsg, e.getMessage());
616 updateState(CHANNEL_TEMP_SETPOINT, UnDefType.UNDEF);
617 } catch (FrameException e) {
618 logger.warn("updateSetpoint() FrameException on frame {}: {}", tmsg, e.getMessage());
619 updateState(CHANNEL_TEMP_SETPOINT, UnDefType.UNDEF);
623 private void updateFanCoilSpeed(Thermoregulation tmsg) {
625 Thermoregulation.FanCoilSpeed speed = Thermoregulation.parseFanCoilSpeed(tmsg);
626 updateState(CHANNEL_FAN_SPEED, new StringType(speed.toString()));
627 } catch (NumberFormatException e) {
628 logger.warn("updateFanCoilSpeed() NumberFormatException on frame {}: {}", tmsg, e.getMessage());
629 updateState(CHANNEL_FAN_SPEED, UnDefType.UNDEF);
630 } catch (FrameException e) {
631 logger.warn("updateFanCoilSpeed() FrameException on frame {}: {}", tmsg, e.getMessage());
632 updateState(CHANNEL_FAN_SPEED, UnDefType.UNDEF);
636 private void updateValveStatus(Thermoregulation tmsg) {
638 Thermoregulation.ValveOrActuatorStatus cv = Thermoregulation.parseValveStatus(tmsg,
639 Thermoregulation.WhatThermoType.CONDITIONING);
640 updateState(CHANNEL_CONDITIONING_VALVES, new StringType(cv.toString()));
642 Thermoregulation.ValveOrActuatorStatus hv = Thermoregulation.parseValveStatus(tmsg,
643 Thermoregulation.WhatThermoType.HEATING);
644 updateState(CHANNEL_HEATING_VALVES, new StringType(hv.toString()));
645 } catch (FrameException e) {
646 logger.warn("updateValveStatus() FrameException on frame {}: {}", tmsg, e.getMessage());
647 updateState(CHANNEL_CONDITIONING_VALVES, UnDefType.UNDEF);
648 updateState(CHANNEL_HEATING_VALVES, UnDefType.UNDEF);
652 private void updateActuatorStatus(Thermoregulation tmsg) {
654 Thermoregulation.ValveOrActuatorStatus hv = Thermoregulation.parseActuatorStatus(tmsg);
655 updateState(CHANNEL_ACTUATORS, new StringType(hv.toString()));
656 } catch (FrameException e) {
657 logger.warn("updateActuatorStatus() FrameException on frame {}: {}", tmsg, e.getMessage());
658 updateState(CHANNEL_ACTUATORS, UnDefType.UNDEF);
662 private void updateLocalOffset(Thermoregulation tmsg) {
664 Thermoregulation.LocalOffset offset = Thermoregulation.parseLocalOffset(tmsg);
665 updateState(CHANNEL_LOCAL_OFFSET, new StringType(offset.toString()));
666 logger.debug("updateLocalOffset() {}: {}", tmsg, offset.toString());
668 } catch (FrameException e) {
669 logger.warn("updateLocalOffset() FrameException on frame {}: {}", tmsg, e.getMessage());
670 updateState(CHANNEL_LOCAL_OFFSET, UnDefType.UNDEF);
674 private void updateCURemoteControlStatus(String status) {
675 updateState(CHANNEL_CU_REMOTE_CONTROL, new StringType(status));
676 logger.debug("updateCURemoteControlStatus(): {}", status);
679 private void resetCUState() {
680 logger.debug("########### resetting CU state");
681 cuAtLeastOneProbeOff = false;
682 cuAtLeastOneProbeProtection = false;
683 cuAtLeastOneProbeManual = false;
684 cuBatteryStatus = CU_BATTERY_OK;
685 cuFailureDiscovered = false;
687 cuStateChannelsUpdateSchedule = scheduler.schedule(() -> {
688 updateCUStateChannels();
689 }, CU_STATE_CHANNELS_UPDATE_DELAY, TimeUnit.MILLISECONDS);
692 private void updateCUStateChannels() {
693 updateState(CHANNEL_CU_AT_LEAST_ONE_PROBE_OFF, OnOffType.from(cuAtLeastOneProbeOff));
694 updateState(CHANNEL_CU_AT_LEAST_ONE_PROBE_PROTECTION, OnOffType.from(cuAtLeastOneProbeProtection));
695 updateState(CHANNEL_CU_AT_LEAST_ONE_PROBE_MANUAL, OnOffType.from(cuAtLeastOneProbeManual));
696 updateState(CHANNEL_CU_BATTERY_STATUS, new StringType(cuBatteryStatus));
697 updateState(CHANNEL_CU_FAILURE_DISCOVERED, OnOffType.from(cuFailureDiscovered));
700 private Boolean channelExists(String channelID) {
701 return thing.getChannel(channelID) != null;
705 protected void refreshDevice(boolean refreshAll) {
706 logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
708 Where w = deviceWhere;
710 logger.warn("refreshDevice() Where is null for thing {}", getThing().getUID());
714 String whereStr = w.value();
718 send(Thermoregulation.requestStatus(getWhere(whereStr)));
719 } catch (OWNException e) {
720 logger.warn("refreshDevice() central unit returned OWNException {}", e.getMessage());
726 send(Thermoregulation.requestTemperature(whereStr));
728 if (!((WhereThermo) w).isProbe()) {
729 // for bus_thermo_zone request also other single channels updates
730 send(Thermoregulation.requestSetPointTemperature(whereStr));
731 send(Thermoregulation.requestMode(whereStr));
733 // refresh ONLY subscribed channels
734 if (channelExists(CHANNEL_FAN_SPEED)) {
735 send(Thermoregulation.requestFanCoilSpeed(whereStr));
737 if (channelExists(CHANNEL_CONDITIONING_VALVES) || channelExists(CHANNEL_HEATING_VALVES)) {
738 send(Thermoregulation.requestValvesStatus(whereStr));
740 if (channelExists(CHANNEL_ACTUATORS)) {
741 send(Thermoregulation.requestActuatorsStatus(whereStr));
743 if (channelExists(CHANNEL_LOCAL_OFFSET)) {
744 send(Thermoregulation.requestLocalOffset(whereStr));
747 } catch (OWNException e) {
748 logger.warn("refreshDevice() where='{}' returned OWNException {}", whereStr, e.getMessage());
753 public void dispose() {
754 ScheduledFuture<?> s = cuStateChannelsUpdateSchedule;
757 logger.debug("dispose() - scheduler stopped.");