2 * Copyright (c) 2010-2024 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.insteon.internal.discovery;
15 import static org.openhab.binding.insteon.internal.InsteonBindingConstants.*;
17 import java.time.Instant;
18 import java.util.HashMap;
20 import java.util.Optional;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.insteon.internal.device.InsteonAddress;
25 import org.openhab.binding.insteon.internal.device.InsteonModem;
26 import org.openhab.binding.insteon.internal.device.ProductData;
27 import org.openhab.binding.insteon.internal.handler.InsteonBridgeHandler;
28 import org.openhab.core.config.discovery.AbstractDiscoveryService;
29 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
30 import org.openhab.core.thing.ThingUID;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * The {@link InsteonDiscoveryService} is responsible for insteon devices & scenes discovery.
37 * @author Jeremy Setton - Initial contribution
40 public class InsteonDiscoveryService extends AbstractDiscoveryService {
41 private static final int SCAN_TIMEOUT = 2; // in seconds
43 private final Logger logger = LoggerFactory.getLogger(InsteonDiscoveryService.class);
45 private final InsteonBridgeHandler handler;
47 public InsteonDiscoveryService(InsteonBridgeHandler handler) {
48 super(DISCOVERABLE_THING_TYPES_UIDS, SCAN_TIMEOUT, false);
49 this.handler = handler;
51 logger.debug("initializing discovery service for bridge {}", handler.getThing().getUID());
53 handler.setDiscoveryService(this);
57 protected void startScan() {
58 logger.debug("starting manual scan on bridge {}", handler.getThing().getUID());
60 discoverMissingThings();
63 public void discoverInsteonDevice(InsteonAddress address, @Nullable ProductData productData) {
64 InsteonModem modem = handler.getModem();
65 if (handler.isDeviceDiscoveryEnabled() && modem != null && modem.getDB().hasEntry(address)
66 && !modem.hasDevice(address)) {
67 addInsteonDevice(address, productData);
69 removeInsteonDevice(address);
73 public void discoverInsteonScene(int group) {
74 InsteonModem modem = handler.getModem();
75 if (handler.isSceneDiscoveryEnabled() && modem != null && modem.getDB().hasBroadcastGroup(group)
76 && !modem.hasScene(group)) {
77 addInsteonScene(group);
79 removeInsteonScene(group);
83 public void discoverMissingThings() {
84 InsteonModem modem = handler.getModem();
86 logger.debug("modem not initialized, scanning aborted.");
87 } else if (!modem.getDB().isComplete()) {
88 logger.debug("modem database not complete, scanning aborted.");
90 long startTime = Instant.now().toEpochMilli();
92 if (handler.isDeviceDiscoveryEnabled()) {
93 modem.getDB().getDevices().stream().filter(address -> !modem.hasDevice(address)).forEach(address -> {
94 logger.debug("device {} in the modem database, but not configured", address);
95 addInsteonDevice(address, handler.getProductData(address));
98 logger.debug("device discovery is disabled, no device will be discovered.");
101 if (handler.isSceneDiscoveryEnabled()) {
102 modem.getDB().getBroadcastGroups().stream().filter(group -> !modem.hasScene(group)).forEach(group -> {
103 logger.debug("scene {} in the modem database, but not configured", group);
104 addInsteonScene(group);
107 logger.debug("scene discovery is disabled, no scene will be discovered.");
110 removeOlderResults(startTime, handler.getThing().getUID());
114 private void addInsteonDevice(InsteonAddress address, @Nullable ProductData productData) {
115 ThingUID bridgeUID = handler.getThing().getUID();
116 String id = address.toString().replace(".", "").toLowerCase();
117 ThingUID thingUID = new ThingUID(THING_TYPE_DEVICE, bridgeUID, id);
118 String label = Optional.ofNullable(productData).map(ProductData::getLabel).orElse("Insteon Device " + address);
119 Map<String, Object> properties = new HashMap<>();
120 properties.put(PROPERTY_DEVICE_ADDRESS, address.toString());
122 thingDiscovered(DiscoveryResultBuilder.create(thingUID).withBridge(bridgeUID).withLabel(label)
123 .withProperties(properties).withRepresentationProperty(PROPERTY_DEVICE_ADDRESS).build());
125 logger.debug("added Insteon device {} to inbox", address);
128 private void addInsteonScene(int group) {
129 ThingUID bridgeUID = handler.getThing().getUID();
130 String id = Integer.toString(group);
131 ThingUID thingUID = new ThingUID(THING_TYPE_SCENE, bridgeUID, id);
132 String label = "Insteon Scene " + group;
133 Map<String, Object> properties = new HashMap<>();
134 properties.put(PROPERTY_SCENE_GROUP, group);
136 thingDiscovered(DiscoveryResultBuilder.create(thingUID).withBridge(bridgeUID).withLabel(label)
137 .withProperties(properties).withRepresentationProperty(PROPERTY_SCENE_GROUP).build());
139 logger.debug("added Insteon scene {} to inbox", group);
142 private void removeInsteonDevice(InsteonAddress address) {
143 ThingUID bridgeUID = handler.getThing().getUID();
144 String id = address.toString().replace(".", "").toLowerCase();
145 ThingUID thingUID = new ThingUID(THING_TYPE_DEVICE, bridgeUID, id);
147 thingRemoved(thingUID);
150 private void removeInsteonScene(int group) {
151 ThingUID bridgeUID = handler.getThing().getUID();
152 String id = Integer.toString(group);
153 ThingUID thingUID = new ThingUID(THING_TYPE_SCENE, bridgeUID, id);
155 thingRemoved(thingUID);