]> git.basschouten.com Git - openhab-addons.git/blob
282f07b86f5d41d59445c51895ea559d8cac9708
[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.neohub.internal;
14
15 import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
16
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22 import java.util.stream.Collectors;
23 import java.util.stream.Stream;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
28 import org.openhab.binding.neohub.internal.NeoHubInfoResponse.InfoRecord;
29 import org.openhab.binding.neohub.internal.NeoHubLiveDeviceData.LiveDataRecord;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * Discovery service for neo devices
41  *
42  * @author Andrew Fiddian-Green - Initial contribution
43  *
44  */
45 @NonNullByDefault
46 public class NeoHubDiscoveryService extends AbstractDiscoveryService {
47
48     private final Logger logger = LoggerFactory.getLogger(NeoHubDiscoveryService.class);
49
50     private @Nullable ScheduledFuture<?> discoveryScheduler;
51
52     private NeoHubHandler hub;
53
54     public static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPES_UIDS = Collections.unmodifiableSet(
55             Stream.of(THING_TYPE_NEOSTAT, THING_TYPE_NEOPLUG, THING_TYPE_NEOCONTACT, THING_TYPE_NEOTEMPERATURESENSOR)
56                     .collect(Collectors.toSet()));
57
58     public NeoHubDiscoveryService(NeoHubHandler hub) {
59         // note: background discovery is enabled in the super method
60         super(DISCOVERABLE_THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
61         this.hub = hub;
62     }
63
64     public void activate() {
65         super.activate(null);
66     }
67
68     @Override
69     public void deactivate() {
70         super.deactivate();
71     }
72
73     @Override
74     protected void startScan() {
75         if (hub.getThing().getStatus() == ThingStatus.ONLINE) {
76             discoverDevices();
77         }
78     }
79
80     @Override
81     protected void startBackgroundDiscovery() {
82         logger.debug("start background discovery..");
83
84         ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
85         if (discoveryScheduler == null || discoveryScheduler.isCancelled()) {
86             this.discoveryScheduler = scheduler.scheduleWithFixedDelay(this::startScan, 10, DISCOVERY_REFRESH_PERIOD,
87                     TimeUnit.SECONDS);
88         }
89     }
90
91     @Override
92     protected void stopBackgroundDiscovery() {
93         logger.debug("stop background discovery..");
94
95         ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
96         if (discoveryScheduler != null && !discoveryScheduler.isCancelled()) {
97             discoveryScheduler.cancel(true);
98         }
99     }
100
101     private void discoverDevices() {
102         NeoHubAbstractDeviceData deviceData = hub.fromNeoHubGetDeviceData();
103         NeoHubGetEngineersData engineerData = hub.isLegacyApiSelected() ? null : hub.fromNeoHubGetEngineersData();
104
105         if (deviceData != null) {
106             List<? extends AbstractRecord> deviceRecords = deviceData.getDevices();
107
108             if (deviceRecords != null) {
109                 int deviceType;
110
111                 for (AbstractRecord deviceRecord : deviceRecords) {
112
113                     // the record came from the legacy API (deviceType included)
114                     if (deviceRecord instanceof InfoRecord) {
115                         deviceType = ((InfoRecord) deviceRecord).getDeviceType();
116                         publishDevice(deviceRecord, deviceType);
117                         continue;
118                     }
119
120                     // the record came from the new API (deviceType NOT included)
121                     if (deviceRecord instanceof LiveDataRecord) {
122                         if (engineerData == null) {
123                             break;
124                         }
125                         String deviceName = ((LiveDataRecord) deviceRecord).getDeviceName();
126                         // exclude repeater nodes from being discovered
127                         if (MATCHER_HEATMISER_REPEATER.matcher(deviceName).matches()) {
128                             continue;
129                         }
130                         deviceType = engineerData.getDeviceType(deviceName);
131                         publishDevice(deviceRecord, deviceType);
132                     }
133                 }
134             }
135         }
136     }
137
138     private void publishDevice(AbstractRecord device, int deviceId) {
139         if (deviceId <= 0) {
140             return;
141         }
142
143         String deviceType;
144         String deviceOpenHabId;
145         String deviceNeohubName;
146         ThingUID deviceUID;
147         ThingTypeUID deviceTypeUID;
148         DiscoveryResult discoveredDevice;
149
150         ThingUID bridgeUID = hub.getThing().getUID();
151
152         switch (deviceId) {
153             case HEATMISER_DEVICE_TYPE_CONTACT: {
154                 deviceType = DEVICE_ID_NEOCONTACT;
155                 deviceTypeUID = THING_TYPE_NEOCONTACT;
156                 break;
157             }
158             case HEATMISER_DEVICE_TYPE_PLUG: {
159                 deviceType = DEVICE_ID_NEOPLUG;
160                 deviceTypeUID = THING_TYPE_NEOPLUG;
161                 break;
162             }
163             case HEATMISER_DEVICE_TYPE_TEMPERATURE_SENSOR: {
164                 deviceType = DEVICE_ID_NEOTEMPERATURESENSOR;
165                 deviceTypeUID = THING_TYPE_NEOTEMPERATURESENSOR;
166                 break;
167             }
168             // all other device types are assumed to be thermostats
169             default: {
170                 deviceType = DEVICE_ID_NEOSTAT;
171                 deviceTypeUID = THING_TYPE_NEOSTAT;
172             }
173         }
174
175         deviceNeohubName = device.getDeviceName();
176         deviceOpenHabId = deviceNeohubName.replaceAll("\\s+", "_");
177         deviceUID = new ThingUID(deviceTypeUID, bridgeUID, deviceOpenHabId);
178
179         discoveredDevice = DiscoveryResultBuilder.create(deviceUID).withBridge(bridgeUID).withLabel(deviceOpenHabId)
180                 .withProperty(DEVICE_NAME, deviceNeohubName).withRepresentationProperty(DEVICE_NAME).build();
181
182         thingDiscovered(discoveredDevice);
183
184         logger.debug("discovered device: id={}, type={}, name={} ..", deviceId, deviceType, deviceOpenHabId);
185     }
186 }