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.draytonwiser.internal.handler;
15 import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
17 import javax.measure.quantity.Time;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
22 import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
23 import org.openhab.binding.draytonwiser.internal.model.RoomDTO;
24 import org.openhab.binding.draytonwiser.internal.model.RoomStatDTO;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.OpenClosedType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.library.unit.SIUnits;
30 import org.openhab.core.library.unit.Units;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.State;
34 import org.openhab.core.types.UnDefType;
37 * The {@link RoomHandler} is responsible for handling commands, which are
38 * sent to one of the channels.
40 * @author Andrew Schofield - Initial contribution
41 * @author Hilbrand Bouwkamp - Simplified handler to handle null data
44 public class RoomHandler extends DraytonWiserThingHandler<RoomDTO> {
46 private String name = "";
48 public RoomHandler(final Thing thing) {
53 public void initialize() {
55 name = (String) getConfig().get("name");
59 protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
61 case CHANNEL_CURRENT_SETPOINT:
62 if (command instanceof QuantityType quantityCommand) {
63 setSetPoint(quantityCommand);
66 case CHANNEL_MANUAL_MODE_STATE:
67 if (command instanceof OnOffType) {
68 setManualMode(OnOffType.ON.equals(command));
71 case CHANNEL_ROOM_BOOST_DURATION:
72 if (command instanceof DecimalType decimalCommand) {
73 setBoostDuration(Math.round((decimalCommand.floatValue() * 60)));
76 case CHANNEL_ROOM_WINDOW_STATE_DETECTION:
77 if (command instanceof OnOffType) {
78 setWindowStateDetection(OnOffType.ON.equals(command));
85 protected void refresh() {
86 updateState(CHANNEL_CURRENT_TEMPERATURE, this::getTemperature);
87 updateState(CHANNEL_CURRENT_HUMIDITY, this::getHumidity);
88 updateState(CHANNEL_CURRENT_SETPOINT, this::getSetPoint);
89 updateState(CHANNEL_CURRENT_DEMAND, this::getDemand);
90 updateState(CHANNEL_HEAT_REQUEST, this::getHeatRequest);
91 updateState(CHANNEL_MANUAL_MODE_STATE, this::getManualModeState);
92 updateState(CHANNEL_ROOM_BOOSTED, this::getBoostedState);
93 updateState(CHANNEL_ROOM_BOOST_REMAINING, this::getBoostRemainingState);
94 updateState(CHANNEL_ROOM_WINDOW_STATE_DETECTION, this::getWindowDetectionState);
95 updateState(CHANNEL_ROOM_WINDOW_STATE, this::getWindowState);
99 protected @Nullable RoomDTO collectData(final DraytonWiserDTO domainDTOProxy) {
100 return domainDTOProxy.getRoomByName(name);
103 private State getSetPoint() {
104 return new QuantityType<>(getData().getCurrentSetPoint() / 10.0, SIUnits.CELSIUS);
107 private void setSetPoint(final QuantityType<?> command) throws DraytonWiserApiException {
108 if (getData().getId() != null) {
109 final QuantityType<?> value = command.toUnit(SIUnits.CELSIUS);
112 final int newSetPoint = (int) Math.round(value.doubleValue() * 10);
114 getApi().setRoomSetPoint(getData().getId(), newSetPoint);
119 private State getHumidity() {
120 if (getData().getId() != null && getData().getRoomStatId() != null) {
121 final RoomStatDTO roomStat = getDraytonWiserDTO().getRoomStat(getData().getRoomStatId());
123 if (roomStat != null) {
124 final Integer humidity = roomStat.getMeasuredHumidity();
126 return humidity == null ? UnDefType.UNDEF : new QuantityType<>(humidity, Units.PERCENT);
129 return UnDefType.UNDEF;
132 private State getTemperature() {
133 final int fullScaleTemp = getData().getCalculatedTemperature();
135 return OFFLINE_TEMPERATURE == fullScaleTemp ? UnDefType.UNDEF
136 : new QuantityType<>(fullScaleTemp / 10.0, SIUnits.CELSIUS);
139 private State getDemand() {
140 return new QuantityType<>(getData().getPercentageDemand(), Units.PERCENT);
143 private State getHeatRequest() {
144 return OnOffType.from(getData().getControlOutputState());
147 private State getManualModeState() {
148 return OnOffType.from("MANUAL".equalsIgnoreCase(getData().getMode()));
151 private void setManualMode(final boolean manualMode) throws DraytonWiserApiException {
152 getApi().setRoomManualMode(getData().getId(), manualMode);
155 private void setWindowStateDetection(final boolean stateDetection) throws DraytonWiserApiException {
156 getApi().setRoomWindowStateDetection(getData().getId(), stateDetection);
159 private State getBoostedState() {
160 if (getData().getOverrideTimeoutUnixTime() != null && !"NONE".equalsIgnoreCase(getData().getOverrideType())) {
163 updateState(CHANNEL_ROOM_BOOST_DURATION, DecimalType.ZERO);
164 return OnOffType.OFF;
167 private State getBoostRemainingState() {
168 final Integer overrideTimeout = getData().getOverrideTimeoutUnixTime();
169 if (overrideTimeout != null && !"NONE".equalsIgnoreCase(getData().getOverrideType())) {
170 return new QuantityType<Time>(overrideTimeout - (System.currentTimeMillis() / 1000L), Units.SECOND);
172 return new QuantityType<Time>(0, Units.SECOND);
175 private void setBoostDuration(final int durationMinutes) throws DraytonWiserApiException {
176 if (durationMinutes > 0) {
177 getApi().setRoomBoostActive(getData().getId(), getData().getCalculatedTemperature() + 20, durationMinutes);
179 getApi().setRoomBoostInactive(getData().getId());
183 private State getWindowDetectionState() {
184 return OnOffType.from(getData().getWindowDetectionActive());
187 private State getWindowState() {
188 if (getData().getWindowState() != null && "OPEN".equalsIgnoreCase(getData().getWindowState())) {
189 return OpenClosedType.OPEN;
191 return OpenClosedType.CLOSED;