]> git.basschouten.com Git - openhab-addons.git/blob
33dec534d99296defd2f1952e4a842f003e67539
[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.adorne.internal.discovery;
14
15 import static org.openhab.binding.adorne.internal.AdorneBindingConstants.*;
16
17 import java.util.Collections;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.adorne.internal.configuration.AdorneHubConfiguration;
22 import org.openhab.binding.adorne.internal.hub.AdorneHubChangeNotify;
23 import org.openhab.binding.adorne.internal.hub.AdorneHubController;
24 import org.openhab.core.config.discovery.AbstractDiscoveryService;
25 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
26 import org.openhab.core.config.discovery.DiscoveryService;
27 import org.openhab.core.thing.ThingTypeUID;
28 import org.openhab.core.thing.ThingUID;
29 import org.openhab.core.util.UIDUtils;
30 import org.osgi.service.component.annotations.Component;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * The {@link AdorneDiscoveryService} discovers things for the Adorne hub and Adorne devices.
36  * Discovery is only supported if the hub is accessible via default host and port.
37  *
38  * @author Mark Theiding - Initial Contribution
39  */
40 @NonNullByDefault
41 @Component(service = DiscoveryService.class, configurationPid = "discovery.adorne")
42 public class AdorneDiscoveryService extends AbstractDiscoveryService implements AdorneHubChangeNotify {
43
44     private final Logger logger = LoggerFactory.getLogger(AdorneDiscoveryService.class);
45     private static final int DISCOVERY_TIMEOUT_SECONDS = 10;
46     private static final String DISCOVERY_HUB_LABEL = "Adorne Hub";
47     private static final String DISCOVERY_ZONE_ID = "zoneId";
48     private @Nullable AdorneHubController adorneHubController;
49
50     /**
51      * Creates an AdorneDiscoveryService with disabled auto-discovery.
52      */
53     public AdorneDiscoveryService() {
54         // Passing false as last argument to super constructor turns off background discovery
55         super(Collections.singleton(new ThingTypeUID(BINDING_ID, "-")), DISCOVERY_TIMEOUT_SECONDS, false);
56
57         // We create the hub controller with default host and port. In the future we could let users create hubs
58         // manually with custom host and port settings and then perform discovery here for those hubs.
59         adorneHubController = null;
60     }
61
62     /**
63      * Kick off discovery of all devices on the hub
64      */
65     @Override
66     protected void startScan() {
67         logger.debug("Discovery scan started");
68
69         AdorneHubController adorneHubController = new AdorneHubController(new AdorneHubConfiguration(), scheduler,
70                 this);
71         this.adorneHubController = adorneHubController;
72
73         // Hack - we wrap the ThingUID in an array to make it appear effectively final to the compiler throughout the
74         // chain of futures. Passing it through the chain as context would bloat the code.
75         ThingUID[] bridgeUID = new ThingUID[1];
76
77         // Future enhancement: Need a timeout for each future execution to recover from bugs in the hub controller, but
78         // Java8 doesn't yet offer that
79         adorneHubController.start().thenCompose(Void -> {
80             // We use the hub's MAC address as its unique identifier
81             return adorneHubController.getMACAddress();
82         }).thenCompose(macAddress -> {
83             String macAddressNoColon = macAddress.replace(':', '-'); // Colons are not allowed in ThingUIDs
84             bridgeUID[0] = new ThingUID(THING_TYPE_HUB, macAddressNoColon);
85             // We have fully discovered the hub
86             thingDiscovered(DiscoveryResultBuilder.create(bridgeUID[0]).withLabel(DISCOVERY_HUB_LABEL).build());
87             return adorneHubController.getZones();
88         }).thenAccept(zoneIds -> {
89             zoneIds.forEach(zoneId -> {
90                 adorneHubController.getState(zoneId).thenAccept(state -> {
91                     String id = UIDUtils.encode(state.name); // Strip zone ID's name to become a valid ThingUID
92                     // We have fully discovered a new zone ID
93                     thingDiscovered(DiscoveryResultBuilder
94                             .create(new ThingUID(state.deviceType, bridgeUID[0], id.toLowerCase()))
95                             .withLabel(state.name).withBridge(bridgeUID[0])
96                             .withProperty(DISCOVERY_ZONE_ID, state.zoneId).build());
97                 }).exceptionally(e -> {
98                     logger.warn("Discovery of zone ID {} failed ({})", zoneId, e.getMessage());
99                     return null;
100                 });
101             });
102             adorneHubController.stopWhenCommandsServed(); // Shut down hub once all discovery requests have been served
103         }).exceptionally(e -> {
104             logger.warn("Discovery failed ({})", e.getMessage());
105             return null;
106         });
107     }
108
109     /**
110      * Notification to stop scanning
111      */
112     @Override
113     protected void stopScan() {
114         super.stopScan();
115
116         AdorneHubController adorneHubController = this.adorneHubController;
117         if (adorneHubController != null) {
118             adorneHubController.stop();
119             this.adorneHubController = null;
120             logger.debug("Discovery timed out. Scan stopped.");
121         }
122     }
123
124     // Nothing to do on change notifications
125     @Override
126     public void stateChangeNotify(int zoneId, boolean onOff, int brightness) {
127     }
128
129     @Override
130     public void connectionChangeNotify(boolean connected) {
131     }
132 }