Skip to content

Commit

Permalink
[tapocontrol] Add Smart Switches S210 and S220 (#17927)
Browse files Browse the repository at this point in the history
* Tapo Smart Switches S210 and S220 added

Signed-off-by: mkmannmanny <[email protected]>
Signed-off-by: Manfred Krämer <[email protected]>
  • Loading branch information
mkmannmanny authored Dec 25, 2024
1 parent 0e5e48f commit 2f2cf22
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 17 deletions.
2 changes: 2 additions & 0 deletions bundles/org.openhab.binding.tapocontrol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ The following Tapo-Devices are supported. For precise channel-description look a
| Smart Contact Sensor (RF) | T110 | Window/Door Smart Contact Sensor |
| Smart Temperature Sensor (RF) | T310 | Temperature and Humidity Sensor |
| | T315 | Temperature and Humidity Sensor with Display |
| Smart Switch (RF) | S210 | Wall switch with 1 contact |
| Smart Switch (RF) | S220 | Wall switch with 2 contacts |

## Prerequisites

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.tapocontrol.internal.devices.bridge.TapoBridgeHandler;
import org.openhab.binding.tapocontrol.internal.devices.rf.smartcontact.TapoSmartContactHandler;
import org.openhab.binding.tapocontrol.internal.devices.rf.smartswitch.TapoSmartSwitchHandler;
import org.openhab.binding.tapocontrol.internal.devices.rf.weathersensor.TapoWeatherSensorHandler;
import org.openhab.binding.tapocontrol.internal.devices.wifi.TapoUniversalDeviceHandler;
import org.openhab.binding.tapocontrol.internal.devices.wifi.bulb.TapoBulbHandler;
Expand Down Expand Up @@ -130,6 +131,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return new TapoSmartContactHandler(thing);
} else if (SUPPORTED_WEATHER_SENSORS.contains(thingTypeUID)) {
return new TapoWeatherSensorHandler(thing);
} else if (SUPPORTED_SMART_SWITCHES.contains(thingTypeUID)) {
return new TapoSmartSwitchHandler(thing);
} else if (thingTypeUID.equals(UNIVERSAL_THING_TYPE)) {
return new TapoUniversalDeviceHandler(thing);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public class TapoThingConstants {
public static final String DEVICE_T110 = "T110";
public static final String DEVICE_T310 = "T310";
public static final String DEVICE_T315 = "T315";
public static final String DEVICE_S210 = "S210";
public static final String DEVICE_S220 = "S220";
public static final String DEVICE_UNIVERSAL = "Test_Device";

/*** LIST OF SUPPORTED DEVICE DESCRIPTIONS ***/
Expand All @@ -63,6 +65,7 @@ public class TapoThingConstants {
public static final String DEVICE_DESCRIPTION_SMART_CONTACT = "Smart-Contact-Sensor";
public static final String DEVICE_DESCRIPTION_MOTION_SENSOR = "Motion-Sensor";
public static final String DEVICE_DESCRIPTION_TEMP_SENSOR = "Temperature-Sensor";
public static final String DEVICE_DESCRIPTION_SMART_SWITCH = "Smart-Switch";

/*** LIST OF SUPPORTED THING UIDS ***/
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_BRIDGE);
Expand All @@ -85,6 +88,8 @@ public class TapoThingConstants {
public static final ThingTypeUID T110_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_T110);
public static final ThingTypeUID T310_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_T310);
public static final ThingTypeUID T315_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_T315);
public static final ThingTypeUID S210_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_S210);
public static final ThingTypeUID S220_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_S220);

/*** SET OF SUPPORTED UIDS ***/
public static final Set<ThingTypeUID> SUPPORTED_BRIDGE_UIDS = Set.of(BRIDGE_THING_TYPE);
Expand All @@ -97,27 +102,28 @@ public class TapoThingConstants {
public static final Set<ThingTypeUID> SUPPORTED_LIGHT_STRIP_UIDS = Set.of(L900_THING_TYPE, L920_THING_TYPE,
L930_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_HUB_CHILD_TYPES_UIDS = Set.of(T110_THING_TYPE, T310_THING_TYPE,
T315_THING_TYPE);
T315_THING_TYPE, S210_THING_TYPE, S220_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_SMART_CONTACTS = Set.of(T110_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_MOTION_SENSORS = Set.of();
public static final Set<ThingTypeUID> SUPPORTED_WEATHER_SENSORS = Set.of(T310_THING_TYPE, T315_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_SMART_SWITCHES = Set.of(S210_THING_TYPE, S220_THING_TYPE);

/*** SET OF ALL SUPPORTED THINGS ***/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
.of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_HUB_UIDS, SUPPORTED_SOCKET_UIDS, SUPPORTED_SOCKET_STRIP_UIDS,
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_HUB_UIDS, SUPPORTED_SOCKET_UIDS, SUPPORTED_SOCKET_STRIP_UIDS,
SUPPORTED_WHITE_BULB_UIDS, SUPPORTED_COLOR_BULB_UIDS, SUPPORTED_LIGHT_STRIP_UIDS,
SUPPORTED_SMART_CONTACTS, SUPPORTED_MOTION_SENSORS, SUPPORTED_WEATHER_SENSORS)
.flatMap(Set::stream).collect(Collectors.toSet()));
SUPPORTED_SMART_CONTACTS, SUPPORTED_MOTION_SENSORS, SUPPORTED_WEATHER_SENSORS,
SUPPORTED_SMART_SWITCHES).flatMap(Set::stream).collect(Collectors.toSet()));

/*** THINGS WITH ENERGY DATA ***/
public static final Set<ThingTypeUID> SUPPORTED_ENERGY_DATA_UIDS = Set.of(P110_THING_TYPE, P115_THING_TYPE);

/*** THINGS WITH CHANNEL GROUPS ***/
public static final Set<ThingTypeUID> CHANNEL_GROUP_THING_SET = Collections.unmodifiableSet(Stream
.of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_HUB_UIDS, SUPPORTED_SOCKET_UIDS, SUPPORTED_SOCKET_STRIP_UIDS,
public static final Set<ThingTypeUID> CHANNEL_GROUP_THING_SET = Collections.unmodifiableSet(
Stream.of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_HUB_UIDS, SUPPORTED_SOCKET_UIDS, SUPPORTED_SOCKET_STRIP_UIDS,
SUPPORTED_WHITE_BULB_UIDS, SUPPORTED_COLOR_BULB_UIDS, SUPPORTED_LIGHT_STRIP_UIDS,
SUPPORTED_SMART_CONTACTS, SUPPORTED_MOTION_SENSORS, SUPPORTED_WEATHER_SENSORS)
.flatMap(Set::stream).collect(Collectors.toSet()));
SUPPORTED_SMART_CONTACTS, SUPPORTED_MOTION_SENSORS, SUPPORTED_WEATHER_SENSORS,
SUPPORTED_SMART_SWITCHES).flatMap(Set::stream).collect(Collectors.toSet()));

public static final String CHILD_REPRESENTATION_PROPERTY = "serialNumber";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
*/
package org.openhab.binding.tapocontrol.internal.devices.rf;

import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorCode.*;
import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorCode.ERR_CONFIG_NO_BRIDGE;
import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TapoUtils.*;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TapoUtils.getValueOrDefault;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TypeUtils.*;

import java.util.HashMap;
Expand Down Expand Up @@ -48,7 +48,7 @@ public abstract class TapoChildDeviceHandler extends BaseThingHandler {
protected final String uid;
protected final String deviceId;
protected @NonNullByDefault({}) TapoHubHandler hub;
private TapoChildDeviceData deviceInfo = new TapoChildDeviceData();
protected TapoChildDeviceData deviceInfo = new TapoChildDeviceData();
private Map<String, Object> oldStates = new HashMap<>();

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2024 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.devices.rf.smartswitch;

import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TypeUtils.getOnOffType;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.tapocontrol.internal.devices.dto.TapoChildDeviceData;
import org.openhab.binding.tapocontrol.internal.devices.rf.TapoChildDeviceHandler;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* TAPO Smart-Contact-Device.
*
* @author Manfred Krämer - Initial contribution
*/

@NonNullByDefault
public class TapoSmartSwitchHandler extends TapoChildDeviceHandler {

private final Logger logger = LoggerFactory.getLogger(TapoSmartSwitchHandler.class);

/**
* Constructor
*
* @param thing Thing object representing device
*/
public TapoSmartSwitchHandler(Thing thing) {
super(thing);
}

/**
* Update properties
*/
@Override
protected void devicePropertiesChanged(TapoChildDeviceData deviceInfo) {
super.devicePropertiesChanged(deviceInfo);
updateState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_OUTPUT), getOnOffType(deviceInfo.isOn()));
}

/**
* handle command sent to device
*
* @param channelUID channelUID command is sent to
* @param command command to be sent
*/
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
/* perform actions */
if (command instanceof RefreshType) {
setDeviceData();
} else if (command instanceof OnOffType onOffCommand) {
deviceInfo.setDeviceOn(OnOffType.ON.equals(onOffCommand));

hub.sendCommandToChild(deviceInfo);
} else {
logger.warn("({}) command type '{}' not supported for channel '{}'", uid, command, channelUID.getId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public Collection<Class<? extends ThingHandlerService>> getServices() {

/**
* Set DiscoveryService
*
*
* @param discoveryService
*/
public void setDiscoveryService(TapoChildDiscoveryService discoveryService) {
Expand Down Expand Up @@ -140,7 +140,7 @@ public void queryDeviceData() {
/**
* Function called by {@link org.openhab.binding.tapocontrol.internal.api.TapoDeviceConnector} if new data were
* received
*
*
* @param queryCommand command where new data belong to
*/
@Override
Expand All @@ -165,6 +165,13 @@ public void newDataResult(String queryCommand) {
* CHILD THINGS
****************************/

/****************************
* Send Command to Child
*/
public void sendCommandToChild(TapoChildDeviceData childData) {
connector.sendChildCommand(childData, false);
}

/**
* Update all Child-Things
*/
Expand Down Expand Up @@ -276,7 +283,7 @@ public List<TapoChildDeviceData> getChildDevices() {

public TapoChildDeviceData getChild(String deviceSerial) {
List<TapoChildDeviceData> childDeviceList = tapoChildsList.getChildDeviceList();
for (int i = 0; i <= childDeviceList.size(); i++) {
for (int i = 0; i < childDeviceList.size(); i++) {
TapoChildDeviceData child = childDeviceList.get(i);
if (child.getDeviceId().equals(deviceSerial)) {
return child;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*;
import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TapoUtils.*;
import static org.openhab.binding.tapocontrol.internal.helpers.utils.TapoUtils.formatMac;

import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -55,7 +55,7 @@ public class TapoChildDiscoveryService extends AbstractDiscoveryService implemen

/**
* INIT CLASS
*
*
*/
public TapoChildDiscoveryService() {
super(SUPPORTED_HUB_CHILD_TYPES_UIDS, TAPO_DISCOVERY_TIMEOUT_S, false);
Expand Down Expand Up @@ -195,6 +195,8 @@ protected String getDeviceLabel(TapoChildDeviceData child) {
deviceLabel = DEVICE_DESCRIPTION_SMART_CONTACT;
} else if (SUPPORTED_MOTION_SENSORS.contains(deviceUID)) {
deviceLabel = DEVICE_DESCRIPTION_MOTION_SENSOR;
} else if (SUPPORTED_SMART_SWITCHES.contains(deviceUID)) {
deviceLabel = DEVICE_DESCRIPTION_SMART_SWITCH;
}
return DEVICE_VENDOR + " " + deviceModel + " " + deviceLabel;
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tapocontrol"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">

<!--S210 THING-TYPE (SMART SWITCH) -->
<thing-type id="S210">
<supported-bridge-type-refs>
<bridge-type-ref id="H100"/>
</supported-bridge-type-refs>

<label>S210 Smart Switch</label>
<description>Tapo Smart Switch</description>
<channel-groups>
<channel-group id="actuator" typeId="smartPlug"/>
<channel-group id="device" typeId="childDeviceState"/>
</channel-groups>
<representation-property>serialNumber</representation-property>
</thing-type>
</thing:thing-descriptions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tapocontrol"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">

<!--S220 THING-TYPE (SMART SWITCH) -->
<thing-type id="S220">
<supported-bridge-type-refs>
<bridge-type-ref id="H100"/>
</supported-bridge-type-refs>

<label>S220 Smart Switch</label>
<description>Tapo Smart Switch</description>
<channel-groups>
<channel-group id="actuator" typeId="smartPlug"/>
<channel-group id="device" typeId="childDeviceState"/>
</channel-groups>
<representation-property>serialNumber</representation-property>
</thing-type>
</thing:thing-descriptions>

0 comments on commit 2f2cf22

Please sign in to comment.