]> git.basschouten.com Git - openhab-addons.git/blob
40064794e0215fed1b270de44b3649635da1befd
[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.Set;
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(Set.of(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         adorneHubController.getMACAddress()).thenCompose(macAddress -> {
82             String macAddressNoColon = macAddress.replace(':', '-'); // Colons are not allowed in ThingUIDs
83             bridgeUID[0] = new ThingUID(THING_TYPE_HUB, macAddressNoColon);
84             // We have fully discovered the hub
85             thingDiscovered(DiscoveryResultBuilder.create(bridgeUID[0]).withLabel(DISCOVERY_HUB_LABEL).build());
86             return adorneHubController.getZones();
87         }).thenAccept(zoneIds -> {
88             zoneIds.forEach(zoneId -> {
89                 adorneHubController.getState(zoneId).thenAccept(state -> {
90                     String id = UIDUtils.encode(state.name); // Strip zone ID's name to become a valid ThingUID
91                     // We have fully discovered a new zone ID
92                     thingDiscovered(DiscoveryResultBuilder
93                             .create(new ThingUID(state.deviceType, bridgeUID[0], id.toLowerCase()))
94                             .withLabel(state.name).withBridge(bridgeUID[0])
95                             .withProperty(DISCOVERY_ZONE_ID, state.zoneId).build());
96                 }).exceptionally(e -> {
97                     logger.warn("Discovery of zone ID {} failed ({})", zoneId, e.getMessage());
98                     return null;
99                 });
100             });
101             adorneHubController.stopWhenCommandsServed(); // Shut down hub once all discovery requests have been served
102         }).exceptionally(e -> {
103             logger.warn("Discovery failed ({})", e.getMessage());
104             return null;
105         });
106     }
107
108     /**
109      * Notification to stop scanning
110      */
111     @Override
112     protected void stopScan() {
113         super.stopScan();
114
115         AdorneHubController adorneHubController = this.adorneHubController;
116         if (adorneHubController != null) {
117             adorneHubController.stop();
118             this.adorneHubController = null;
119             logger.debug("Discovery timed out. Scan stopped.");
120         }
121     }
122
123     // Nothing to do on change notifications
124     @Override
125     public void stateChangeNotify(int zoneId, boolean onOff, int brightness) {
126     }
127
128     @Override
129     public void connectionChangeNotify(boolean connected) {
130     }
131 }