2 * Copyright (c) 2010-2021 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.nest.internal.discovery;
15 import static org.openhab.binding.nest.internal.NestBindingConstants.*;
16 import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION;
18 import java.util.HashMap;
19 import java.util.List;
22 import java.util.function.BiConsumer;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.openhab.binding.nest.internal.config.NestDeviceConfiguration;
28 import org.openhab.binding.nest.internal.config.NestStructureConfiguration;
29 import org.openhab.binding.nest.internal.data.BaseNestDevice;
30 import org.openhab.binding.nest.internal.data.Camera;
31 import org.openhab.binding.nest.internal.data.SmokeDetector;
32 import org.openhab.binding.nest.internal.data.Structure;
33 import org.openhab.binding.nest.internal.data.Thermostat;
34 import org.openhab.binding.nest.internal.handler.NestBridgeHandler;
35 import org.openhab.binding.nest.internal.listener.NestThingDataListener;
36 import org.openhab.core.config.discovery.AbstractDiscoveryService;
37 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.thing.ThingUID;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * This service connects to the Nest bridge and creates the correct discovery results for Nest devices
45 * as they are found through the API.
47 * @author David Bennett - Initial contribution
48 * @author Wouter Born - Add representation properties
51 public class NestDiscoveryService extends AbstractDiscoveryService {
53 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
54 .of(THING_TYPE_CAMERA, THING_TYPE_THERMOSTAT, THING_TYPE_SMOKE_DETECTOR, THING_TYPE_STRUCTURE)
55 .collect(Collectors.toSet());
57 private final Logger logger = LoggerFactory.getLogger(NestDiscoveryService.class);
59 private final DiscoveryDataListener<Camera> cameraDiscoveryDataListener = new DiscoveryDataListener<>(Camera.class,
60 THING_TYPE_CAMERA, this::addDeviceDiscoveryResult);
61 private final DiscoveryDataListener<SmokeDetector> smokeDetectorDiscoveryDataListener = new DiscoveryDataListener<>(
62 SmokeDetector.class, THING_TYPE_SMOKE_DETECTOR, this::addDeviceDiscoveryResult);
63 private final DiscoveryDataListener<Structure> structureDiscoveryDataListener = new DiscoveryDataListener<>(
64 Structure.class, THING_TYPE_STRUCTURE, this::addStructureDiscoveryResult);
65 private final DiscoveryDataListener<Thermostat> thermostatDiscoveryDataListener = new DiscoveryDataListener<>(
66 Thermostat.class, THING_TYPE_THERMOSTAT, this::addDeviceDiscoveryResult);
68 @SuppressWarnings("rawtypes")
69 private final List<DiscoveryDataListener> discoveryDataListeners = Stream.of(cameraDiscoveryDataListener,
70 smokeDetectorDiscoveryDataListener, structureDiscoveryDataListener, thermostatDiscoveryDataListener)
71 .collect(Collectors.toList());
73 private final NestBridgeHandler bridge;
75 private static class DiscoveryDataListener<T> implements NestThingDataListener<T> {
76 private Class<T> dataClass;
77 private ThingTypeUID thingTypeUID;
78 private BiConsumer<T, ThingTypeUID> onDiscovered;
80 private DiscoveryDataListener(Class<T> dataClass, ThingTypeUID thingTypeUID,
81 BiConsumer<T, ThingTypeUID> onDiscovered) {
82 this.dataClass = dataClass;
83 this.thingTypeUID = thingTypeUID;
84 this.onDiscovered = onDiscovered;
88 public void onNewData(T data) {
89 onDiscovered.accept(data, thingTypeUID);
93 public void onUpdatedData(T oldData, T data) {
97 public void onMissingData(String nestId) {
101 public NestDiscoveryService(NestBridgeHandler bridge) {
102 super(SUPPORTED_THING_TYPES, 60, true);
103 this.bridge = bridge;
106 @SuppressWarnings("unchecked")
107 public void activate() {
108 discoveryDataListeners.forEach(l -> bridge.addThingDataListener(l.dataClass, l));
109 addDiscoveryResultsFromLastUpdates();
113 @SuppressWarnings("unchecked")
114 public void deactivate() {
115 discoveryDataListeners.forEach(l -> bridge.removeThingDataListener(l.dataClass, l));
119 protected void startScan() {
120 addDiscoveryResultsFromLastUpdates();
123 @SuppressWarnings("unchecked")
124 private void addDiscoveryResultsFromLastUpdates() {
125 discoveryDataListeners
126 .forEach(l -> addDiscoveryResultsFromLastUpdates(l.dataClass, l.thingTypeUID, l.onDiscovered));
129 private <T> void addDiscoveryResultsFromLastUpdates(Class<T> dataClass, ThingTypeUID thingTypeUID,
130 BiConsumer<T, ThingTypeUID> onDiscovered) {
131 List<T> lastUpdates = bridge.getLastUpdates(dataClass);
132 lastUpdates.forEach(lastUpdate -> onDiscovered.accept(lastUpdate, thingTypeUID));
135 private void addDeviceDiscoveryResult(BaseNestDevice device, ThingTypeUID typeUID) {
136 ThingUID bridgeUID = bridge.getThing().getUID();
137 ThingUID thingUID = new ThingUID(typeUID, bridgeUID, device.getDeviceId());
138 logger.debug("Discovered {}", thingUID);
139 Map<String, Object> properties = new HashMap<>();
140 properties.put(NestDeviceConfiguration.DEVICE_ID, device.getDeviceId());
141 properties.put(PROPERTY_FIRMWARE_VERSION, device.getSoftwareVersion());
143 thingDiscovered(DiscoveryResultBuilder.create(thingUID)
144 .withThingType(typeUID)
145 .withLabel(device.getNameLong())
146 .withBridge(bridgeUID)
147 .withProperties(properties)
148 .withRepresentationProperty(NestDeviceConfiguration.DEVICE_ID)
154 public void addStructureDiscoveryResult(Structure structure, ThingTypeUID typeUID) {
155 ThingUID bridgeUID = bridge.getThing().getUID();
156 ThingUID thingUID = new ThingUID(typeUID, bridgeUID, structure.getStructureId());
157 logger.debug("Discovered {}", thingUID);
158 Map<String, Object> properties = new HashMap<>();
159 properties.put(NestStructureConfiguration.STRUCTURE_ID, structure.getStructureId());
161 thingDiscovered(DiscoveryResultBuilder.create(thingUID)
162 .withThingType(THING_TYPE_STRUCTURE)
163 .withLabel(structure.getName())
164 .withBridge(bridgeUID)
165 .withProperties(properties)
166 .withRepresentationProperty(NestStructureConfiguration.STRUCTURE_ID)