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.dmx.internal.handler;
15 import static org.openhab.binding.dmx.internal.DmxBindingConstants.*;
17 import java.util.ArrayList;
18 import java.util.List;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
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.ValueSet;
26 import org.openhab.binding.dmx.internal.action.FadeAction;
27 import org.openhab.binding.dmx.internal.action.ResumeAction;
28 import org.openhab.binding.dmx.internal.config.ChaserThingHandlerConfiguration;
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.OnOffType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.openhab.core.types.State;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * The {@link ChaserThingHandler} is responsible for handling commands, which are
49 * @author Jan N. Klug - Initial contribution
52 public class ChaserThingHandler extends DmxThingHandler {
53 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_CHASER);
55 private final Logger logger = LoggerFactory.getLogger(ChaserThingHandler.class);
57 private final List<DmxChannel> channels = new ArrayList<>();
58 private List<ValueSet> values = new ArrayList<>();
60 private boolean resumeAfter = false;
61 private OnOffType isRunning = OnOffType.OFF;
63 public ChaserThingHandler(Thing dimmerThing) {
68 public void handleCommand(ChannelUID channelUID, Command command) {
69 switch (channelUID.getId()) {
71 if (command instanceof OnOffType onOffCommand) {
72 if (onOffCommand.equals(OnOffType.ON)) {
73 Integer channelCounter = 0;
74 for (DmxChannel channel : channels) {
76 channel.suspendAction();
78 channel.clearAction();
80 for (ValueSet value : values) {
81 channel.addChannelAction(new FadeAction(value.getFadeTime(),
82 value.getValue(channelCounter), value.getHoldTime()));
85 channel.addChannelAction(new ResumeAction());
87 channel.addListener(channelUID, this, ListenerType.ACTION);
91 for (DmxChannel channel : channels) {
92 if (resumeAfter && channel.isSuspended()) {
93 channel.setChannelAction(new ResumeAction());
95 channel.clearAction();
99 } else if (command instanceof RefreshType) {
100 updateState(channelUID, isRunning);
102 logger.debug("command {} not supported in channel {}:switch", command.getClass(),
103 this.thing.getUID());
106 case CHANNEL_CONTROL:
107 if (command instanceof StringType stringCommand) {
108 List<ValueSet> newValues = ValueSet.parseChaseConfig(stringCommand.toString());
109 if (!newValues.isEmpty()) {
111 logger.debug("updated chase config in {}", this.thing.getUID());
113 logger.debug("could not update chase config in {}, malformed: {}", this.thing.getUID(),
117 logger.debug("command {} not supported in channel {}:control", command.getClass(),
118 this.thing.getUID());
122 logger.debug("Channel {} not supported in thing {}", channelUID.getId(), this.thing.getUID());
127 public void initialize() {
128 Bridge bridge = getBridge();
129 DmxBridgeHandler bridgeHandler;
130 if (bridge == null) {
131 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "no bridge assigned");
132 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
135 bridgeHandler = (DmxBridgeHandler) bridge.getHandler();
136 if (bridgeHandler == null) {
137 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "no bridge handler available");
138 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
143 ChaserThingHandlerConfiguration configuration = getConfig().as(ChaserThingHandlerConfiguration.class);
145 if (configuration.dmxid.isEmpty()) {
146 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
147 "DMX channel configuration missing");
148 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
153 List<BaseDmxChannel> configChannels = BaseDmxChannel.fromString(configuration.dmxid,
154 bridgeHandler.getUniverseId());
155 logger.trace("found {} channels in {}", configChannels.size(), this.thing.getUID());
156 for (BaseDmxChannel channel : configChannels) {
157 channels.add(bridgeHandler.getDmxChannel(channel, this.thing));
159 } catch (IllegalArgumentException e) {
160 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
161 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
164 if (!configuration.steps.isEmpty()) {
165 values = ValueSet.parseChaseConfig(configuration.steps);
166 if (!values.isEmpty()) {
167 if (bridge.getStatus().equals(ThingStatus.ONLINE)) {
168 updateStatus(ThingStatus.ONLINE);
169 dmxHandlerStatus = ThingStatusDetail.NONE;
171 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
174 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
175 "chaser configuration malformed");
176 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
179 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Chase configuration missing");
180 dmxHandlerStatus = ThingStatusDetail.CONFIGURATION_ERROR;
183 resumeAfter = configuration.resumeafter;
184 logger.trace("set resumeAfter to {}", resumeAfter);
188 public void dispose() {
189 if (!channels.isEmpty()) {
190 Bridge bridge = getBridge();
191 if (bridge != null) {
192 DmxBridgeHandler bridgeHandler = (DmxBridgeHandler) bridge.getHandler();
193 if (bridgeHandler != null) {
194 bridgeHandler.unregisterDmxChannels(this.thing);
195 logger.debug("removing {} channels from {}", channels.size(), this.thing.getUID());
197 ChannelUID switchChannelUID = new ChannelUID(this.thing.getUID(), CHANNEL_SWITCH);
198 for (DmxChannel channel : channels) {
199 channel.removeListener(switchChannelUID);
207 public void updateSwitchState(ChannelUID channelUID, State state) {
208 logger.trace("received {} for {}", state, channelUID);
209 if (channelUID.getId().equals(CHANNEL_SWITCH) && (state instanceof OnOffType onOffState)) {
210 this.isRunning = onOffState;
211 updateState(channelUID, state);
213 logger.debug("unknown state received: {} in channel {} thing {}", state, channelUID, this.thing.getUID());