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 * @param bridgeHandler
62 public TapoDiscoveryService() {
63 super(SUPPORTED_THING_TYPES_UIDS, TAPO_DISCOVERY_TIMEOUT_S, false);
70 public void activate() {
71 TapoBridgeConfiguration config = bridge.getBridgeConfig();
72 if (config.cloudDiscovery || config.udpDiscovery) {
73 startBackgroundDiscovery();
81 public void deactivate() {
86 public void setThingHandler(@Nullable ThingHandler handler) {
87 if (handler instanceof TapoBridgeHandler) {
88 TapoBridgeHandler tapoBridge = (TapoBridgeHandler) handler;
89 tapoBridge.setDiscoveryService(this);
90 this.bridge = tapoBridge;
95 public @Nullable ThingHandler getThingHandler() {
99 /***********************************
103 ************************************/
106 * Start scan manually
109 public void startScan() {
110 removeOlderResults(getTimestampOfLastScan());
111 if (bridge != null) {
112 JsonArray jsonArray = bridge.getDeviceList();
113 handleCloudDevices(jsonArray);
117 /***********************************
121 ************************************/
124 * CREATE DISCOVERY RESULT
125 * creates discoveryResult (Thing) from JsonObject got from Cloud
127 * @param device JsonObject with device information
128 * @return DiscoveryResult-Object
130 public DiscoveryResult createResult(JsonObject device) {
131 TapoBridgeHandler tapoBridge = this.bridge;
132 String deviceModel = getDeviceModel(device);
133 String label = getDeviceLabel(device);
134 String deviceMAC = device.get(CLOUD_JSON_KEY_MAC).getAsString();
135 ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel);
137 /* create properties */
138 Map<String, Object> properties = new HashMap<>();
139 properties.put(Thing.PROPERTY_VENDOR, DEVICE_VENDOR);
140 properties.put(Thing.PROPERTY_MAC_ADDRESS, formatMac(deviceMAC, MAC_DIVISION_CHAR));
141 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.get(CLOUD_JSON_KEY_FW).getAsString());
142 properties.put(Thing.PROPERTY_HARDWARE_VERSION, device.get(CLOUD_JSON_KEY_HW).getAsString());
143 properties.put(Thing.PROPERTY_MODEL_ID, deviceModel);
144 properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.get(CLOUD_JSON_KEY_ID).getAsString());
146 logger.debug("device {} discovered", deviceModel);
147 if (tapoBridge != null) {
148 ThingUID bridgeUID = tapoBridge.getUID();
149 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, deviceMAC);
150 return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
151 .withRepresentationProperty(DEVICE_REPRESENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label)
154 ThingUID thingUID = new ThingUID(BINDING_ID, deviceMAC);
155 return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
156 .withRepresentationProperty(DEVICE_REPRESENTATION_PROPERTY).withLabel(label).build();
161 * work with result from get devices from cloud devices
165 protected void handleCloudDevices(JsonArray deviceList) {
167 for (JsonElement deviceElement : deviceList) {
168 if (deviceElement.isJsonObject()) {
169 JsonObject device = deviceElement.getAsJsonObject();
170 String deviceModel = getDeviceModel(device);
171 ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel);
174 if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
175 DiscoveryResult discoveryResult = createResult(device);
176 thingDiscovered(discoveryResult);
180 } catch (Exception e) {
181 logger.debug("error handlling CloudDevices", e);
188 * @param device JsonObject with deviceData
189 * @return String with DeviceModel
191 protected String getDeviceModel(JsonObject device) {
193 String deviceModel = device.get(CLOUD_JSON_KEY_MODEL).getAsString();
194 deviceModel = deviceModel.replaceAll("\\(.*\\)", ""); // replace (DE)
195 deviceModel = deviceModel.replace("Tapo", "");
196 deviceModel = deviceModel.replace("Series", "");
197 deviceModel = deviceModel.trim();
198 deviceModel = deviceModel.replace(" ", "_");
200 } catch (Exception e) {
201 logger.debug("error getDeviceModel", e);
209 * @param device JsonObject with deviceData
210 * @return String with DeviceLabel
212 protected String getDeviceLabel(JsonObject device) {
214 String deviceLabel = "";
215 String deviceModel = getDeviceModel(device);
216 ThingTypeUID deviceUID = new ThingTypeUID(BINDING_ID, deviceModel);
218 if (SUPPORTED_SMART_PLUG_UIDS.contains(deviceUID)) {
219 deviceLabel = DEVICE_DESCRIPTION_SMART_PLUG;
220 } else if (SUPPORTED_WHITE_BULB_UIDS.contains(deviceUID)) {
221 deviceLabel = DEVICE_DESCRIPTION_WHITE_BULB;
222 } else if (SUPPORTED_COLOR_BULB_UIDS.contains(deviceUID)) {
223 deviceLabel = DEVICE_DESCRIPTION_COLOR_BULB;
225 return DEVICE_VENDOR + " " + deviceModel + " " + deviceLabel;
226 } catch (Exception e) {
227 logger.debug("error getDeviceLabel", e);