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.Collections;
18 import java.util.HashMap;
21 import java.util.concurrent.ScheduledFuture;
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.surepetcare.internal.dto.SurePetcareDevice;
27 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDevice.ProductType;
28 import org.openhab.binding.surepetcare.internal.dto.SurePetcareHousehold;
29 import org.openhab.binding.surepetcare.internal.dto.SurePetcarePet;
30 import org.openhab.binding.surepetcare.internal.handler.SurePetcareBridgeHandler;
31 import org.openhab.core.config.discovery.AbstractDiscoveryService;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.config.discovery.DiscoveryService;
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 SurePetcareDiscoveryService} is an implementation of a discovery service for Sure Petcare pets and
46 * @author Rene Scherer - Initial contribution
49 public class SurePetcareDiscoveryService extends AbstractDiscoveryService
50 implements DiscoveryService, ThingHandlerService {
52 private final Logger logger = LoggerFactory.getLogger(SurePetcareDiscoveryService.class);
54 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE);
56 private static final int DISCOVER_TIMEOUT_SECONDS = 5;
57 private static final int DISCOVERY_SCAN_DELAY_MINUTES = 1;
58 private static final int DISCOVERY_REFRESH_INTERVAL_HOURS = 12;
60 private @Nullable ScheduledFuture<?> discoveryJob;
62 private @NonNullByDefault({}) SurePetcareBridgeHandler bridgeHandler;
63 private @NonNullByDefault({}) ThingUID bridgeUID;
66 * Creates a SurePetcareDiscoveryService with enabled autostart.
68 public SurePetcareDiscoveryService() {
69 super(SUPPORTED_THING_TYPES, DISCOVER_TIMEOUT_SECONDS);
73 public Set<ThingTypeUID> getSupportedThingTypes() {
74 return SUPPORTED_THING_TYPES;
78 public void activate() {
79 Map<String, Object> properties = new HashMap<>();
80 properties.put(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY, Boolean.TRUE);
81 super.activate(properties);
84 /* We override this method to allow a call from the thing handler factory */
86 public void deactivate() {
91 public void setThingHandler(@Nullable ThingHandler handler) {
92 if (handler instanceof SurePetcareBridgeHandler) {
93 bridgeHandler = (SurePetcareBridgeHandler) handler;
94 bridgeUID = bridgeHandler.getUID();
99 public @Nullable ThingHandler getThingHandler() {
100 return bridgeHandler;
104 protected void startBackgroundDiscovery() {
105 logger.debug("Starting Sure Petcare household discovery");
106 stopBackgroundDiscovery();
107 discoveryJob = scheduler.scheduleWithFixedDelay(this::startScan, DISCOVERY_SCAN_DELAY_MINUTES,
108 DISCOVERY_REFRESH_INTERVAL_HOURS * 60, TimeUnit.MINUTES);
109 logger.debug("Scheduled topology-changed job every {} hours", DISCOVERY_REFRESH_INTERVAL_HOURS);
113 protected void stopBackgroundDiscovery() {
114 ScheduledFuture<?> job = discoveryJob;
118 logger.debug("Stopped Sure Petcare device background discovery");
123 protected void startScan() {
124 logger.debug("Starting Sure Petcare discovery scan");
125 // If the bridge is not online no other thing devices can be found, so no reason to scan at this moment.
126 removeOlderResults(getTimestampOfLastScan());
127 if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) {
128 logger.debug("Starting device discovery for bridge {}", bridgeUID);
129 bridgeHandler.listHouseholds().forEach(this::householdDiscovered);
130 bridgeHandler.listPets().forEach(this::petDiscovered);
131 bridgeHandler.listDevices().forEach(this::deviceDiscovered);
135 private void householdDiscovered(SurePetcareHousehold household) {
136 logger.debug("Discovered household: {}", household.name);
137 ThingUID thingsUID = new ThingUID(THING_TYPE_HOUSEHOLD, bridgeUID, household.id.toString());
138 Map<String, Object> properties = new HashMap<>(household.getThingProperties());
139 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(household.name).withProperties(properties)
140 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
143 private void petDiscovered(SurePetcarePet pet) {
144 logger.debug("Discovered pet: {}", pet.name);
145 ThingUID thingsUID = new ThingUID(THING_TYPE_PET, bridgeUID, pet.id.toString());
146 Map<String, Object> properties = new HashMap<>(pet.getThingProperties());
147 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(pet.name).withProperties(properties)
148 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());
151 private void deviceDiscovered(SurePetcareDevice device) {
152 logger.debug("Discovered device: {}", device.name);
153 ThingTypeUID typeUID = null;
154 switch (ProductType.findByTypeId(device.productId)) {
156 typeUID = THING_TYPE_HUB_DEVICE;
159 typeUID = THING_TYPE_FLAP_DEVICE;
162 typeUID = THING_TYPE_FLAP_DEVICE;
165 typeUID = THING_TYPE_FEEDER_DEVICE;
171 ThingUID thingsUID = new ThingUID(typeUID, bridgeUID, device.id.toString());
172 Map<String, Object> properties = new HashMap<>(device.getThingProperties());
173 thingDiscovered(DiscoveryResultBuilder.create(thingsUID).withLabel(device.name).withProperties(properties)
174 .withRepresentationProperty(PROPERTY_NAME_ID).withBridge(bridgeUID).build());