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.types.RefreshType.REFRESH;
18 import java.io.IOException;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.qbus.internal.QbusBridgeHandler;
24 import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
25 import org.openhab.binding.qbus.internal.protocol.QbusDimmer;
26 import org.openhab.core.library.types.IncreaseDecreaseType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.PercentType;
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 QbusDimmerHandler} is responsible for handling the dimmable outputs of Qbus
40 * @author Koen Schockaert - Initial Contribution
44 public class QbusDimmerHandler extends QbusGlobalHandler {
46 private final Logger logger = LoggerFactory.getLogger(QbusDimmerHandler.class);
48 protected @Nullable QbusThingsConfig dimmerConfig = new QbusThingsConfig();
50 private @Nullable Integer dimmerId;
52 private @Nullable String sn;
54 public QbusDimmerHandler(Thing thing) {
62 public void initialize() {
65 this.dimmerId = getId();
69 scheduler.submit(() -> {
70 QbusCommunication controllerComm;
72 if (this.dimmerId != null) {
73 controllerComm = getCommunication("Dimmer", this.dimmerId);
75 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for DIMMER no set! " + this.dimmerId);
79 if (controllerComm == null) {
80 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
81 "ID for DIMMER not known in controller " + this.dimmerId);
85 Map<Integer, QbusDimmer> dimmerCommLocal = controllerComm.getDimmer();
87 QbusDimmer outputLocal = dimmerCommLocal.get(this.dimmerId);
89 if (outputLocal == null) {
90 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
91 "Bridge could not initialize DIMMER ID " + this.dimmerId);
95 outputLocal.setThingHandler(this);
96 handleStateUpdate(outputLocal);
98 QbusBridgeHandler qBridgeHandler = getBridgeHandler("Dimmer", this.dimmerId);
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 DIMMER ID " + this.dimmerId);
112 * Handle the status update from the dimmer
115 public void handleCommand(ChannelUID channelUID, Command command) {
116 QbusCommunication qComm = getCommunication("Dimmer", this.dimmerId);
119 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
120 "ID for DIMMER not known in controller " + this.dimmerId);
123 Map<Integer, QbusDimmer> dimmerComm = qComm.getDimmer();
125 QbusDimmer qDimmer = dimmerComm.get(this.dimmerId);
127 if (qDimmer == null) {
128 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
129 "ID for DIMMER not known in controller " + this.dimmerId);
132 scheduler.submit(() -> {
133 if (!qComm.communicationActive()) {
134 restartCommunication(qComm, "Dimmer", this.dimmerId);
137 if (qComm.communicationActive()) {
138 if (command == REFRESH) {
139 handleStateUpdate(qDimmer);
143 switch (channelUID.getId()) {
146 handleSwitchCommand(qDimmer, command);
147 } catch (IOException e) {
148 String message = e.getMessage();
149 logger.warn("Error on executing Switch for dimmer ID {}. IOException: {}",
150 this.dimmerId, message);
151 } catch (InterruptedException e) {
152 String message = e.getMessage();
153 logger.warn("Error on executing Switch for dimmer ID {}. Interruptedexception {}",
154 this.dimmerId, message);
158 case CHANNEL_BRIGHTNESS:
160 handleBrightnessCommand(qDimmer, command);
161 } catch (IOException e) {
162 String message = e.getMessage();
163 logger.warn("Error on executing Brightness for dimmer ID {}. IOException: {}",
164 this.dimmerId, message);
165 } catch (InterruptedException e) {
166 String message = e.getMessage();
168 "Error on executing Brightness for dimmer ID {}. Interruptedexception {}",
169 this.dimmerId, message);
174 thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
175 "Unknown Channel " + channelUID.getId());
184 * Executes the switch command
186 * @throws IOException
187 * @throws InterruptedException
189 private void handleSwitchCommand(QbusDimmer qDimmer, Command command) throws InterruptedException, IOException {
190 if (command instanceof OnOffType) {
191 String snr = getSN();
193 if (command == OnOffType.OFF) {
194 qDimmer.execute(0, snr);
196 qDimmer.execute(1000, snr);
199 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
200 "No serial number configured for DIMMER " + this.dimmerId);
206 * Executes the brightness command
208 * @throws IOException
209 * @throws InterruptedException
211 private void handleBrightnessCommand(QbusDimmer qDimmer, Command command) throws InterruptedException, IOException {
212 String snr = getSN();
215 thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
216 "No serial number configured for DIMMER " + this.dimmerId);
219 if (command instanceof OnOffType) {
220 if (command == OnOffType.OFF) {
221 qDimmer.execute(0, snr);
223 qDimmer.execute(100, snr);
225 } else if (command instanceof IncreaseDecreaseType) {
226 int stepValue = ((Number) getConfig().get(CONFIG_STEP_VALUE)).intValue();
227 Integer currentValue = qDimmer.getState();
230 if (currentValue != null) {
231 if (command == IncreaseDecreaseType.INCREASE) {
232 newValue = currentValue + stepValue;
233 // round down to step multiple
234 newValue = newValue - newValue % stepValue;
235 sendvalue = newValue > 100 ? 100 : newValue;
236 qDimmer.execute(sendvalue, snr);
238 newValue = currentValue - stepValue;
239 // round up to step multiple
240 newValue = newValue + newValue % stepValue;
241 sendvalue = newValue < 0 ? 0 : newValue;
242 qDimmer.execute(sendvalue, snr);
245 } else if (command instanceof PercentType) {
246 int percentToInt = ((PercentType) command).intValue();
247 if (PercentType.ZERO.equals(command)) {
248 qDimmer.execute(0, snr);
250 qDimmer.execute(percentToInt, snr);
257 * Method to update state of channel, called from Qbus Dimmer.
261 public void handleStateUpdate(QbusDimmer qDimmer) {
262 Integer dimmerState = qDimmer.getState();
263 if (dimmerState != null) {
264 updateState(CHANNEL_BRIGHTNESS, new PercentType(dimmerState));
269 * Returns the serial number of the controller
271 * @return the serial number
273 public @Nullable String getSN() {
278 * Sets the serial number of the controller
280 public void setSN() {
281 QbusBridgeHandler qBridgeHandler = getBridgeHandler("Dimmer", this.dimmerId);
282 if (qBridgeHandler == null) {
283 thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
284 "No communication with Qbus Bridge for DIMMER " + this.dimmerId);
287 this.sn = qBridgeHandler.getSn();
291 * Read the configuration
293 protected synchronized void readConfig() {
294 dimmerConfig = getConfig().as(QbusThingsConfig.class);
298 * Returns the Id from the configuration
302 public @Nullable Integer getId() {
303 QbusThingsConfig localConfig = dimmerConfig;
304 if (localConfig != null) {
305 return localConfig.dimmerId;