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.velux.internal.handler;
16 import java.util.Map.Entry;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.openhab.binding.velux.internal.VeluxBindingConstants;
20 import org.openhab.binding.velux.internal.handler.utils.ExtendedBaseThingHandler;
21 import org.openhab.binding.velux.internal.handler.utils.Thing2VeluxActuator;
22 import org.openhab.binding.velux.internal.things.VeluxProduct;
23 import org.openhab.binding.velux.internal.utils.Localization;
24 import org.openhab.core.config.core.Configuration;
25 import org.openhab.core.thing.Bridge;
26 import org.openhab.core.thing.Channel;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BridgeHandler;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * The{@link VeluxHandler} is responsible for handling commands, which are
39 * sent via {@link VeluxBridgeHandler} to one of the channels.
41 * @author Guenther Schreiner - Initial contribution
44 public class VeluxHandler extends ExtendedBaseThingHandler {
45 private final Logger logger = LoggerFactory.getLogger(VeluxHandler.class);
47 public VeluxHandler(Thing thing, Localization localization) {
49 logger.trace("VeluxHandler(thing={},localization={}) constructor called.", thing, localization);
53 public void initialize() {
54 logger.trace("initialize() called.");
55 Bridge thisBridge = getBridge();
56 logger.debug("initialize(): Initializing thing {} in combination with bridge {}.", getThing().getUID(),
58 if (thisBridge == null) {
59 logger.trace("initialize() updating ThingStatus to OFFLINE/CONFIGURATION_PENDING.");
60 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING);
62 } else if (thisBridge.getStatus() == ThingStatus.ONLINE) {
63 logger.trace("initialize() updating ThingStatus to ONLINE.");
64 updateStatus(ThingStatus.ONLINE);
65 initializeProperties();
67 logger.trace("initialize() updating ThingStatus to OFFLINE/BRIDGE_OFFLINE.");
68 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
70 logger.trace("initialize() done.");
73 private synchronized void initializeProperties() {
74 logger.trace("initializeProperties() done.");
78 public void dispose() {
79 logger.trace("dispose() called.");
84 public void channelLinked(ChannelUID channelUID) {
85 logger.trace("channelLinked({}) called.", channelUID.getAsString());
87 if (thing.getStatus() == ThingStatus.ONLINE) {
88 handleCommand(channelUID, RefreshType.REFRESH);
93 public void handleCommand(ChannelUID channelUID, Command command) {
94 logger.trace("handleCommand({},{}) initiated by {}.", channelUID.getAsString(), command,
95 Thread.currentThread());
96 Bridge bridge = getBridge();
98 logger.trace("handleCommand() nothing yet to do as there is no bridge available.");
100 BridgeHandler handler = bridge.getHandler();
101 if (handler == null) {
102 logger.trace("handleCommand() nothing yet to do as thing is not initialized.");
104 handler.handleCommand(channelUID, command);
107 logger.trace("handleCommand() done.");
111 public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
112 if (isInitialized()) { // prevents change of address
113 validateConfigurationParameters(configurationParameters);
114 Configuration configuration = editConfiguration();
115 for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
116 logger.trace("handleConfigurationUpdate(): found modified config entry {}.",
117 configurationParameter.getKey());
118 configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
120 // persist new configuration and reinitialize handler
122 updateConfiguration(configuration);
125 super.handleConfigurationUpdate(configurationParameters);
130 * Remove previously statically created vane channel if the device does not support it. Or log a warning if it does
131 * support a vane and the respective channel is missing.
133 * @param bridgeHandler the calling bridge handler.
134 * @throws IllegalStateException if something went wrong.
136 public void updateDynamicChannels(VeluxBridgeHandler bridgeHandler) throws IllegalStateException {
137 // roller shutters are the only things with a previously statically created vane channel
138 if (!VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER.equals(thing.getThingTypeUID())) {
142 String id = VeluxBindingConstants.CHANNEL_VANE_POSITION;
143 ChannelUID uid = new ChannelUID(thing.getUID(), id);
144 Thing2VeluxActuator actuator = new Thing2VeluxActuator(bridgeHandler, uid);
145 VeluxProduct product = bridgeHandler.existingProducts().get(actuator.getProductBridgeIndex());
147 if (product.equals(VeluxProduct.UNKNOWN)) {
148 throw new IllegalStateException("updateDynamicChannels(): Product unknown in the bridge");
151 Channel channel = thing.getChannel(id);
152 boolean required = product.supportsVanePosition();
154 if (!required && channel != null) {
155 logger.debug("Removing unsupported channel for {}: {}", thing.getUID(), id);
156 updateThing(editThing().withoutChannels(channel).build());
157 } else if (required && channel == null) {
158 logger.warn("Thing {} does not have a '{}' channel => please re-create it", thing.getUID(), id);