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.surepetcare.internal.discovery;
15 import static org.openhab.binding.surepetcare.internal.SurePetcareConstants.*;
17 import java.util.HashMap;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDevice;
26 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDevice.ProductType;
27 import org.openhab.binding.surepetcare.internal.dto.SurePetcareHousehold;
28 import org.openhab.binding.surepetcare.internal.dto.SurePetcarePet;
29 import org.openhab.binding.surepetcare.internal.handler.SurePetcareBridgeHandler;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
32 import org.openhab.core.config.discovery.DiscoveryService;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.openhab.core.thing.binding.ThingHandler;
37 import org.openhab.core.thing.binding.ThingHandlerService;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * The {@link SurePetcareDiscoveryService} is an implementation of a discovery service for Sure Petcare pets and
45 * @author Rene Scherer - Initial contribution
48 public class SurePetcareDiscoveryService extends AbstractDiscoveryService
49 implements DiscoveryService, ThingHandlerService {
51 private final Logger logger = LoggerFactory.getLogger(SurePetcareDiscoveryService.class);
53 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
55 private static final int DISCOVER_TIMEOUT_SECONDS = 5;
56 private static final int DISCOVERY_SCAN_DELAY_MINUTES = 1;
57 private static final int DISCOVERY_REFRESH_INTERVAL_HOURS = 12;
59 private @Nullable ScheduledFuture<?> discoveryJob;
61 private @NonNullByDefault({}) SurePetcareBridgeHandler bridgeHandler;
62 private @NonNullByDefault({}) ThingUID bridgeUID;
65 * Creates a SurePetcareDiscoveryService with enabled autostart.
67 public SurePetcareDiscoveryService() {
68 super(SUPPORTED_THING_TYPES, DISCOVER_TIMEOUT_SECONDS);
72 public Set<ThingTypeUID> getSupportedThingTypes() {
73 return SUPPORTED_THING_TYPES;
77 public void activate() {
78 Map<String, Object> properties = new HashMap<>();
79 properties.put(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY, Boolean.TRUE);
80 super.activate(properties);
83 /* We override this method to allow a call from the thing handler factory */
85 public void deactivate() {
90 public void setThingHandler(@Nullable ThingHandler handler) {
91 if (handler instanceof SurePetcareBridgeHandler bridgeHandler) {
92 this.bridgeHandler = bridgeHandler;
93 bridgeUID = bridgeHandler.getUID();
98 public @Nullable ThingHandler getThingHandler() {
103 protected void startBackgroundDiscovery() {
104 logger.debug("Starting Sure Petcare household discovery");
105 stopBackgroundDiscovery();
106 discoveryJob = scheduler.scheduleWithFixedDelay(this::startScan, DISCOVERY_SCAN_DELAY_MINUTES,
107 DISCOVERY_REFRESH_INTERVAL_HOURS * 60, TimeUnit.MINUTES);
108 logger.debug("Scheduled topology-changed job every {} hours", DISCOVERY_REFRESH_INTERVAL_HOURS);
112 protected void stopBackgroundDiscovery() {
113 ScheduledFuture<?> job = discoveryJob;
117 logger.debug("Stopped Sure Petcare device background discovery");
122 protected void startScan() {
123 logger.debug("Starting Sure Petcare discovery scan");
124 // If the bridge is not online no other thing devices can be found, so no reason to scan at this moment.
125 removeOlderResults(getTimestampOfLastScan());
126 if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) {
127 logger.debug("Starting device discovery for bridge {}", bridgeUID);
128 bridgeHandler.listHouseholds().forEach(this::householdDiscovered);
129 bridgeHandler.listPets().forEach(this::petDiscovered);
130 bridgeHandler.listDevices().forEach(this::deviceDiscovered);
134 private void householdDiscovered(SurePetcareHousehold household) {
135 logger.debug("Discovered household: {}", household.name);
136 ThingUID thingsUID = new ThingUID(THING_TYPE_HOUSEHOLD, bridgeUID, household.id.toString());
137 Map<String, Object> properties = new HashMap<>(household.getThingProperties());
138 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(household.name).withProperties(properties)
139 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
142 private void petDiscovered(SurePetcarePet pet) {
143 logger.debug("Discovered pet: {}", pet.name);
144 ThingUID thingsUID = new ThingUID(THING_TYPE_PET, bridgeUID, pet.id.toString());
145 Map<String, Object> properties = new HashMap<>(pet.getThingProperties());
146 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(pet.name).withProperties(properties)
147 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
150 private void deviceDiscovered(SurePetcareDevice device) {
151 logger.debug("Discovered device: {}", device.name);
152 ThingTypeUID typeUID = null;
153 switch (ProductType.findByTypeId(device.productId)) {
155 typeUID = THING_TYPE_HUB_DEVICE;
158 typeUID = THING_TYPE_FLAP_DEVICE;
161 typeUID = THING_TYPE_FLAP_DEVICE;
164 typeUID = THING_TYPE_FEEDER_DEVICE;
170 ThingUID thingsUID = new ThingUID(typeUID, bridgeUID, device.id.toString());
171 Map<String, Object> properties = new HashMap<>(device.getThingProperties());
172 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(device.name).withProperties(properties)
173 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());