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
14 package org.openhab.binding.touchwand.internal.discovery;
16 import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.*;
18 import java.util.Arrays;
19 import java.util.Date;
20 import java.util.HashMap;
22 import java.util.concurrent.CopyOnWriteArraySet;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.touchwand.internal.TouchWandBridgeHandler;
30 import org.openhab.binding.touchwand.internal.TouchWandUnitStatusUpdateListener;
31 import org.openhab.binding.touchwand.internal.dto.TouchWandUnitData;
32 import org.openhab.binding.touchwand.internal.dto.TouchWandUnitFromJson;
33 import org.openhab.core.config.discovery.AbstractDiscoveryService;
34 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
35 import org.openhab.core.config.discovery.DiscoveryService;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingTypeUID;
38 import org.openhab.core.thing.ThingUID;
39 import org.openhab.core.thing.binding.ThingHandler;
40 import org.openhab.core.thing.binding.ThingHandlerService;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 import com.google.gson.JsonArray;
45 import com.google.gson.JsonElement;
46 import com.google.gson.JsonParser;
47 import com.google.gson.JsonSyntaxException;
50 * The {@link TouchWandUnitDiscoveryService} Discovery service for TouchWand units.
52 * @author Roie Geron - Initial contribution
55 public class TouchWandUnitDiscoveryService extends AbstractDiscoveryService
56 implements DiscoveryService, ThingHandlerService {
58 private static final int SEARCH_TIME_SEC = 10;
59 private static final int SCAN_INTERVAL_SEC = 60;
60 private static final int LINK_DISCOVERY_SERVICE_INITIAL_DELAY_SEC = 5;
61 private static final String[] CONNECTIVITY_OPTIONS = { CONNECTIVITY_KNX, CONNECTIVITY_ZWAVE };
62 private @NonNullByDefault({}) TouchWandBridgeHandler touchWandBridgeHandler;
63 private final Logger logger = LoggerFactory.getLogger(TouchWandUnitDiscoveryService.class);
65 private @Nullable ScheduledFuture<?> scanningJob;
66 private CopyOnWriteArraySet<TouchWandUnitStatusUpdateListener> listeners = new CopyOnWriteArraySet<>();
68 public TouchWandUnitDiscoveryService() {
69 super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME_SEC, true);
73 protected void startScan() {
74 if (touchWandBridgeHandler.getThing().getStatus() != ThingStatus.ONLINE) {
75 logger.warn("Could not scan units while bridge offline");
79 logger.debug("Starting TouchWand discovery on bridge {}", touchWandBridgeHandler.getThing().getUID());
80 String response = touchWandBridgeHandler.touchWandClient.cmdListUnits();
81 if (response.isEmpty()) {
85 JsonParser jsonParser = new JsonParser();
87 JsonArray jsonArray = jsonParser.parse(response).getAsJsonArray();
88 if (jsonArray.isJsonArray()) {
90 for (JsonElement unit : jsonArray) {
91 TouchWandUnitData touchWandUnit;
92 touchWandUnit = TouchWandUnitFromJson.parseResponse(unit.getAsJsonObject());
94 if (!touchWandBridgeHandler.isAddSecondaryControllerUnits()) {
95 if (!Arrays.asList(CONNECTIVITY_OPTIONS).contains(touchWandUnit.getConnectivity())) {
99 String type = touchWandUnit.getType();
100 if (!Arrays.asList(SUPPORTED_TOUCHWAND_TYPES).contains(type)) {
101 logger.debug("Unit discovery skipping unsupported unit type : {} ", type);
105 case TYPE_WALLCONTROLLER:
106 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_WALLCONTROLLER);
109 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_SWITCH);
110 notifyListeners(touchWandUnit);
113 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_DIMMER);
114 notifyListeners(touchWandUnit);
117 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_SHUTTER);
119 case TYPE_ALARMSENSOR:
120 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_ALARMSENSOR);
126 } catch (JsonSyntaxException e) {
127 logger.warn("Could not parse unit {}", e.getMessage());
130 } catch (JsonSyntaxException msg) {
131 logger.warn("Could not parse list units response {}", msg.getMessage());
135 private void notifyListeners(TouchWandUnitData touchWandUnit) {
136 for (TouchWandUnitStatusUpdateListener listener : listeners) {
137 listener.onDataReceived(touchWandUnit);
142 protected void stopScan() {
143 removeOlderResults(getTimestampOfLastScan());
148 public void activate() {
149 super.activate(null);
150 removeOlderResults(new Date().getTime(), touchWandBridgeHandler.getThing().getUID());
154 public void deactivate() {
155 removeOlderResults(new Date().getTime(), touchWandBridgeHandler.getThing().getUID());
160 protected void startBackgroundDiscovery() {
161 ScheduledFuture<?> localScanningJob = scanningJob;
162 if (localScanningJob == null || localScanningJob.isCancelled()) {
163 scanningJob = scheduler.scheduleWithFixedDelay(this::startScan, LINK_DISCOVERY_SERVICE_INITIAL_DELAY_SEC,
164 SCAN_INTERVAL_SEC, TimeUnit.SECONDS);
169 protected void stopBackgroundDiscovery() {
170 ScheduledFuture<?> myScanningJob = scanningJob;
171 if (myScanningJob != null) {
172 myScanningJob.cancel(true);
177 public void registerListener(TouchWandUnitStatusUpdateListener listener) {
178 if (!listeners.contains(listener)) {
179 logger.debug("Adding TouchWandWebSocket listener {}", listener);
180 listeners.add(listener);
184 public void unregisterListener(TouchWandUnitStatusUpdateListener listener) {
185 logger.debug("Removing TouchWandWebSocket listener {}", listener);
186 listeners.remove(listener);
190 public int getScanTimeout() {
191 return SEARCH_TIME_SEC;
194 private void addDeviceDiscoveryResult(TouchWandUnitData unit, ThingTypeUID typeUID) {
195 ThingUID bridgeUID = touchWandBridgeHandler.getThing().getUID();
196 ThingUID thingUID = new ThingUID(typeUID, bridgeUID, unit.getId().toString());
197 Map<String, Object> properties = new HashMap<>();
198 properties.put(HANDLER_PROPERTIES_ID, unit.getId().toString());
199 properties.put(HANDLER_PROPERTIES_NAME, unit.getName());
201 thingDiscovered(DiscoveryResultBuilder.create(thingUID)
202 .withThingType(typeUID)
203 .withLabel(unit.getName())
204 .withBridge(bridgeUID)
205 .withProperties(properties)
206 .withRepresentationProperty(HANDLER_PROPERTIES_ID)
213 public void setThingHandler(@NonNullByDefault({}) ThingHandler handler) {
214 if (handler instanceof TouchWandBridgeHandler) {
215 touchWandBridgeHandler = (TouchWandBridgeHandler) handler;
216 registerListener(touchWandBridgeHandler);
221 public @NonNull ThingHandler getThingHandler() {
222 return touchWandBridgeHandler;