2 * Copyright (c) 2010-2024 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.ecobee.internal.discovery;
15 import static org.openhab.binding.ecobee.internal.EcobeeBindingConstants.*;
17 import java.util.HashMap;
18 import java.util.List;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.ecobee.internal.dto.thermostat.RemoteSensorDTO;
27 import org.openhab.binding.ecobee.internal.dto.thermostat.ThermostatDTO;
28 import org.openhab.binding.ecobee.internal.handler.EcobeeAccountBridgeHandler;
29 import org.openhab.binding.ecobee.internal.handler.EcobeeThermostatBridgeHandler;
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.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingTypeUID;
36 import org.openhab.core.thing.ThingUID;
37 import org.openhab.core.thing.binding.ThingHandler;
38 import org.openhab.core.thing.binding.ThingHandlerService;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * The {@link EcobeeDiscoveryService} is responsible for discovering the Ecobee
44 * thermostats that are associated with the Ecobee Account, as well as the sensors
45 * are associated with the Ecobee thermostats.
47 * @author Mark Hilbush - Initial contribution
50 public class EcobeeDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
52 private final Logger logger = LoggerFactory.getLogger(EcobeeDiscoveryService.class);
54 private @NonNullByDefault({}) EcobeeAccountBridgeHandler bridgeHandler;
56 private @Nullable Future<?> discoveryJob;
58 public EcobeeDiscoveryService() {
59 super(SUPPORTED_THERMOSTAT_AND_SENSOR_THING_TYPES_UIDS, 8, true);
63 public void setThingHandler(@Nullable ThingHandler handler) {
64 if (handler instanceof EcobeeAccountBridgeHandler accountBridgeHandler) {
65 this.bridgeHandler = accountBridgeHandler;
70 public @Nullable ThingHandler getThingHandler() {
75 public void activate() {
80 public void deactivate() {
85 public Set<ThingTypeUID> getSupportedThingTypes() {
86 return SUPPORTED_THERMOSTAT_AND_SENSOR_THING_TYPES_UIDS;
90 protected void startBackgroundDiscovery() {
91 logger.debug("EcobeeDiscovery: Starting background discovery job");
92 Future<?> localDiscoveryJob = discoveryJob;
93 if (localDiscoveryJob == null || localDiscoveryJob.isCancelled()) {
94 discoveryJob = scheduler.scheduleWithFixedDelay(this::backgroundDiscover, DISCOVERY_INITIAL_DELAY_SECONDS,
95 DISCOVERY_INTERVAL_SECONDS, TimeUnit.SECONDS);
100 protected void stopBackgroundDiscovery() {
101 logger.debug("EcobeeDiscovery: Stopping background discovery job");
102 Future<?> localDiscoveryJob = discoveryJob;
103 if (localDiscoveryJob != null) {
104 localDiscoveryJob.cancel(true);
110 public void startScan() {
111 logger.debug("EcobeeDiscovery: Starting discovery scan");
115 private void backgroundDiscover() {
116 if (!bridgeHandler.isBackgroundDiscoveryEnabled()) {
122 private void discover() {
123 if (bridgeHandler.getThing().getStatus() != ThingStatus.ONLINE) {
124 logger.debug("EcobeeDiscovery: Skipping discovery because Account Bridge thing is not ONLINE");
127 logger.debug("EcobeeDiscovery: Discovering Ecobee devices");
128 discoverThermostats();
132 private synchronized void discoverThermostats() {
133 logger.debug("EcobeeDiscovery: Discovering thermostats");
134 for (ThermostatDTO thermostat : bridgeHandler.getRegisteredThermostats()) {
135 String name = thermostat.name;
136 String identifier = thermostat.identifier;
137 if (identifier != null && name != null) {
138 ThingUID thingUID = new ThingUID(UID_THERMOSTAT_BRIDGE, bridgeHandler.getThing().getUID(), identifier);
139 thingDiscovered(createThermostatDiscoveryResult(thingUID, identifier, name));
140 logger.debug("EcobeeDiscovery: Thermostat '{}' and name '{}' added with UID '{}'", identifier, name,
146 private DiscoveryResult createThermostatDiscoveryResult(ThingUID thermostatUID, String identifier, String name) {
147 Map<String, Object> properties = new HashMap<>();
148 properties.put(CONFIG_THERMOSTAT_ID, identifier);
149 return DiscoveryResultBuilder.create(thermostatUID).withProperties(properties)
150 .withRepresentationProperty(CONFIG_THERMOSTAT_ID).withBridge(bridgeHandler.getThing().getUID())
151 .withLabel(String.format("Ecobee Thermostat %s", name)).build();
154 private synchronized void discoverSensors() {
155 List<Thing> thermostatThings = bridgeHandler.getThing().getThings();
156 if (thermostatThings.isEmpty()) {
157 logger.debug("EcobeeDiscovery: Skipping sensor discovery because there are no thermostat things");
160 logger.debug("EcobeeDiscovery: Discovering sensors");
161 for (Thing thermostat : thermostatThings) {
162 EcobeeThermostatBridgeHandler thermostatHandler = (EcobeeThermostatBridgeHandler) thermostat.getHandler();
163 if (thermostatHandler != null) {
164 String thermostatId = thermostatHandler.getThermostatId();
165 logger.debug("EcobeeDiscovery: Discovering sensors for thermostat '{}'", thermostatId);
166 for (RemoteSensorDTO sensor : thermostatHandler.getSensors()) {
167 ThingUID bridgeUID = thermostatHandler.getThing().getUID();
168 ThingUID sensorUID = new ThingUID(UID_SENSOR_THING, bridgeUID, sensor.id.replace(":", "-"));
169 thingDiscovered(createSensorDiscoveryResult(sensorUID, bridgeUID, sensor));
170 logger.debug("EcobeeDiscovery: Sensor for '{}' with id '{}' and name '{}' added with UID '{}'",
171 thermostatId, sensor.id, sensor.name, sensorUID);
177 private DiscoveryResult createSensorDiscoveryResult(ThingUID sensorUID, ThingUID bridgeUID,
178 RemoteSensorDTO sensor) {
179 Map<String, Object> properties = new HashMap<>();
180 properties.put(CONFIG_SENSOR_ID, sensor.id);
181 return DiscoveryResultBuilder.create(sensorUID).withProperties(properties)
182 .withRepresentationProperty(CONFIG_SENSOR_ID).withBridge(bridgeUID)
183 .withLabel(String.format("Ecobee Sensor %s", sensor.name)).build();