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.tapocontrol.internal;
15 import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*;
16 import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
17 import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*;
19 import java.util.HashMap;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler;
25 import org.openhab.binding.tapocontrol.internal.structures.TapoBridgeConfiguration;
26 import org.openhab.core.config.discovery.AbstractDiscoveryService;
27 import org.openhab.core.config.discovery.DiscoveryResult;
28 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingTypeUID;
31 import org.openhab.core.thing.ThingUID;
32 import org.openhab.core.thing.binding.ThingHandler;
33 import org.openhab.core.thing.binding.ThingHandlerService;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import com.google.gson.JsonArray;
38 import com.google.gson.JsonElement;
39 import com.google.gson.JsonObject;
42 * Handler class for TAPO Smart Home thing discovery
44 * @author Christian Wild - Initial contribution
47 public class TapoDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
48 private final Logger logger = LoggerFactory.getLogger(TapoDiscoveryService.class);
49 protected @NonNullByDefault({}) TapoBridgeHandler bridge;
51 /***********************************
55 ************************************/
60 public TapoDiscoveryService() {
61 super(SUPPORTED_THING_TYPES_UIDS, TAPO_DISCOVERY_TIMEOUT_S, false);
68 public void activate() {
69 TapoBridgeConfiguration config = bridge.getBridgeConfig();
70 if (config.cloudDiscovery) {
71 startBackgroundDiscovery();
79 public void deactivate() {
84 public void setThingHandler(@Nullable ThingHandler handler) {
85 if (handler instanceof TapoBridgeHandler tapoBridge) {
86 tapoBridge.setDiscoveryService(this);
87 this.bridge = tapoBridge;
92 public @Nullable ThingHandler getThingHandler() {
96 /***********************************
100 ************************************/
103 * Start scan manually
106 public void startScan() {
107 removeOlderResults(getTimestampOfLastScan());
108 if (bridge != null) {
109 JsonArray jsonArray = bridge.getDeviceList();
110 handleCloudDevices(jsonArray);
114 /***********************************
118 ************************************/
121 * CREATE DISCOVERY RESULT
122 * creates discoveryResult (Thing) from JsonObject got from Cloud
124 * @param device JsonObject with device information
125 * @return DiscoveryResult-Object
127 public DiscoveryResult createResult(JsonObject device) {
128 TapoBridgeHandler tapoBridge = this.bridge;
129 String deviceModel = getDeviceModel(device);
130 String label = getDeviceLabel(device);
131 String deviceMAC = device.get(CLOUD_JSON_KEY_MAC).getAsString();
132 ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel);
134 /* create properties */
135 Map<String, Object> properties = new HashMap<>();
136 properties.put(Thing.PROPERTY_VENDOR, DEVICE_VENDOR);
137 properties.put(Thing.PROPERTY_MAC_ADDRESS, formatMac(deviceMAC, MAC_DIVISION_CHAR));
138 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.get(CLOUD_JSON_KEY_FW).getAsString());
139 properties.put(Thing.PROPERTY_HARDWARE_VERSION, device.get(CLOUD_JSON_KEY_HW).getAsString());
140 properties.put(Thing.PROPERTY_MODEL_ID, deviceModel);
141 properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.get(CLOUD_JSON_KEY_ID).getAsString());
143 logger.debug("device {} discovered", deviceModel);
144 if (tapoBridge != null) {
145 ThingUID bridgeUID = tapoBridge.getUID();
146 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, deviceMAC);
147 return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
148 .withRepresentationProperty(DEVICE_REPRESENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label)
151 ThingUID thingUID = new ThingUID(BINDING_ID, deviceMAC);
152 return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
153 .withRepresentationProperty(DEVICE_REPRESENTATION_PROPERTY).withLabel(label).build();
158 * work with result from get devices from cloud devices
162 protected void handleCloudDevices(JsonArray deviceList) {
164 for (JsonElement deviceElement : deviceList) {
165 if (deviceElement.isJsonObject()) {
166 JsonObject device = deviceElement.getAsJsonObject();
167 String deviceModel = getDeviceModel(device);
168 ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel);
171 if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
172 DiscoveryResult discoveryResult = createResult(device);
173 thingDiscovered(discoveryResult);
177 } catch (Exception e) {
178 logger.debug("error handling CloudDevices", e);
185 * @param device JsonObject with deviceData
186 * @return String with DeviceModel
188 protected String getDeviceModel(JsonObject device) {
190 String deviceModel = device.get(CLOUD_JSON_KEY_MODEL).getAsString();
191 deviceModel = deviceModel.replaceAll("\\(.*\\)", ""); // replace (DE)
192 deviceModel = deviceModel.replace("Tapo", "");
193 deviceModel = deviceModel.replace("Series", "");
194 deviceModel = deviceModel.trim();
195 deviceModel = deviceModel.replace(" ", "_");
197 } catch (Exception e) {
198 logger.debug("error getDeviceModel", e);
206 * @param device JsonObject with deviceData
207 * @return String with DeviceLabel
209 protected String getDeviceLabel(JsonObject device) {
211 String deviceLabel = "";
212 String deviceModel = getDeviceModel(device);
213 ThingTypeUID deviceUID = new ThingTypeUID(BINDING_ID, deviceModel);
215 if (SUPPORTED_SMART_PLUG_UIDS.contains(deviceUID)) {
216 deviceLabel = DEVICE_DESCRIPTION_SMART_PLUG;
217 } else if (SUPPORTED_WHITE_BULB_UIDS.contains(deviceUID)) {
218 deviceLabel = DEVICE_DESCRIPTION_WHITE_BULB;
219 } else if (SUPPORTED_COLOR_BULB_UIDS.contains(deviceUID)) {
220 deviceLabel = DEVICE_DESCRIPTION_COLOR_BULB;
222 return DEVICE_VENDOR + " " + deviceModel + " " + deviceLabel;
223 } catch (Exception e) {
224 logger.debug("error getDeviceLabel", e);