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.amazonechocontrol.internal.discovery;
15 import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.amazonechocontrol.internal.Connection;
29 import org.openhab.binding.amazonechocontrol.internal.handler.AccountHandler;
30 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
31 import org.openhab.core.config.discovery.AbstractDiscoveryService;
32 import org.openhab.core.config.discovery.DiscoveryResult;
33 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.osgi.service.component.annotations.Activate;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link AmazonEchoDiscovery} is responsible for discovering echo devices on
42 * the amazon account specified in the binding.
44 * @author Michael Geramb - Initial contribution
47 public class AmazonEchoDiscovery extends AbstractDiscoveryService {
49 AccountHandler accountHandler;
50 private final Logger logger = LoggerFactory.getLogger(AmazonEchoDiscovery.class);
51 private final Set<String> discoveredFlashBriefings = new HashSet<>();
53 private @Nullable ScheduledFuture<?> startScanStateJob;
54 private @Nullable Long activateTimeStamp;
56 public AmazonEchoDiscovery(AccountHandler accountHandler) {
57 super(SUPPORTED_ECHO_THING_TYPES_UIDS, 10);
58 this.accountHandler = accountHandler;
61 public void activate() {
62 activate(new HashMap<>());
66 public void deactivate() {
71 protected void startScan() {
73 final Long activateTimeStamp = this.activateTimeStamp;
74 if (activateTimeStamp != null) {
75 removeOlderResults(activateTimeStamp);
77 setDevices(accountHandler.updateDeviceList());
79 String currentFlashBriefingConfiguration = accountHandler.getNewCurrentFlashbriefingConfiguration();
80 discoverFlashBriefingProfiles(currentFlashBriefingConfiguration);
83 protected void startAutomaticScan() {
84 if (!this.accountHandler.getThing().getThings().isEmpty()) {
88 Connection connection = this.accountHandler.findConnection();
89 if (connection == null) {
92 Date verifyTime = connection.tryGetVerifyTime();
93 if (verifyTime == null) {
96 if (new Date().getTime() - verifyTime.getTime() < 10000) {
103 protected void startBackgroundDiscovery() {
105 startScanStateJob = scheduler.scheduleWithFixedDelay(this::startAutomaticScan, 3000, 1000,
106 TimeUnit.MILLISECONDS);
110 protected void stopBackgroundDiscovery() {
116 ScheduledFuture<?> currentStartScanStateJob = startScanStateJob;
117 if (currentStartScanStateJob != null) {
118 currentStartScanStateJob.cancel(false);
119 startScanStateJob = null;
125 public void activate(@Nullable Map<String, Object> config) {
126 super.activate(config);
127 if (config != null) {
130 if (activateTimeStamp == null) {
131 activateTimeStamp = new Date().getTime();
135 synchronized void setDevices(List<Device> deviceList) {
136 for (Device device : deviceList) {
137 String serialNumber = device.serialNumber;
138 if (serialNumber != null) {
139 String deviceFamily = device.deviceFamily;
140 if (deviceFamily != null) {
141 ThingTypeUID thingTypeId;
142 if ("ECHO".equals(deviceFamily)) {
143 thingTypeId = THING_TYPE_ECHO;
144 } else if ("ROOK".equals(deviceFamily)) {
145 thingTypeId = THING_TYPE_ECHO_SPOT;
146 } else if ("KNIGHT".equals(deviceFamily)) {
147 thingTypeId = THING_TYPE_ECHO_SHOW;
148 } else if ("WHA".equals(deviceFamily)) {
149 thingTypeId = THING_TYPE_ECHO_WHA;
151 logger.debug("Unknown thing type '{}'", deviceFamily);
155 ThingUID bridgeThingUID = this.accountHandler.getThing().getUID();
156 ThingUID thingUID = new ThingUID(thingTypeId, bridgeThingUID, serialNumber);
158 DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withLabel(device.accountName)
159 .withProperty(DEVICE_PROPERTY_SERIAL_NUMBER, serialNumber)
160 .withProperty(DEVICE_PROPERTY_FAMILY, deviceFamily)
161 .withRepresentationProperty(DEVICE_PROPERTY_SERIAL_NUMBER).withBridge(bridgeThingUID)
164 logger.debug("Device [{}: {}] found. Mapped to thing type {}", device.deviceFamily, serialNumber,
165 thingTypeId.getAsString());
167 thingDiscovered(result);
173 public synchronized void discoverFlashBriefingProfiles(String currentFlashBriefingJson) {
174 if (currentFlashBriefingJson.isEmpty()) {
178 if (!discoveredFlashBriefings.contains(currentFlashBriefingJson)) {
179 ThingUID bridgeThingUID = this.accountHandler.getThing().getUID();
180 ThingUID freeThingUID = new ThingUID(THING_TYPE_FLASH_BRIEFING_PROFILE, bridgeThingUID,
181 Integer.toString(currentFlashBriefingJson.hashCode()));
182 DiscoveryResult result = DiscoveryResultBuilder.create(freeThingUID).withLabel("FlashBriefing")
183 .withProperty(DEVICE_PROPERTY_FLASH_BRIEFING_PROFILE, currentFlashBriefingJson)
184 .withBridge(accountHandler.getThing().getUID()).build();
185 logger.debug("Flash Briefing {} discovered", currentFlashBriefingJson);
186 thingDiscovered(result);
187 discoveredFlashBriefings.add(currentFlashBriefingJson);
191 public synchronized void removeExistingFlashBriefingProfile(@Nullable String currentFlashBriefingJson) {
192 if (currentFlashBriefingJson != null) {
193 discoveredFlashBriefings.remove(currentFlashBriefingJson);