]> git.basschouten.com Git - openhab-addons.git/blob
c289d1bcf629a0bb91cb6718759b6f278dbd926b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.dmx.internal.handler;
14
15 import static org.openhab.binding.dmx.internal.DmxBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.stream.IntStream;
21
22 import org.openhab.binding.dmx.internal.DmxBindingConstants.ListenerType;
23 import org.openhab.binding.dmx.internal.DmxBridgeHandler;
24 import org.openhab.binding.dmx.internal.DmxThingHandler;
25 import org.openhab.binding.dmx.internal.Util;
26 import org.openhab.binding.dmx.internal.ValueSet;
27 import org.openhab.binding.dmx.internal.action.FadeAction;
28 import org.openhab.binding.dmx.internal.config.DimmerThingHandlerConfiguration;
29 import org.openhab.binding.dmx.internal.multiverse.BaseDmxChannel;
30 import org.openhab.binding.dmx.internal.multiverse.DmxChannel;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.IncreaseDecreaseType;
33 import org.openhab.core.library.types.OnOffType;
34 import org.openhab.core.library.types.PercentType;
35 import org.openhab.core.thing.Bridge;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.thing.ThingStatus;
39 import org.openhab.core.thing.ThingStatusDetail;
40 import org.openhab.core.thing.ThingTypeUID;
41 import org.openhab.core.types.Command;
42 import org.openhab.core.types.RefreshType;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * The {@link DimmerThingHandler} is responsible for handling commands, which are
48  * sent to the dimmer.
49  *
50  * @author Jan N. Klug - Initial contribution
51  */
52
53 public class DimmerThingHandler extends DmxThingHandler {
54     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_DIMMER);
55
56     private final Logger logger = LoggerFactory.getLogger(DimmerThingHandler.class);
57
58     private final List<DmxChannel> channels = new ArrayList<>();
59
60     private PercentType currentBrightness = PercentType.ZERO;
61
62     private ValueSet turnOnValue = new ValueSet(0, -1, DmxChannel.MAX_VALUE);
63     private ValueSet turnOffValue = new ValueSet(0, -1, DmxChannel.MIN_VALUE);
64
65     private int fadeTime = 0, dimTime = 0;
66
67     private boolean dynamicTurnOnValue = false;
68     private boolean isDimming = false;
69
70     public DimmerThingHandler(Thing dimmerThing) {
71         super(dimmerThing);
72     }
73
74     @Override
75     public void handleCommand(ChannelUID channelUID, Command command) {
76         logger.trace("received command {} in channel {}", command, channelUID);
77         ValueSet targetValueSet = new ValueSet(fadeTime, -1);
78         switch (channelUID.getId()) {
79             case CHANNEL_BRIGHTNESS: {
80                 if (command instanceof PercentType || command instanceof DecimalType) {
81                     PercentType brightness = (command instanceof PercentType percentCommand) ? percentCommand
82                             : Util.toPercentValue(((DecimalType) command).intValue());
83                     logger.trace("adding fade to channels in thing {}", this.thing.getUID());
84                     targetValueSet.addValue(brightness);
85                 } else if (command instanceof OnOffType onOffCommand) {
86                     logger.trace("adding {} fade to channels in thing {}", command, this.thing.getUID());
87                     if (onOffCommand == OnOffType.ON) {
88                         targetValueSet = turnOnValue;
89                     } else {
90                         if (dynamicTurnOnValue) {
91                             turnOnValue.clear();
92                             for (DmxChannel channel : channels) {
93                                 turnOnValue.addValue(channel.getValue());
94                             }
95                             logger.trace("stored channel values fort next turn-on");
96                         }
97                         targetValueSet = turnOffValue;
98                     }
99                 } else if (command instanceof IncreaseDecreaseType increaseDecreaseCommand) {
100                     if (isDimming && increaseDecreaseCommand.equals(IncreaseDecreaseType.INCREASE)) {
101                         logger.trace("stopping fade in thing {}", this.thing.getUID());
102                         channels.forEach(DmxChannel::clearAction);
103                         isDimming = false;
104                         return;
105                     } else {
106                         logger.trace("starting {} fade in thing {}", command, this.thing.getUID());
107                         targetValueSet = increaseDecreaseCommand.equals(IncreaseDecreaseType.INCREASE) ? turnOnValue
108                                 : turnOffValue;
109                         targetValueSet.setFadeTime(dimTime);
110                         isDimming = true;
111                     }
112                 } else if (command instanceof RefreshType) {
113                     logger.trace("sending update on refresh to channel {}:brightness", this.thing.getUID());
114                     currentBrightness = Util.toPercentValue(channels.get(0).getValue());
115                     updateState(channelUID, currentBrightness);
116                     return;
117                 } else {
118                     logger.debug("command {} not supported in channel {}:brightness", command.getClass(),
119                             this.thing.getUID());
120                     return;
121                 }
122                 break;
123             }
124             default:
125                 logger.debug("channel {} not supported in thing {}", channelUID.getId(), this.thing.getUID());
126                 return;
127         }
128         final ValueSet valueSet = targetValueSet;
129         IntStream.range(0, channels.size()).forEach(i -> {
130             channels.get(i).setChannelAction(new FadeAction(valueSet.getFadeTime(), channels.get(i).getValue(),
131                     valueSet.getValue(i), valueSet.getHoldTime()));
132         });
133     }
134
135     @Override
136     public void initialize() {
137         Bridge bridge = getBridge();
138         DmxBridgeHandler bridgeHandler;
139         if (bridge == null) {
140             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "no bridge assigned");
141             dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
142             return;
143         } else {
144             bridgeHandler = (DmxBridgeHandler) bridge.getHandler();
145             if (bridgeHandler == null) {
146                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "no bridge handler available");
147                 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
148                 return;
149             }
150         }
151
152         DimmerThingHandlerConfiguration configuration = getConfig().as(DimmerThingHandlerConfiguration.class);
153
154         if (configuration.dmxid.isEmpty()) {
155             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
156                     "DMX channel configuration missing");
157             dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
158             return;
159         }
160         try {
161             List<BaseDmxChannel> configChannels = BaseDmxChannel.fromString(configuration.dmxid,
162                     bridgeHandler.getUniverseId());
163             logger.trace("found {} channels in {}", configChannels.size(), this.thing.getUID());
164             for (BaseDmxChannel channel : configChannels) {
165                 channels.add(bridgeHandler.getDmxChannel(channel, this.thing));
166             }
167         } catch (IllegalArgumentException e) {
168             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
169             dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
170             return;
171         }
172
173         fadeTime = configuration.fadetime;
174         logger.trace("setting fadeTime to {} ms in {}", fadeTime, this.thing.getUID());
175
176         dimTime = configuration.dimtime;
177         logger.trace("setting dimTime to {} ms in {}", fadeTime, this.thing.getUID());
178
179         String turnOnValueString = fadeTime + ":" + configuration.turnonvalue + ":-1";
180
181         ValueSet turnOnValue = ValueSet.fromString(turnOnValueString);
182         if (!turnOnValue.isEmpty()) {
183             this.turnOnValue = turnOnValue;
184             logger.trace("set turnonvalue to {} in {}", turnOnValue, this.thing.getUID());
185         } else {
186             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "turn-on value malformed");
187             dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
188             return;
189         }
190
191         this.turnOnValue.setFadeTime(fadeTime);
192
193         dynamicTurnOnValue = configuration.dynamicturnonvalue;
194
195         String turnOffValueString = fadeTime + ":" + configuration.turnoffvalue + ":-1";
196         ValueSet turnOffValue = ValueSet.fromString(turnOffValueString);
197         if (!turnOffValue.isEmpty()) {
198             this.turnOffValue = turnOffValue;
199             logger.trace("set turnoffvalue to {} in {}", turnOffValue, this.thing.getUID());
200         } else {
201             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "turn-off value malformed");
202             dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
203             return;
204         }
205
206         this.turnOffValue.setFadeTime(fadeTime);
207
208         // register feedback listener
209         channels.get(0).addListener(new ChannelUID(this.thing.getUID(), CHANNEL_BRIGHTNESS), this, ListenerType.VALUE);
210
211         if (bridge.getStatus().equals(ThingStatus.ONLINE)) {
212             updateStatus(ThingStatus.ONLINE);
213             dmxHandlerStatus = ThingStatusDetail.NONE;
214         } else {
215             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
216         }
217     }
218
219     @Override
220     public void dispose() {
221         if (!channels.isEmpty()) {
222             channels.get(0).removeListener(new ChannelUID(this.thing.getUID(), CHANNEL_BRIGHTNESS));
223
224             Bridge bridge = getBridge();
225             if (bridge != null) {
226                 DmxBridgeHandler bridgeHandler = (DmxBridgeHandler) bridge.getHandler();
227                 if (bridgeHandler != null) {
228                     bridgeHandler.unregisterDmxChannels(this.thing);
229                     logger.debug("removing {} channels from {}", channels.size(), this.thing.getUID());
230                 }
231             }
232             channels.clear();
233         }
234     }
235
236     @Override
237     public void updateChannelValue(ChannelUID channelUID, int value) {
238         updateState(channelUID, Util.toPercentValue(value));
239         if (channelUID.getId().equals(CHANNEL_BRIGHTNESS)) {
240             currentBrightness = Util.toPercentValue(value);
241         } else {
242             logger.debug("don't know how to handle {}", channelUID.getId());
243             return;
244         }
245         logger.trace("received update {} in channel {}, resulting in brightness={}", value, channelUID,
246                 currentBrightness);
247     }
248 }