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.ecovacs.internal.discovery;
15 import static org.openhab.binding.ecovacs.internal.EcovacsBindingConstants.*;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Optional;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.ecovacs.internal.api.EcovacsApi;
24 import org.openhab.binding.ecovacs.internal.api.EcovacsApiException;
25 import org.openhab.binding.ecovacs.internal.api.EcovacsDevice;
26 import org.openhab.binding.ecovacs.internal.api.util.SchedulerTask;
27 import org.openhab.binding.ecovacs.internal.handler.EcovacsApiHandler;
28 import org.openhab.core.config.discovery.AbstractDiscoveryService;
29 import org.openhab.core.config.discovery.DiscoveryResult;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.config.discovery.DiscoveryService;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingUID;
34 import org.openhab.core.thing.binding.ThingHandler;
35 import org.openhab.core.thing.binding.ThingHandlerService;
36 import org.osgi.service.component.annotations.Component;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link EcovacsDeviceDiscoveryService} is used for discovering devices registered in the cloud account.
43 * @author Danny Baumann - Initial contribution
46 @Component(service = DiscoveryService.class, configurationPid = "discovery.ecovacs")
47 public class EcovacsDeviceDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
48 private final Logger logger = LoggerFactory.getLogger(EcovacsDeviceDiscoveryService.class);
50 private static final int DISCOVER_TIMEOUT_SECONDS = 10;
52 private @NonNullByDefault({}) EcovacsApiHandler apiHandler;
53 private Optional<EcovacsApi> api = Optional.empty();
54 private final SchedulerTask onDemandScanTask = new SchedulerTask(scheduler, logger, "OnDemandScan",
55 this::scanForDevices);
56 private final SchedulerTask backgroundScanTask = new SchedulerTask(scheduler, logger, "BackgroundScan",
57 this::scanForDevices);
59 public EcovacsDeviceDiscoveryService() {
60 super(Collections.singleton(THING_TYPE_VACUUM), DISCOVER_TIMEOUT_SECONDS, true);
64 public void setThingHandler(@Nullable ThingHandler handler) {
65 if (handler instanceof EcovacsApiHandler) {
66 this.apiHandler = (EcovacsApiHandler) handler;
67 this.apiHandler.setDiscoveryService(this);
72 public @Nullable ThingHandler getThingHandler() {
77 public void activate() {
82 public void deactivate() {
87 protected synchronized void startBackgroundDiscovery() {
88 stopBackgroundDiscovery();
89 backgroundScanTask.scheduleRecurring(60);
93 protected synchronized void stopBackgroundDiscovery() {
94 backgroundScanTask.cancel();
97 public synchronized void startScanningWithApi(EcovacsApi api) {
98 this.api = Optional.of(api);
99 onDemandScanTask.cancel();
104 public synchronized void startScan() {
105 logger.debug("Starting Ecovacs discovery scan");
106 onDemandScanTask.submit();
110 public synchronized void stopScan() {
111 logger.debug("Stopping Ecovacs discovery scan");
112 onDemandScanTask.cancel();
116 private void scanForDevices() {
117 this.api.ifPresent(api -> {
118 long timestampOfLastScan = getTimestampOfLastScan();
120 List<EcovacsDevice> devices = api.getDevices();
121 logger.debug("Ecovacs discovery found {} devices", devices.size());
123 for (EcovacsDevice device : devices) {
124 deviceDiscovered(device);
126 for (Thing thing : apiHandler.getThing().getThings()) {
127 String serial = thing.getUID().getId();
128 if (!devices.stream().anyMatch(d -> serial.equals(d.getSerialNumber()))) {
129 thingRemoved(thing.getUID());
132 } catch (InterruptedException e) {
133 Thread.currentThread().interrupt();
134 } catch (EcovacsApiException e) {
135 logger.debug("Could not retrieve devices from Ecovacs API", e);
137 removeOlderResults(timestampOfLastScan);
142 private void deviceDiscovered(EcovacsDevice device) {
143 ThingUID thingUID = new ThingUID(THING_TYPE_VACUUM, apiHandler.getThing().getUID(), device.getSerialNumber());
144 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
145 .withBridge(apiHandler.getThing().getUID()).withLabel(device.getModelName())
146 .withProperty(Thing.PROPERTY_SERIAL_NUMBER, device.getSerialNumber())
147 .withProperty(Thing.PROPERTY_MODEL_ID, device.getModelName())
148 .withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
149 thingDiscovered(discoveryResult);