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.dali.internal.handler;
15 import static org.openhab.binding.dali.internal.DaliBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.util.List;
19 import java.util.concurrent.CompletableFuture;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.dali.internal.protocol.DaliAddress;
24 import org.openhab.binding.dali.internal.protocol.DaliDAPCCommand;
25 import org.openhab.binding.dali.internal.protocol.DaliResponse;
26 import org.openhab.binding.dali.internal.protocol.DaliResponse.NumericMask;
27 import org.openhab.binding.dali.internal.protocol.DaliStandardCommand;
28 import org.openhab.core.library.types.HSBType;
29 import org.openhab.core.library.types.IncreaseDecreaseType;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.PercentType;
32 import org.openhab.core.thing.Bridge;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.binding.BaseThingHandler;
38 import org.openhab.core.thing.binding.BridgeHandler;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * The {@link DaliRgbHandler} handles commands for things of type RGB.
47 * @author Robert Schmid - Initial contribution
50 public class DaliRgbHandler extends BaseThingHandler {
51 private final Logger logger = LoggerFactory.getLogger(DaliRgbHandler.class);
52 private @Nullable List<Integer> outputs;
54 public DaliRgbHandler(Thing thing) {
59 public void initialize() {
60 Bridge bridge = getBridge();
63 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
65 updateStatus(ThingStatus.ONLINE);
68 outputs = List.of(((BigDecimal) this.thing.getConfiguration().get(TARGET_ID_R)).intValueExact(),
69 ((BigDecimal) this.thing.getConfiguration().get(TARGET_ID_G)).intValueExact(),
70 ((BigDecimal) this.thing.getConfiguration().get(TARGET_ID_B)).intValueExact());
74 public void handleCommand(ChannelUID channelUID, Command command) {
76 if (CHANNEL_COLOR.equals(channelUID.getId())) {
77 boolean queryDeviceState = false;
79 if (command instanceof HSBType) {
80 PercentType[] rgb = ((HSBType) command).toRGB();
82 for (int i = 0; i < 3; i++) {
83 byte dimmValue = (byte) ((rgb[i].floatValue() * DALI_SWITCH_100_PERCENT) / 100);
84 getBridgeHandler().sendCommand(
85 new DaliDAPCCommand(DaliAddress.createShortAddress(outputs.get(i)), dimmValue));
87 } else if (command instanceof OnOffType) {
88 if ((OnOffType) command == OnOffType.ON) {
89 for (Integer output : outputs) {
90 getBridgeHandler().sendCommand(new DaliDAPCCommand(DaliAddress.createShortAddress(output),
91 (byte) DALI_SWITCH_100_PERCENT));
94 for (Integer output : outputs) {
95 getBridgeHandler().sendCommand(
96 DaliStandardCommand.createOffCommand(DaliAddress.createShortAddress(output)));
99 } else if (command instanceof IncreaseDecreaseType) {
100 if ((IncreaseDecreaseType) command == IncreaseDecreaseType.INCREASE) {
101 for (Integer output : outputs) {
102 getBridgeHandler().sendCommand(
103 DaliStandardCommand.createUpCommand(DaliAddress.createShortAddress(output)));
106 for (Integer output : outputs) {
107 getBridgeHandler().sendCommand(
108 DaliStandardCommand.createDownCommand(DaliAddress.createShortAddress(output)));
112 queryDeviceState = true;
113 } else if (command instanceof RefreshType) {
114 queryDeviceState = true;
117 if (queryDeviceState) {
118 CompletableFuture<@Nullable NumericMask> responseR = getBridgeHandler()
119 .sendCommandWithResponse(
120 DaliStandardCommand.createQueryActualLevelCommand(
121 DaliAddress.createShortAddress(outputs.get(0))),
122 DaliResponse.NumericMask.class);
123 CompletableFuture<@Nullable NumericMask> responseG = getBridgeHandler()
124 .sendCommandWithResponse(
125 DaliStandardCommand.createQueryActualLevelCommand(
126 DaliAddress.createShortAddress(outputs.get(1))),
127 DaliResponse.NumericMask.class);
128 CompletableFuture<@Nullable NumericMask> responseB = getBridgeHandler()
129 .sendCommandWithResponse(
130 DaliStandardCommand.createQueryActualLevelCommand(
131 DaliAddress.createShortAddress(outputs.get(2))),
132 DaliResponse.NumericMask.class);
134 CompletableFuture.allOf(responseR, responseG, responseB).thenAccept(x -> {
136 NumericMask r = responseR.join(), g = responseG.join(), b = responseB.join();
137 if (r != null && !r.mask && g != null && !g.mask && b != null && !b.mask) {
138 Integer rValue = r.value != null ? r.value : 0;
139 Integer gValue = g.value != null ? g.value : 0;
140 Integer bValue = b.value != null ? b.value : 0;
141 updateState(channelUID,
142 HSBType.fromRGB((int) (rValue.floatValue() * 255 / DALI_SWITCH_100_PERCENT),
143 (int) (gValue.floatValue() * 255 / DALI_SWITCH_100_PERCENT),
144 (int) (bValue.floatValue() * 255 / DALI_SWITCH_100_PERCENT)));
146 }).exceptionally(e -> {
147 logger.warn("Error querying device status: {}", e.getMessage());
152 } catch (DaliException e) {
153 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
157 protected DaliserverBridgeHandler getBridgeHandler() throws DaliException {
158 Bridge bridge = this.getBridge();
159 if (bridge == null) {
160 throw new DaliException("No bridge was found");
163 BridgeHandler handler = bridge.getHandler();
164 if (handler == null) {
165 throw new DaliException("No handler was found");
168 return (DaliserverBridgeHandler) handler;