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