]> git.basschouten.com Git - openhab-addons.git/blob
33a3ce49c0631ced26b5dc78d7079d97337e90b1
[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.ecovacs.internal.discovery;
14
15 import static org.openhab.binding.ecovacs.internal.EcovacsBindingConstants.*;
16
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Optional;
20
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;
39
40 /**
41  * The {@link EcovacsDeviceDiscoveryService} is used for discovering devices registered in the cloud account.
42  *
43  * @author Danny Baumann - Initial contribution
44  */
45 @NonNullByDefault
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);
49
50     private static final int DISCOVER_TIMEOUT_SECONDS = 10;
51
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);
58
59     public EcovacsDeviceDiscoveryService() {
60         super(Collections.singleton(THING_TYPE_VACUUM), DISCOVER_TIMEOUT_SECONDS, true);
61     }
62
63     @Override
64     public void setThingHandler(@Nullable ThingHandler handler) {
65         if (handler instanceof EcovacsApiHandler) {
66             this.apiHandler = (EcovacsApiHandler) handler;
67             this.apiHandler.setDiscoveryService(this);
68         }
69     }
70
71     @Override
72     public @Nullable ThingHandler getThingHandler() {
73         return apiHandler;
74     }
75
76     @Override
77     public void activate() {
78         super.activate(null);
79     }
80
81     @Override
82     public void deactivate() {
83         super.deactivate();
84     }
85
86     @Override
87     protected synchronized void startBackgroundDiscovery() {
88         stopBackgroundDiscovery();
89         backgroundScanTask.scheduleRecurring(60);
90     }
91
92     @Override
93     protected synchronized void stopBackgroundDiscovery() {
94         backgroundScanTask.cancel();
95     }
96
97     public synchronized void startScanningWithApi(EcovacsApi api) {
98         this.api = Optional.of(api);
99         onDemandScanTask.cancel();
100         startScan();
101     }
102
103     @Override
104     public synchronized void startScan() {
105         logger.debug("Starting Ecovacs discovery scan");
106         onDemandScanTask.submit();
107     }
108
109     @Override
110     public synchronized void stopScan() {
111         logger.debug("Stopping Ecovacs discovery scan");
112         onDemandScanTask.cancel();
113         super.stopScan();
114     }
115
116     private void scanForDevices() {
117         this.api.ifPresent(api -> {
118             long timestampOfLastScan = getTimestampOfLastScan();
119             try {
120                 List<EcovacsDevice> devices = api.getDevices();
121                 logger.debug("Ecovacs discovery found {} devices", devices.size());
122
123                 for (EcovacsDevice device : devices) {
124                     deviceDiscovered(device);
125                 }
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());
130                     }
131                 }
132             } catch (InterruptedException e) {
133                 Thread.currentThread().interrupt();
134             } catch (EcovacsApiException e) {
135                 logger.debug("Could not retrieve devices from Ecovacs API", e);
136             } finally {
137                 removeOlderResults(timestampOfLastScan);
138             }
139         });
140     }
141
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);
150     }
151 }