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.plugwiseha.internal.handler;
15 import static org.openhab.binding.plugwiseha.internal.PlugwiseHABindingConstants.*;
16 import static org.openhab.core.thing.ThingStatus.*;
17 import static org.openhab.core.thing.ThingStatusDetail.BRIDGE_OFFLINE;
18 import static org.openhab.core.thing.ThingStatusDetail.COMMUNICATION_ERROR;
19 import static org.openhab.core.thing.ThingStatusDetail.CONFIGURATION_ERROR;
22 import java.util.Optional;
24 import javax.measure.Unit;
25 import javax.measure.quantity.Temperature;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.plugwiseha.internal.PlugwiseHABindingConstants;
30 import org.openhab.binding.plugwiseha.internal.api.exception.PlugwiseHAException;
31 import org.openhab.binding.plugwiseha.internal.api.model.PlugwiseHAController;
32 import org.openhab.binding.plugwiseha.internal.api.model.dto.Location;
33 import org.openhab.binding.plugwiseha.internal.config.PlugwiseHAThingConfig;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.library.types.QuantityType;
36 import org.openhab.core.library.types.StringType;
37 import org.openhab.core.library.unit.ImperialUnits;
38 import org.openhab.core.library.unit.SIUnits;
39 import org.openhab.core.thing.ChannelUID;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingTypeUID;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.types.State;
44 import org.openhab.core.types.UnDefType;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
49 * The {@link PlugwiseHAZoneHandler} class is responsible for handling commands
50 * and status updates for the Plugwise Home Automation zones/locations.
51 * Extends @{link PlugwiseHABaseHandler}
53 * @author Bas van Wetten - Initial contribution
54 * @author Leo Siepel - finish initial contribution
59 public class PlugwiseHAZoneHandler extends PlugwiseHABaseHandler<Location, PlugwiseHAThingConfig> {
61 private @Nullable Location location;
62 private final Logger logger = LoggerFactory.getLogger(PlugwiseHAZoneHandler.class);
66 public PlugwiseHAZoneHandler(Thing thing) {
70 public static boolean supportsThingType(ThingTypeUID thingTypeUID) {
71 return PlugwiseHABindingConstants.THING_TYPE_ZONE.equals(thingTypeUID);
77 protected synchronized void initialize(PlugwiseHAThingConfig config, PlugwiseHABridgeHandler bridgeHandler) {
78 if (thing.getStatus() == INITIALIZING) {
79 logger.debug("Initializing Plugwise Home Automation zone handler with config = {}", config);
80 if (!config.isValid()) {
81 updateStatus(OFFLINE, CONFIGURATION_ERROR,
82 "Invalid configuration for Plugwise Home Automation zone handler.");
87 PlugwiseHAController controller = bridgeHandler.getController();
88 if (controller != null) {
89 this.location = getEntity(controller);
90 if (this.location != null) {
91 setLocationProperties();
94 updateStatus(OFFLINE);
97 updateStatus(OFFLINE, BRIDGE_OFFLINE);
99 } catch (PlugwiseHAException e) {
100 updateStatus(OFFLINE, COMMUNICATION_ERROR, e.getMessage());
106 protected @Nullable Location getEntity(PlugwiseHAController controller) throws PlugwiseHAException {
107 PlugwiseHAThingConfig config = getPlugwiseThingConfig();
108 Location location = controller.getLocation(config.getId());
114 protected void handleCommand(Location entity, ChannelUID channelUID, Command command) throws PlugwiseHAException {
115 String channelID = channelUID.getIdWithoutGroup();
116 PlugwiseHABridgeHandler bridge = this.getPlugwiseHABridge();
117 if (bridge != null) {
118 PlugwiseHAController controller = bridge.getController();
119 if (controller != null) {
121 case ZONE_COOLING_CHANNEL:
122 if (command instanceof OnOffType) {
124 controller.setAllowCooling(entity, command == OnOffType.ON);
125 } catch (PlugwiseHAException e) {
126 logger.warn("Unable to switch allow cooling {} for zone '{}'", (State) command,
131 case ZONE_SETPOINT_CHANNEL:
132 if (command instanceof QuantityType) {
133 Unit<Temperature> unit = entity.getSetpointTemperatureUnit().orElse(UNIT_CELSIUS)
134 .equals(UNIT_CELSIUS) ? SIUnits.CELSIUS : ImperialUnits.FAHRENHEIT;
135 QuantityType<?> state = ((QuantityType<?>) command).toUnit(unit);
138 controller.setLocationThermostat(entity, state.doubleValue());
139 } catch (PlugwiseHAException e) {
140 logger.warn("Unable to update setpoint for zone '{}': {} -> {}", entity.getName(),
141 entity.getSetpointTemperature().orElse(null), state.doubleValue());
146 case ZONE_PREHEAT_CHANNEL:
147 if (command instanceof OnOffType) {
149 controller.setPreHeating(entity, command == OnOffType.ON);
150 } catch (PlugwiseHAException e) {
151 logger.warn("Unable to switch zone pre heating {} for zone '{}'", (State) command,
156 case ZONE_REGULATION_CHANNEL:
157 if (command instanceof StringType) {
159 controller.setRegulationControl(entity, command.toString());
160 } catch (PlugwiseHAException e) {
161 logger.warn("Unable to switch regulation control {} for zone '{}'", (State) command,
166 case ZONE_PRESETSCENE_CHANNEL:
167 if (command instanceof StringType) {
169 controller.setPresetScene(entity, command.toString());
170 } catch (PlugwiseHAException e) {
171 logger.warn("Unable to switch preset scene {} for zone '{}'", (State) command,
177 logger.warn("Ignoring unsupported command = {} for channel = {}", command, channelUID);
183 private State getDefaultState(String channelID) {
184 State state = UnDefType.NULL;
186 case ZONE_COOLING_CHANNEL:
187 case ZONE_PREHEAT_CHANNEL:
188 case ZONE_PRESETSCENE_CHANNEL:
189 case ZONE_REGULATION_CHANNEL:
190 case ZONE_SETPOINT_CHANNEL:
191 case ZONE_TEMPERATURE_CHANNEL:
192 state = UnDefType.NULL;
199 protected void refreshChannel(Location entity, ChannelUID channelUID) {
200 String channelID = channelUID.getIdWithoutGroup();
201 State state = getDefaultState(channelID);
204 case ZONE_COOLING_CHANNEL:
205 Optional<Boolean> allowCoolingState = entity.getCoolingAllowed();
206 if (allowCoolingState.isPresent()) {
207 state = OnOffType.from(allowCoolingState.get());
210 case ZONE_PREHEAT_CHANNEL:
211 Optional<Boolean> preHeatState = entity.getPreHeatState();
212 if (preHeatState.isPresent()) {
213 state = OnOffType.from(preHeatState.get());
216 case ZONE_PRESETSCENE_CHANNEL:
217 state = new StringType(entity.getPreset());
219 case ZONE_SETPOINT_CHANNEL:
220 if (entity.getSetpointTemperature().isPresent()) {
221 Unit<Temperature> unit = entity.getSetpointTemperatureUnit().orElse(UNIT_CELSIUS)
222 .equals(UNIT_CELSIUS) ? SIUnits.CELSIUS : ImperialUnits.FAHRENHEIT;
223 state = new QuantityType<Temperature>(entity.getSetpointTemperature().get(), unit);
226 case ZONE_REGULATION_CHANNEL:
227 String value = entity.getRegulationControl();
229 state = new StringType(entity.getRegulationControl());
232 case ZONE_TEMPERATURE_CHANNEL:
233 if (entity.getTemperature().isPresent()) {
234 Unit<Temperature> unit = entity.getTemperatureUnit().orElse(UNIT_CELSIUS).equals(UNIT_CELSIUS)
236 : ImperialUnits.FAHRENHEIT;
237 state = new QuantityType<Temperature>(entity.getTemperature().get(), unit);
244 if (state != UnDefType.NULL) {
245 updateState(channelID, state);
249 protected void setLocationProperties() {
250 if (this.location != null) {
251 Map<String, String> properties = editProperties();
253 Location localLocation = this.location;
254 if (localLocation != null) {
255 properties.put(PlugwiseHABindingConstants.LOCATION_PROPERTY_DESCRIPTION,
256 localLocation.getDescription());
257 properties.put(PlugwiseHABindingConstants.LOCATION_PROPERTY_TYPE, localLocation.getType());
258 properties.put(PlugwiseHABindingConstants.LOCATION_PROPERTY_FUNCTIONALITIES,
259 String.join(", ", localLocation.getActuatorFunctionalities().keySet()));
262 updateProperties(properties);