From 8d28085226ac74dc8182d412faa6cb5b61badd96 Mon Sep 17 00:00:00 2001 From: Christian Wild <40909464+wildcs@users.noreply.github.com> Date: Sat, 10 Dec 2022 16:53:30 +0100 Subject: [PATCH] [tapocontrol] add L610, L630 Spot and L930 LightStrip (#13814) * fix color change bug* Signed-off-by: Christian Wild --- .../org.openhab.binding.tapocontrol/README.md | 80 +++++-------- .../internal/TapoDiscoveryService.java | 4 +- .../constants/TapoThingConstants.java | 13 ++- .../internal/device/TapoBridgeHandler.java | 2 + .../internal/device/TapoSmartBulb.java | 6 +- .../OH-INF/i18n/tapocontrol.properties | 8 ++ .../src/main/resources/OH-INF/thing/L610.xml | 23 ++++ .../src/main/resources/OH-INF/thing/L630.xml | 23 ++++ .../src/main/resources/OH-INF/thing/L930.xml | 23 ++++ .../main/resources/OH-INF/thing/channels.xml | 12 +- .../internal}/TapoDiscoveryService.java | 2 +- .../internal/discovery/TapoMDNS.java | 107 ++++++++++++++++++ .../internal/{api => discovery}/TapoUDP.java | 0 13 files changed, 239 insertions(+), 64 deletions(-) create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L610.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L630.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L930.xml rename bundles/org.openhab.binding.tapocontrol/src/test/{ => java/org/openhab/binding/tapocontrol/internal}/TapoDiscoveryService.java (99%) create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoMDNS.java rename bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/{api => discovery}/TapoUDP.java (100%) diff --git a/bundles/org.openhab.binding.tapocontrol/README.md b/bundles/org.openhab.binding.tapocontrol/README.md index 562c0f66a1..4df37cd098 100644 --- a/bundles/org.openhab.binding.tapocontrol/README.md +++ b/bundles/org.openhab.binding.tapocontrol/README.md @@ -4,49 +4,21 @@ This binding adds support to control Tapo (Copyright © TP-Link Corporation Limi ## Supported Things -The following Tapo-Devices are supported - -### P100/P105 SmartPlug (Wi-Fi) - -* Power On/Off -* Wi-Fi signal (SignalStrength) -* On-Time (Time in seconds device is switched on) - -### P110/P115 EnergyMonitoring SmartPlug (Wi-Fi) - -* Power On/Off -* Wi-Fi signal (SignalStrength) -* On-Time (Time in seconds device is switched on) -* actual PowerUsage (Watt) -* today EnergyUsage (Wh) -* today Runtime (Time in seconds device was on today) - -### L510(Series) dimmable SmartBulb (Wi-Fi) - -* Light On/Off -* Brightnes (Dimmer) 0-100 % -* ColorTemperature (Number) 2500-6500 K -* Wi-Fi signal (SignalStrength) -* On-Time (Time in seconds device is switched on) - -### L530(Series) MultiColor SmartBulb (Wi-Fi) - -* Light On/Off -* Brightnes (Dimmer) 0-100 % -* ColorTemperature (Number) 2500-6500 K -* Color (Color) -* Wi-Fi signal (SignalStrength) -* On-Time (Time in seconds device is switched on) - -### L900/L920 LED-LightStrip (Wi-Fi) - -* Light On/Off -* Brightnes (Dimmer) 0-100 % -* ColorTemperature (Number) 2500-6500 K -* Color (Color) -* Wi-Fi signal (SignalStrength) -* On-Time (Time in seconds device is switched on) - +The following Tapo-Devices are supported. For precise channel-description look at `channels-table` below + +| DeviceType | ThingType | Description | +|------------------------------------|-------------|---------------------------------------------| +| SmartPlug (Wi-Fi) | P100 | Smart Socket | +| | P105 | Smart Mini Socket | +| EnergyMonitoring SmartPlug (Wi-Fi) | P110 | Energy Monitoring Smart Socket | +| | P115 | Energy Monitoring Mini Smart Socket | +| Dimmable SmartBulb (Wi-Fi) | L510 | Dimmable White-Light Smart-Bulb (E27) | +| | L610 | Dimmable White-Light Smart-Spot (GU10) | +| MultiColor SmartBulb (Wi-Fi) | L530 | Multicolor Smart-Bulb (E27) | +| | L630 | Multicolor Smart-Spot (GU10) | +| MultiColor LightStrip (Wi-Fi) | L900 | Multicolor RGB Dimmable LightStrip (5m) | +| | L920 | Multicolor RGB-IC ColorZone LightStrip (5m) | +| | L930 | Multicolor RGBW-IC 50-Zone LightStrip (5m) | ## Prerequisites @@ -91,17 +63,17 @@ The thing has the following configuration parameters: All devices support some of the following channels: -| group | channel |type | description | things supporting this channel | -|-----------|----------------- |------------------------|------------------------------|------------------------------------------------| -| actuator | output | Switch | Power device on or off | P100, P105, P110, P115, L510, L530, L900, L920 | -| | brightness | Dimmer | Brightness 0-100% | L510, L530, L900 | -| | colorTemperature | Number | White-Color-Temp 2500-6500K | L510, L530, L900 | -| | color | Color | Color | L530, L900 | -| device | wifiSignal | system.signal-strength | WiFi-quality-level | P100, P105, P110, P115, L510, L530, L900, L920 | -| | onTime | Number:Time | seconds output is on | P100, P105, P110, P115, L510, L530, L900, L920 | -| energy | actualPower | Number:Power | actual Power (Watt) | P110, P115 | -| | todayEnergyUsage | Number:Energy | used energy today (Wh) | P110, P115 | -| | todayRuntime | Number:Time | seconds output was on today | P110, P115 | +| group | channel | type | description | things supporting this channel | +|-----------|----------------- |------------------------|------------------------------|------------------------------------------------------------------| +| actuator | output | Switch | Power device on or off | P100, P105, P110, P115, L510, L530, L610, L630, L900, L920, L930 | +| | brightness | Dimmer | Brightness 0-100% | L510, L530, L610, L630, L900 | +| | colorTemperature | Number | White-Color-Temp 2500-6500K | L510, L530, L610, L630, L900 | +| | color | Color | Color | L530, L630, L900 | +| device | wifiSignal | Number | WiFi-quality-level | P100, P105, P110, P115, L510, L530, L610, L630, L900, L920, L930 | +| | onTime | Number:Time | seconds output is on | P100, P105, P110, P115, L510, L530, L900, L920, L930 | +| energy | actualPower | Number:Power | actual Power (Watt) | P110, P115 | +| | todayEnergyUsage | Number:Energy | used energy today (Wh) | P110, P115 | +| | todayRuntime | Number:Time | seconds output was on today | P110, P115 | ## Channel Refresh diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java index f13bfc7f70..0e465af8c0 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java @@ -64,7 +64,7 @@ public class TapoDiscoveryService extends AbstractDiscoveryService implements Th } /** - * deactivate + * activate */ @Override public void activate() { @@ -178,7 +178,7 @@ public class TapoDiscoveryService extends AbstractDiscoveryService implements Th } } } catch (Exception e) { - logger.debug("error handlling CloudDevices", e); + logger.debug("error handling CloudDevices", e); } } diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java index b2422668ea..60f2ec9009 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java @@ -40,8 +40,11 @@ public class TapoThingConstants { public static final String DEVICE_P115 = "P115"; public static final String DEVICE_L510 = "L510"; public static final String DEVICE_L530 = "L530"; + public static final String DEVICE_L610 = "L610"; + public static final String DEVICE_L630 = "L630"; public static final String DEVICE_L900 = "L900"; public static final String DEVICE_L920 = "L920"; + public static final String DEVICE_L930 = "L930"; public static final String DEVICE_UNIVERSAL = "Test_Device"; /*** LIST OF SUPPORTED DEVICE DESCRIPTIONS ***/ @@ -59,17 +62,21 @@ public class TapoThingConstants { public static final ThingTypeUID P115_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_P115); public static final ThingTypeUID L510_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L510); public static final ThingTypeUID L530_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L530); + public static final ThingTypeUID L610_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L610); + public static final ThingTypeUID L630_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L630); public static final ThingTypeUID L900_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L900); public static final ThingTypeUID L920_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L920); + public static final ThingTypeUID L930_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L930); public static final ThingTypeUID UNIVERSAL_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_UNIVERSAL); /*** SET OF SUPPORTED UIDS ***/ public static final Set SUPPORTED_BRIDGE_UIDS = Set.of(BRIDGE_THING_TYPE); public static final Set SUPPORTED_SMART_PLUG_UIDS = Set.of(P100_THING_TYPE, P105_THING_TYPE, P110_THING_TYPE, P115_THING_TYPE); - public static final Set SUPPORTED_WHITE_BULB_UIDS = Set.of(L510_THING_TYPE); - public static final Set SUPPORTED_COLOR_BULB_UIDS = Set.of(L530_THING_TYPE); - public static final Set SUPPORTED_LIGHT_STRIP_UIDS = Set.of(L900_THING_TYPE, L920_THING_TYPE); + public static final Set SUPPORTED_WHITE_BULB_UIDS = Set.of(L510_THING_TYPE, L610_THING_TYPE); + public static final Set SUPPORTED_COLOR_BULB_UIDS = Set.of(L530_THING_TYPE, L630_THING_TYPE); + public static final Set SUPPORTED_LIGHT_STRIP_UIDS = Set.of(L900_THING_TYPE, L920_THING_TYPE, + L930_THING_TYPE); public static final Set SUPPORTED_THING_TYPES_UIDS = Collections .unmodifiableSet(Stream .of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_SMART_PLUG_UIDS, SUPPORTED_WHITE_BULB_UIDS, diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java index 832f1dfdf1..2f7296b074 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java @@ -259,6 +259,8 @@ public class TapoBridgeHandler extends BaseBridgeHandler { if (config.cloudDiscovery) { logger.trace("{} discover devicelist from cloud", this.uid); deviceList = getDeviceListCloud(); + } else { + logger.info("{} Discovery disabled in bridge settings ", this.uid); } return deviceList; } diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java index 985c005144..dd73822472 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java @@ -127,9 +127,9 @@ public class TapoSmartBulb extends TapoDevice { protected void setColor(HSBType command) { HashMap newState = new HashMap<>(); newState.put(DEVICE_PROPERTY_ON, true); - newState.put(DEVICE_PROPERTY_HUE, command.getHue()); - newState.put(DEVICE_PROPERTY_SATURATION, command.getSaturation()); - newState.put(DEVICE_PROPERTY_BRIGHTNES, command.getBrightness()); + newState.put(DEVICE_PROPERTY_HUE, command.getHue().intValue()); + newState.put(DEVICE_PROPERTY_SATURATION, command.getSaturation().intValue()); + newState.put(DEVICE_PROPERTY_BRIGHTNES, command.getBrightness().intValue()); connector.sendDeviceCommands(newState); } diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties index 2dc9379b14..1fc39a16f3 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties @@ -9,10 +9,16 @@ thing-type.tapocontrol.L510.label = L510 Series White-Bulb thing-type.tapocontrol.L510.description = Tapo Smart dimmable White-Light-Bulb thing-type.tapocontrol.L530.label = L530 Series Color-Bulb thing-type.tapocontrol.L530.description = Tapo Smart Multicolor Light-Bulb +thing-type.tapocontrol.L610.label = L610 Series White-Spot +thing-type.tapocontrol.L610.description = Tapo Smart dimmable White-Light-Spot +thing-type.tapocontrol.L630.label = L630 Series Color-Spot +thing-type.tapocontrol.L630.description = Tapo Smart Multicolor Light-Spot thing-type.tapocontrol.L900.label = L900 LightStrip thing-type.tapocontrol.L900.description = Tapo Smart LED-Lightstrip thing-type.tapocontrol.L920.label = L920 LightStrip thing-type.tapocontrol.L920.description = Tapo Smart Multicolor LED-Lightstrip +thing-type.tapocontrol.L930.label = L930 LightStrip +thing-type.tapocontrol.L930.description = Tapo Smart Multicolor LED-Lightstrip with ZoneControl thing-type.tapocontrol.P100.label = P100 SmartPlug thing-type.tapocontrol.P100.description = Tapo Smart Wifi Plug thing-type.tapocontrol.P105.label = P105 SmartPlug @@ -44,6 +50,8 @@ channel-group-type.tapocontrol.colorBulb.label = Color Light Bulb channel-group-type.tapocontrol.colorBulb.description = Tapo Multicolor Smart Light Bulb channel-group-type.tapocontrol.deviceState.label = Device State channel-group-type.tapocontrol.deviceState.description = Information about the device +channel-group-type.tapocontrol.deviceStateS.label = Device State +channel-group-type.tapocontrol.deviceStateS.description = Information about the device channel-group-type.tapocontrol.energyMonitor.label = Energy Usage channel-group-type.tapocontrol.energyMonitor.description = Energy and Power usage channel-group-type.tapocontrol.lightBulb.label = Light Bulb diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L610.xml b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L610.xml new file mode 100644 index 0000000000..cc57394679 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L610.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + Tapo Smart dimmable White-Light-Spot + + + + + macAddress + + + + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L630.xml b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L630.xml new file mode 100644 index 0000000000..1108af0dd3 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L630.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + Tapo Smart Multicolor Light-Spot + + + + + macAddress + + + + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L930.xml b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L930.xml new file mode 100644 index 0000000000..2fe67041b7 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L930.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + Tapo Smart Multicolor LED-Lightstrip with ZoneControl + + + + + macAddress + + + + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/channels.xml index 04e6226dda..009179a5f4 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/channels.xml @@ -7,7 +7,7 @@ - + Information about the device @@ -18,6 +18,16 @@ + + + + Information about the device + + + + + + diff --git a/bundles/org.openhab.binding.tapocontrol/src/test/TapoDiscoveryService.java b/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java similarity index 99% rename from bundles/org.openhab.binding.tapocontrol/src/test/TapoDiscoveryService.java rename to bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java index 3c02a7c0d5..c2e9994711 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/test/TapoDiscoveryService.java +++ b/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java @@ -64,7 +64,7 @@ public class TapoDiscoveryService extends AbstractDiscoveryService implements Th } /** - * deactivate + * activate */ @Override public void activate() { diff --git a/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoMDNS.java b/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoMDNS.java new file mode 100644 index 0000000000..83fabceb0f --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoMDNS.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.api; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; + +import java.util.Dictionary; +import java.util.Set; + +import javax.jmdns.ServiceInfo; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Modified; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler class for TAPO Smart Home thing discovery over mDNS + * + * @author Christian Wild - Initial contribution + */ +@Component(configurationPid = "discovery.tapocontrol") +@NonNullByDefault +public class TapoMDNS implements MDNSDiscoveryParticipant { + private final Logger logger = LoggerFactory.getLogger(TapoMDNS.class); + private boolean isAutoDiscoveryEnabled = true; + + @Activate + protected void activate(ComponentContext componentContext) { + activateOrModifyService(componentContext); + } + + @Modified + protected void modified(ComponentContext componentContext) { + activateOrModifyService(componentContext); + } + + private void activateOrModifyService(ComponentContext componentContext) { + Dictionary properties = componentContext.getProperties(); + String autoDiscoveryPropertyValue = (String) properties + .get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY); + if (autoDiscoveryPropertyValue != null && !autoDiscoveryPropertyValue.isBlank()) { + isAutoDiscoveryEnabled = Boolean.valueOf(autoDiscoveryPropertyValue); + } + } + + @Override + public Set getSupportedThingTypeUIDs() { + return SUPPORTED_THING_TYPES_UIDS; + } + + @Override + public String getServiceType() { + return "NULL"; + } + + @Override + public @Nullable ThingUID getThingUID(ServiceInfo service) { + ThingTypeUID thingTypeUID = getThingType(service); + if (thingTypeUID != null) { + String id = service.getPropertyString(PROPERTY_FAMILY); // device id + return new ThingUID(thingTypeUID, id); + } + return null; + } + + private @Nullable ThingTypeUID getThingType(final ServiceInfo service) { + String model = service.getPropertyString(PROPERTY_FAMILY); // model + logger.debug("found Type: {}", model); + if (model == null) { + return null; + } + return L510_THING_TYPE; + } + + @Override + public @Nullable DiscoveryResult createResult(ServiceInfo service) { + if (isAutoDiscoveryEnabled) { + ThingUID uid = getThingUID(service); + if (uid != null) { + String host = service.getHostAddresses()[0]; + int port = service.getPort(); + logger.debug("device Found: {} {}", host, port); + } + } + return null; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/api/TapoUDP.java b/bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoUDP.java similarity index 100% rename from bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/api/TapoUDP.java rename to bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/discovery/TapoUDP.java -- 2.47.3