2 * Copyright (c) 2010-2023 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.adorne.internal.discovery;
15 import static org.openhab.binding.adorne.internal.AdorneBindingConstants.*;
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;
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.
38 * @author Mark Theiding - Initial Contribution
41 @Component(service = DiscoveryService.class, configurationPid = "discovery.adorne")
42 public class AdorneDiscoveryService extends AbstractDiscoveryService implements AdorneHubChangeNotify {
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;
51 * Creates an AdorneDiscoveryService with disabled auto-discovery.
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);
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;
63 * Kick off discovery of all devices on the hub
66 protected void startScan() {
67 logger.debug("Discovery scan started");
69 AdorneHubController adorneHubController = new AdorneHubController(new AdorneHubConfiguration(), scheduler,
71 this.adorneHubController = adorneHubController;
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];
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());
101 adorneHubController.stopWhenCommandsServed(); // Shut down hub once all discovery requests have been served
102 }).exceptionally(e -> {
103 logger.warn("Discovery failed ({})", e.getMessage());
109 * Notification to stop scanning
112 protected void stopScan() {
115 AdorneHubController adorneHubController = this.adorneHubController;
116 if (adorneHubController != null) {
117 adorneHubController.stop();
118 this.adorneHubController = null;
119 logger.debug("Discovery timed out. Scan stopped.");
123 // Nothing to do on change notifications
125 public void stateChangeNotify(int zoneId, boolean onOff, int brightness) {
129 public void connectionChangeNotify(boolean connected) {