]> git.basschouten.com Git - openhab-addons.git/blob
f346c8311cb8e0af1d8e6f52150d8363359db2b0
[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.somfymylink.internal.discovery;
14
15 import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.*;
16
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.somfymylink.internal.SomfyMyLinkHandlerFactory;
26 import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkBridgeHandler;
27 import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkException;
28 import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkScene;
29 import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkShade;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.config.discovery.DiscoveryService;
34 import org.openhab.core.config.discovery.ScanListener;
35 import org.openhab.core.thing.ThingStatus;
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.thing.binding.ThingHandlerService;
40 import org.osgi.service.component.annotations.Activate;
41 import org.osgi.service.component.annotations.Deactivate;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link SomfyMyLinkDeviceDiscoveryService} is responsible discovering things connected to the mylink.
47  *
48  * @author Chris Johnson - Initial contribution
49  */
50 @NonNullByDefault
51 public class SomfyMyLinkDeviceDiscoveryService extends AbstractDiscoveryService
52         implements DiscoveryService, ThingHandlerService {
53
54     private static final int DISCOVERY_REFRESH_SEC = 900;
55
56     private final Logger logger = LoggerFactory.getLogger(SomfyMyLinkDeviceDiscoveryService.class);
57     private @NonNullByDefault({}) SomfyMyLinkBridgeHandler mylinkHandler;
58     private @Nullable Future<?> scanTask;
59     private @Nullable ScheduledFuture<?> discoveryJob;
60
61     public SomfyMyLinkDeviceDiscoveryService() {
62         super(SomfyMyLinkHandlerFactory.DISCOVERABLE_DEVICE_TYPES_UIDS, 10);
63     }
64
65     @Override
66     public void setThingHandler(@Nullable ThingHandler handler) {
67         if (handler instanceof SomfyMyLinkBridgeHandler bridgeHandler) {
68             this.mylinkHandler = bridgeHandler;
69         }
70     }
71
72     @Override
73     public @Nullable ThingHandler getThingHandler() {
74         return mylinkHandler;
75     }
76
77     @Override
78     @Activate
79     public void activate() {
80         super.activate(null);
81     }
82
83     @Override
84     @Deactivate
85     public void deactivate() {
86         super.deactivate();
87     }
88
89     @Override
90     protected void startBackgroundDiscovery() {
91         logger.debug("Starting Somfy My Link background discovery");
92
93         ScheduledFuture<?> discoveryJob = this.discoveryJob;
94         if (discoveryJob == null || discoveryJob.isCancelled()) {
95             discoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, 10, DISCOVERY_REFRESH_SEC,
96                     TimeUnit.SECONDS);
97         }
98     }
99
100     @Override
101     protected void stopBackgroundDiscovery() {
102         logger.debug("Stopping Somfy MyLink background discovery");
103
104         ScheduledFuture<?> discoveryJob = this.discoveryJob;
105         if (discoveryJob != null) {
106             discoveryJob.cancel(true);
107             this.discoveryJob = null;
108         }
109     }
110
111     @Override
112     protected synchronized void startScan() {
113         Future<?> scanTask = this.scanTask;
114         if (scanTask == null || scanTask.isDone()) {
115             logger.debug("Starting somfy mylink discovery scan");
116             scanTask = scheduler.submit(this::discoverDevices);
117         }
118     }
119
120     @Override
121     public void stopScan() {
122         Future<?> scanTask = this.scanTask;
123         if (scanTask != null) {
124             logger.debug("Stopping somfy mylink discovery scan");
125             scanTask.cancel(true);
126         }
127         super.stopScan();
128     }
129
130     private synchronized void discoverDevices() {
131         logger.info("Scanning for things...");
132
133         if (this.mylinkHandler.getThing().getStatus() != ThingStatus.ONLINE) {
134             logger.info("Skipping device discover as bridge is {}", this.mylinkHandler.getThing().getStatus());
135             return;
136         }
137
138         try {
139             // get the shade list
140             SomfyMyLinkShade[] shades = this.mylinkHandler.getShadeList();
141
142             for (SomfyMyLinkShade shade : shades) {
143                 String id = shade.getTargetID();
144                 String label = "Somfy Shade " + shade.getName();
145
146                 if (id != null) {
147                     logger.debug("Adding device {}", id);
148                     notifyThingDiscovery(THING_TYPE_SHADE, id, label, TARGET_ID);
149                 }
150             }
151
152             SomfyMyLinkScene[] scenes = this.mylinkHandler.getSceneList();
153
154             for (SomfyMyLinkScene scene : scenes) {
155                 String id = scene.getTargetID();
156                 String label = "Somfy Scene " + scene.getName();
157
158                 logger.debug("Adding device {}", id);
159                 notifyThingDiscovery(THING_TYPE_SCENE, id, label, SCENE_ID);
160             }
161         } catch (SomfyMyLinkException e) {
162             logger.warn("Error scanning for devices: {}", e.getMessage(), e);
163             ScanListener scanListener = this.scanListener;
164             if (scanListener != null) {
165                 scanListener.onErrorOccurred(e);
166             }
167         }
168     }
169
170     private void notifyThingDiscovery(ThingTypeUID thingTypeUID, String id, String label, String idType) {
171         if (id.isEmpty()) {
172             logger.info("Discovered {} with no ID", label);
173             return;
174         }
175
176         ThingUID bridgeUID = this.mylinkHandler.getThing().getUID();
177         ThingUID uid = new ThingUID(thingTypeUID, bridgeUID, id);
178
179         Map<String, Object> properties = new HashMap<>();
180
181         properties.put(idType, id);
182
183         DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID).withLabel(label)
184                 .withProperties(properties).withRepresentationProperty(idType).build();
185
186         thingDiscovered(result);
187
188         logger.debug("Discovered {}", uid);
189     }
190 }