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.neohub.internal;
15 import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
17 import java.util.Collections;
18 import java.util.List;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22 import java.util.stream.Collectors;
23 import java.util.stream.Stream;
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;
40 * Discovery service for neo devices
42 * @author Andrew Fiddian-Green - Initial contribution
46 public class NeoHubDiscoveryService extends AbstractDiscoveryService {
48 private final Logger logger = LoggerFactory.getLogger(NeoHubDiscoveryService.class);
50 private @Nullable ScheduledFuture<?> discoveryScheduler;
52 private NeoHubHandler hub;
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()));
58 public NeoHubDiscoveryService(NeoHubHandler hub) {
59 // note: background discovery is enabled in the super method
60 super(DISCOVERABLE_THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
64 public void activate() {
69 public void deactivate() {
74 protected void startScan() {
75 if (hub.getThing().getStatus() == ThingStatus.ONLINE) {
81 protected void startBackgroundDiscovery() {
82 logger.debug("start background discovery..");
84 ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
85 if (discoveryScheduler == null || discoveryScheduler.isCancelled()) {
86 this.discoveryScheduler = scheduler.scheduleWithFixedDelay(this::startScan, 10, DISCOVERY_REFRESH_PERIOD,
92 protected void stopBackgroundDiscovery() {
93 logger.debug("stop background discovery..");
95 ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
96 if (discoveryScheduler != null && !discoveryScheduler.isCancelled()) {
97 discoveryScheduler.cancel(true);
101 private void discoverDevices() {
102 NeoHubAbstractDeviceData deviceData = hub.fromNeoHubGetDeviceData();
103 NeoHubGetEngineersData engineerData = hub.isLegacyApiSelected() ? null : hub.fromNeoHubGetEngineersData();
105 if (deviceData != null) {
106 List<? extends AbstractRecord> deviceRecords = deviceData.getDevices();
108 if (deviceRecords != null) {
111 for (AbstractRecord deviceRecord : deviceRecords) {
113 // the record came from the legacy API (deviceType included)
114 if (deviceRecord instanceof InfoRecord infoRecord) {
115 deviceType = infoRecord.getDeviceType();
116 publishDevice(deviceRecord, deviceType);
120 // the record came from the new API (deviceType NOT included)
121 if (deviceRecord instanceof LiveDataRecord liveDataRecord) {
122 if (engineerData == null) {
125 String deviceName = liveDataRecord.getDeviceName();
126 // exclude repeater nodes from being discovered
127 if (MATCHER_HEATMISER_REPEATER.matcher(deviceName).matches()) {
130 deviceType = engineerData.getDeviceType(deviceName);
131 publishDevice(deviceRecord, deviceType);
138 private void publishDevice(AbstractRecord device, int deviceId) {
144 String deviceOpenHabId;
145 String deviceNeohubName;
147 ThingTypeUID deviceTypeUID;
148 DiscoveryResult discoveredDevice;
150 ThingUID bridgeUID = hub.getThing().getUID();
153 case HEATMISER_DEVICE_TYPE_CONTACT: {
154 deviceType = DEVICE_ID_NEOCONTACT;
155 deviceTypeUID = THING_TYPE_NEOCONTACT;
158 case HEATMISER_DEVICE_TYPE_PLUG: {
159 deviceType = DEVICE_ID_NEOPLUG;
160 deviceTypeUID = THING_TYPE_NEOPLUG;
163 case HEATMISER_DEVICE_TYPE_TEMPERATURE_SENSOR: {
164 deviceType = DEVICE_ID_NEOTEMPERATURESENSOR;
165 deviceTypeUID = THING_TYPE_NEOTEMPERATURESENSOR;
168 // all other device types are assumed to be thermostats
170 deviceType = DEVICE_ID_NEOSTAT;
171 deviceTypeUID = THING_TYPE_NEOSTAT;
175 deviceNeohubName = device.getDeviceName();
176 deviceOpenHabId = deviceNeohubName.replaceAll("\\s+", "_");
177 deviceUID = new ThingUID(deviceTypeUID, bridgeUID, deviceOpenHabId);
179 discoveredDevice = DiscoveryResultBuilder.create(deviceUID).withBridge(bridgeUID).withLabel(deviceOpenHabId)
180 .withProperty(DEVICE_NAME, deviceNeohubName).withRepresentationProperty(DEVICE_NAME).build();
182 thingDiscovered(discoveredDevice);
184 logger.debug("discovered device: id={}, type={}, name={} ..", deviceId, deviceType, deviceOpenHabId);