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.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 bridgeUID = bridgeHandler.getUID();
97 public @Nullable ThingHandler getThingHandler() {
102 protected void startBackgroundDiscovery() {
103 logger.debug("Starting Sure Petcare household discovery");
104 stopBackgroundDiscovery();
105 discoveryJob = scheduler.scheduleWithFixedDelay(this::startScan, DISCOVERY_SCAN_DELAY_MINUTES,
106 DISCOVERY_REFRESH_INTERVAL_HOURS * 60, TimeUnit.MINUTES);
107 logger.debug("Scheduled topology-changed job every {} hours", DISCOVERY_REFRESH_INTERVAL_HOURS);
111 protected void stopBackgroundDiscovery() {
112 ScheduledFuture<?> job = discoveryJob;
116 logger.debug("Stopped Sure Petcare device background discovery");
121 protected void startScan() {
122 logger.debug("Starting Sure Petcare discovery scan");
123 // If the bridge is not online no other thing devices can be found, so no reason to scan at this moment.
124 removeOlderResults(getTimestampOfLastScan());
125 if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) {
126 logger.debug("Starting device discovery for bridge {}", bridgeUID);
127 bridgeHandler.listHouseholds().forEach(this::householdDiscovered);
128 bridgeHandler.listPets().forEach(this::petDiscovered);
129 bridgeHandler.listDevices().forEach(this::deviceDiscovered);
133 private void householdDiscovered(SurePetcareHousehold household) {
134 logger.debug("Discovered household: {}", household.name);
135 ThingUID thingsUID = new ThingUID(THING_TYPE_HOUSEHOLD, bridgeUID, household.id.toString());
136 Map<String, Object> properties = new HashMap<>(household.getThingProperties());
137 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(household.name).withProperties(properties)
138 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
141 private void petDiscovered(SurePetcarePet pet) {
142 logger.debug("Discovered pet: {}", pet.name);
143 ThingUID thingsUID = new ThingUID(THING_TYPE_PET, bridgeUID, pet.id.toString());
144 Map<String, Object> properties = new HashMap<>(pet.getThingProperties());
145 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(pet.name).withProperties(properties)
146 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
149 private void deviceDiscovered(SurePetcareDevice device) {
150 logger.debug("Discovered device: {}", device.name);
151 ThingTypeUID typeUID = null;
152 switch (ProductType.findByTypeId(device.productId)) {
154 typeUID = THING_TYPE_HUB_DEVICE;
157 typeUID = THING_TYPE_FLAP_DEVICE;
160 typeUID = THING_TYPE_FLAP_DEVICE;
163 typeUID = THING_TYPE_FEEDER_DEVICE;
169 ThingUID thingsUID = new ThingUID(typeUID, bridgeUID, device.id.toString());
170 Map<String, Object> properties = new HashMap<>(device.getThingProperties());
171 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(device.name).withProperties(properties)
172 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());