]> git.basschouten.com Git - openhab-addons.git/blob
8d21f443bc9e7e7b8b036f639dcb1f9dd24ce0e4
[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.elroconnects.internal.discovery;
14
15 import static org.openhab.binding.elroconnects.internal.ElroConnectsBindingConstants.*;
16
17 import java.time.Instant;
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.elroconnects.internal.ElroConnectsBindingConstants;
26 import org.openhab.binding.elroconnects.internal.devices.ElroConnectsConnector;
27 import org.openhab.binding.elroconnects.internal.handler.ElroConnectsAccountHandler;
28 import org.openhab.core.config.discovery.AbstractDiscoveryService;
29 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingUID;
32 import org.openhab.core.thing.binding.ThingHandler;
33 import org.openhab.core.thing.binding.ThingHandlerService;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * {@link ElroConnectsBridgeDiscoveryService} is used to discover K1 Hubs attached to an ELRO Connects cloud account.
39  *
40  * @author Mark Herwege - Initial Contribution
41  */
42 @NonNullByDefault
43 public class ElroConnectsBridgeDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
44
45     private final Logger logger = LoggerFactory.getLogger(ElroConnectsBridgeDiscoveryService.class);
46
47     private @Nullable ElroConnectsAccountHandler accountHandler;
48
49     private volatile @Nullable ScheduledFuture<?> discoveryJob;
50
51     private static final int TIMEOUT_S = 5;
52     private static final int INITIAL_DELAY_S = 5; // initial delay for polling to allow time for login and retrieval in
53                                                   // ElroConnectsAccountHandler to complete
54     private static final int REFRESH_INTERVAL_S = 60;
55
56     public ElroConnectsBridgeDiscoveryService() {
57         super(ElroConnectsBindingConstants.SUPPORTED_CONNECTOR_TYPES_UIDS, TIMEOUT_S);
58         logger.debug("Bridge discovery service started");
59     }
60
61     @Override
62     protected void startScan() {
63         scheduler.execute(this::discoverConnectors); // If background account polling is not enabled for the handler,
64                                                      // this will trigger http requests, therefore do in separate thread
65                                                      // to be able to return quickly
66     }
67
68     private void discoverConnectors() {
69         logger.debug("Starting hub discovery scan");
70         ElroConnectsAccountHandler account = accountHandler;
71         if (account == null) {
72             return;
73         }
74
75         ThingUID bridgeUID = account.getThing().getUID();
76
77         Map<String, ElroConnectsConnector> connectors = account.getDevices();
78         if (connectors == null) {
79             return;
80         }
81
82         connectors.entrySet().forEach(c -> {
83             if (c.getValue().online) {
84                 String connectorId = c.getKey();
85                 String firmwareVersion = c.getValue().binVersion;
86                 boolean legacy = false;
87                 try {
88                     legacy = Integer.valueOf(firmwareVersion.substring(firmwareVersion.lastIndexOf(".") + 1)) <= 14;
89                 } catch (NumberFormatException e) {
90                     // Assume new firmware if we cannot decode firmwareVersion
91                     logger.debug("Cannot get firmware version from {}, assume new firmware", firmwareVersion);
92                 }
93                 final Map<String, Object> properties = new HashMap<>();
94                 properties.put(CONFIG_CONNECTOR_ID, connectorId);
95                 properties.put(CONFIG_LEGACY_FIRMWARE, legacy);
96                 properties.put("binVersion", c.getValue().binVersion);
97                 properties.put("binType", c.getValue().binType);
98                 properties.put("sdkVer", c.getValue().sdkVer);
99                 properties.put(Thing.PROPERTY_MODEL_ID, c.getValue().model);
100                 properties.put("desc", c.getValue().desc);
101
102                 thingDiscovered(
103                         DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_CONNECTOR, bridgeUID, connectorId))
104                                 .withLabel(c.getValue().desc).withBridge(bridgeUID).withProperties(properties)
105                                 .withRepresentationProperty(CONFIG_CONNECTOR_ID).build());
106             }
107         });
108     }
109
110     @Override
111     protected synchronized void stopScan() {
112         super.stopScan();
113         removeOlderResults(getTimestampOfLastScan());
114     }
115
116     @Override
117     public void startBackgroundDiscovery() {
118         logger.debug("Start bridge background discovery");
119         ScheduledFuture<?> job = discoveryJob;
120         if (job == null || job.isCancelled()) {
121             discoveryJob = scheduler.scheduleWithFixedDelay(this::discoverConnectors, INITIAL_DELAY_S,
122                     REFRESH_INTERVAL_S, TimeUnit.SECONDS);
123         }
124     }
125
126     @Override
127     public void stopBackgroundDiscovery() {
128         logger.debug("Stop bridge background discovery");
129         ScheduledFuture<?> job = discoveryJob;
130         if (job != null && !job.isCancelled()) {
131             job.cancel(true);
132             discoveryJob = null;
133         }
134     }
135
136     @Override
137     public void deactivate() {
138         removeOlderResults(Instant.now().toEpochMilli());
139         super.deactivate();
140     }
141
142     @Override
143     public void setThingHandler(@Nullable ThingHandler handler) {
144         if (handler instanceof ElroConnectsAccountHandler accountHandler) {
145             this.accountHandler = accountHandler;
146             accountHandler.setDiscoveryService(this);
147         }
148     }
149
150     @Override
151     public @Nullable ThingHandler getThingHandler() {
152         return accountHandler;
153     }
154 }