2 * Copyright (c) 2010-2020 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.nikobus.internal.handler;
15 import static org.openhab.binding.nikobus.internal.NikobusBindingConstants.*;
16 import static org.openhab.binding.nikobus.internal.protocol.SwitchModuleGroup.*;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.nikobus.internal.protocol.NikobusCommand;
27 import org.openhab.binding.nikobus.internal.protocol.SwitchModuleGroup;
28 import org.openhab.binding.nikobus.internal.utils.Utils;
29 import org.openhab.core.common.AbstractUID;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingTypeUID;
37 import org.openhab.core.thing.ThingUID;
38 import org.openhab.core.thing.binding.ThingHandler;
39 import org.openhab.core.types.Command;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link NikobusPushButtonHandler} is responsible for handling Nikobus push buttons.
46 * @author Boris Krivonog - Initial contribution
49 public class NikobusPushButtonHandler extends NikobusBaseThingHandler {
50 private static class ImpactedModule {
51 private final ThingUID thingUID;
52 private final SwitchModuleGroup group;
54 ImpactedModule(ThingUID thingUID, SwitchModuleGroup group) {
55 this.thingUID = thingUID;
59 public ThingUID getThingUID() {
63 public SwitchModuleGroup getGroup() {
68 public String toString() {
69 return "'" + thingUID + "'-" + group;
73 private static class ImpactedModuleUID extends AbstractUID {
74 ImpactedModuleUID(String uid) {
78 String getThingTypeId() {
86 SwitchModuleGroup getGroup() {
87 if (getSegment(2).equals("1")) {
90 if (getSegment(2).equals("2")) {
93 throw new IllegalArgumentException("Unexpected group found " + getSegment(2));
97 protected int getMinimalNumberOfSegments() {
102 private static final String END_OF_TRANSMISSION = "\r#E1";
103 private final Logger logger = LoggerFactory.getLogger(NikobusPushButtonHandler.class);
104 private final List<ImpactedModule> impactedModules = Collections.synchronizedList(new ArrayList<>());
105 private @Nullable Future<?> requestUpdateFuture;
107 public NikobusPushButtonHandler(Thing thing) {
112 public void initialize() {
115 if (thing.getStatus() == ThingStatus.OFFLINE) {
119 impactedModules.clear();
121 Object impactedModulesObject = getConfig().get(CONFIG_IMPACTED_MODULES);
122 if (impactedModulesObject != null) {
124 Bridge bridge = getBridge();
125 if (bridge == null) {
126 throw new IllegalArgumentException("Bridge does not exist!");
129 ThingUID bridgeUID = thing.getBridgeUID();
130 if (bridgeUID == null) {
131 throw new IllegalArgumentException("Unable to read BridgeUID!");
134 String[] impactedModulesString = impactedModulesObject.toString().split(",");
135 for (String impactedModuleString : impactedModulesString) {
136 ImpactedModuleUID impactedModuleUID = new ImpactedModuleUID(impactedModuleString.trim());
137 ThingTypeUID thingTypeUID = new ThingTypeUID(bridgeUID.getBindingId(),
138 impactedModuleUID.getThingTypeId());
139 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, impactedModuleUID.getThingId());
141 if (!bridge.getThings().stream().anyMatch(thing -> thing.getUID().equals(thingUID))) {
142 throw new IllegalArgumentException(
143 "Impacted module " + thingUID + " not found for '" + impactedModuleString + "'");
146 impactedModules.add(new ImpactedModule(thingUID, impactedModuleUID.getGroup()));
148 } catch (RuntimeException e) {
149 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
153 logger.debug("Impacted modules for {} = {}", thing.getUID(), impactedModules);
156 NikobusPcLinkHandler pcLink = getPcLink();
157 if (pcLink != null) {
158 pcLink.addListener(getAddress(), this::commandReceived);
163 public void dispose() {
166 Utils.cancel(requestUpdateFuture);
167 requestUpdateFuture = null;
169 NikobusPcLinkHandler pcLink = getPcLink();
170 if (pcLink != null) {
171 pcLink.removeListener(getAddress());
176 public void handleCommand(ChannelUID channelUID, Command command) {
177 logger.debug("handleCommand '{}' '{}'", channelUID, command);
179 if (!CHANNEL_BUTTON.equals(channelUID.getId())) {
183 // Whenever the button receives an ON command,
184 // we send a simulated button press to the Nikobus.
185 if (command == OnOffType.ON) {
186 NikobusPcLinkHandler pcLink = getPcLink();
187 if (pcLink != null) {
188 pcLink.sendCommand(new NikobusCommand(getAddress() + END_OF_TRANSMISSION));
193 private void commandReceived() {
194 if (thing.getStatus() != ThingStatus.ONLINE) {
195 updateStatus(ThingStatus.ONLINE);
198 updateState(CHANNEL_BUTTON, OnOffType.ON);
200 if (!impactedModules.isEmpty()) {
201 Utils.cancel(requestUpdateFuture);
202 requestUpdateFuture = scheduler.schedule(this::update, 400, TimeUnit.MILLISECONDS);
206 private void update() {
207 for (ImpactedModule module : impactedModules) {
208 NikobusModuleHandler switchModule = getModuleWithId(module.getThingUID());
209 if (switchModule != null) {
210 switchModule.requestStatus(module.getGroup());
215 private @Nullable NikobusModuleHandler getModuleWithId(ThingUID thingUID) {
216 Bridge bridge = getBridge();
217 if (bridge == null) {
221 Thing thing = bridge.getThing(thingUID);
226 ThingHandler thingHandler = thing.getHandler();
227 if (thingHandler instanceof NikobusModuleHandler) {
228 return (NikobusModuleHandler) thingHandler;
234 protected String getAddress() {
235 return "#N" + super.getAddress();