added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.tplinksmarthome-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-tplinksmarthome" description="TP-Link Smart Home Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.tplinksmarthome/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.GetRealtime;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.GetSysinfo;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.GsonUtil;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetBrightness;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetLedOff;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetRelayState;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetSwitchState;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightState;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightState.LightOnOff;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightState.LightStateBrightness;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightState.LightStateColor;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightState.LightStateColorTemperature;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightStateResponse;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Class to construct the tp-link json commands and convert retrieved results into data objects.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Rewritten to use gson to parse json
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Commands {
|
||||
|
||||
private static final String CONTEXT = "{\"context\":{\"child_ids\":[\"%s\"]},";
|
||||
private static final String SYSTEM_GET_SYSINFO = "\"system\":{\"get_sysinfo\":{}}";
|
||||
private static final String GET_SYSINFO = "{" + SYSTEM_GET_SYSINFO + "}";
|
||||
private static final String REALTIME = "\"emeter\":{\"get_realtime\":{}}";
|
||||
private static final String GET_REALTIME_AND_SYSINFO = "{" + SYSTEM_GET_SYSINFO + ", " + REALTIME + "}";
|
||||
private static final String GET_REALTIME_BULB_AND_SYSINFO = "{" + SYSTEM_GET_SYSINFO
|
||||
+ ", \"smartlife.iot.common.emeter\":{\"get_realtime\":{}}}";
|
||||
|
||||
private final Gson gson = GsonUtil.createGson();
|
||||
private final Gson gsonWithExpose = GsonUtil.createGsonWithExpose();
|
||||
|
||||
/**
|
||||
* Returns the json to get the energy and sys info data from the device.
|
||||
*
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public static String getRealtimeAndSysinfo() {
|
||||
return GET_REALTIME_AND_SYSINFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json to get the energy and sys info data from the bulb.
|
||||
*
|
||||
* @return The json string of the command to send to the bulb
|
||||
*/
|
||||
public static String getRealtimeBulbAndSysinfo() {
|
||||
return GET_REALTIME_BULB_AND_SYSINFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json to get the energy and sys info data from an outlet device.
|
||||
*
|
||||
* @param id optional id of the device
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public static String getRealtimeWithContext(String id) {
|
||||
return String.format(CONTEXT, id) + REALTIME + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response of the get_realtime command to the data object.
|
||||
*
|
||||
* @param realtimeResponse the json string
|
||||
* @return The data object containing the energy data from the json string
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
public Realtime getRealtimeResponse(String realtimeResponse) {
|
||||
GetRealtime getRealtime = gson.fromJson(realtimeResponse, GetRealtime.class);
|
||||
return getRealtime == null ? new Realtime() : getRealtime.getRealtime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json to get the sys info data from the device.
|
||||
*
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public static String getSysinfo() {
|
||||
return GET_SYSINFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response of the get_sysinfo command to the data object.
|
||||
*
|
||||
* @param getSysinfoReponse the json string
|
||||
* @return The data object containing the state data from the json string
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
public Sysinfo getSysinfoReponse(String getSysinfoReponse) {
|
||||
GetSysinfo getSysinfo = gson.fromJson(getSysinfoReponse, GetSysinfo.class);
|
||||
return getSysinfo == null ? new Sysinfo() : getSysinfo.getSysinfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_relay_state command to switch on or off.
|
||||
*
|
||||
* @param onOff the switch state to set
|
||||
* @param childId optional child id if multiple children are supported by a single device
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setRelayState(OnOffType onOff, @Nullable String childId) {
|
||||
SetRelayState relayState = new SetRelayState();
|
||||
relayState.setRelayState(onOff);
|
||||
if (childId != null) {
|
||||
relayState.setChildId(childId);
|
||||
}
|
||||
return gsonWithExpose.toJson(relayState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response of the set_relay_state command to the data object.
|
||||
*
|
||||
* @param relayStateResponse the json string
|
||||
* @return The data object containing the state data from the json string
|
||||
*/
|
||||
public @Nullable SetRelayState setRelayStateResponse(String relayStateResponse) {
|
||||
return gsonWithExpose.fromJson(relayStateResponse, SetRelayState.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_switch_state command to switch a dimmer on or off.
|
||||
*
|
||||
* @param onOff the switch state to set
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setSwitchState(OnOffType onOff) {
|
||||
SetSwitchState switchState = new SetSwitchState();
|
||||
switchState.setSwitchState(onOff);
|
||||
return gsonWithExpose.toJson(switchState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response of the set_switch_state command to the data object.
|
||||
*
|
||||
* @param switchStateResponse the json string
|
||||
* @return The data object containing the state data from the json string
|
||||
*/
|
||||
public @Nullable SetSwitchState setSwitchStateResponse(String switchStateResponse) {
|
||||
return gsonWithExpose.fromJson(switchStateResponse, SetSwitchState.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_brightness command to set the brightness value.
|
||||
*
|
||||
* @param brightness the brightness value to set
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setDimmerBrightness(int brightness) {
|
||||
SetBrightness setBrightness = new SetBrightness();
|
||||
setBrightness.setBrightness(brightness);
|
||||
return gsonWithExpose.toJson(setBrightness);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response of the set_brightness command to the data object.
|
||||
*
|
||||
* @param dimmerBrightnessResponse the json string
|
||||
* @return The data object containing the state data from the json string
|
||||
*/
|
||||
public @Nullable HasErrorResponse setDimmerBrightnessResponse(String dimmerBrightnessResponse) {
|
||||
return gsonWithExpose.fromJson(dimmerBrightnessResponse, SetBrightness.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_light_state command to switch a bulb on or off.
|
||||
*
|
||||
* @param onOff the switch state to set
|
||||
* @param transitionPeriod the transition period for the action to take place
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setLightState(OnOffType onOff, int transitionPeriod) {
|
||||
TransitionLightState transitionLightState = new TransitionLightState();
|
||||
LightOnOff lightState = new LightOnOff();
|
||||
lightState.setOnOff(onOff);
|
||||
lightState.setTransitionPeriod(transitionPeriod);
|
||||
transitionLightState.setLightState(lightState);
|
||||
return gson.toJson(transitionLightState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_led_off command to switch the led of the device on or off.
|
||||
*
|
||||
* @param onOff the led state to set
|
||||
* @param childId optional child id if multiple children are supported by a single device
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setLedOn(OnOffType onOff, @Nullable String childId) {
|
||||
SetLedOff sLOff = new SetLedOff();
|
||||
sLOff.setLed(onOff);
|
||||
if (childId != null) {
|
||||
sLOff.setChildId(childId);
|
||||
}
|
||||
return gsonWithExpose.toJson(sLOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response for the set_led_off command to the data object.
|
||||
*
|
||||
* @param setLedOnResponse the json string
|
||||
* @return The data object containing the data from the json string
|
||||
*/
|
||||
public @Nullable SetLedOff setLedOnResponse(String setLedOnResponse) {
|
||||
return gsonWithExpose.fromJson(setLedOnResponse, SetLedOff.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_light_State command to set the brightness.
|
||||
*
|
||||
* @param brightness the brightness value
|
||||
* @param transitionPeriod the transition period for the action to take place
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setBrightness(int brightness, int transitionPeriod) {
|
||||
TransitionLightState transitionLightState = new TransitionLightState();
|
||||
LightStateBrightness lightState = new LightStateBrightness();
|
||||
lightState.setOnOff(brightness == 0 ? OnOffType.OFF : OnOffType.ON);
|
||||
lightState.setBrightness(brightness);
|
||||
lightState.setTransitionPeriod(transitionPeriod);
|
||||
transitionLightState.setLightState(lightState);
|
||||
return gson.toJson(transitionLightState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_light_State command to set the color.
|
||||
*
|
||||
* @param hsb the color to set
|
||||
* @param transitionPeriod the transition period for the action to take place
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setColor(HSBType hsb, int transitionPeriod) {
|
||||
TransitionLightState transitionLightState = new TransitionLightState();
|
||||
LightStateColor lightState = new LightStateColor();
|
||||
int brightness = hsb.getBrightness().intValue();
|
||||
lightState.setOnOff(brightness == 0 ? OnOffType.OFF : OnOffType.ON);
|
||||
lightState.setBrightness(brightness);
|
||||
lightState.setHue(hsb.getHue().intValue());
|
||||
lightState.setSaturation(hsb.getSaturation().intValue());
|
||||
lightState.setTransitionPeriod(transitionPeriod);
|
||||
transitionLightState.setLightState(lightState);
|
||||
return gson.toJson(transitionLightState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json for the set_light_State command to set the color temperature.
|
||||
*
|
||||
* @param colorTemperature the color temperature to set
|
||||
* @param transitionPeriod the transition period for the action to take place
|
||||
* @return The json string of the command to send to the device
|
||||
*/
|
||||
public String setColorTemperature(int colorTemperature, int transitionPeriod) {
|
||||
TransitionLightState transitionLightState = new TransitionLightState();
|
||||
LightStateColorTemperature lightState = new LightStateColorTemperature();
|
||||
lightState.setOnOff(OnOffType.ON);
|
||||
lightState.setColorTemperature(colorTemperature);
|
||||
lightState.setTransitionPeriod(transitionPeriod);
|
||||
transitionLightState.setLightState(lightState);
|
||||
return gson.toJson(transitionLightState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response for the set_light_state command.
|
||||
*
|
||||
* @param response the json string
|
||||
* @return The data object containing the state data from the json string
|
||||
*/
|
||||
public @Nullable TransitionLightStateResponse setTransitionLightStateResponse(String response) {
|
||||
return gson.fromJson(response, TransitionLightStateResponse.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class acts as and interface to the physical device.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Reorganized code an put connection in single class
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Connection {
|
||||
|
||||
public static final int TP_LINK_SMART_HOME_PORT = 9999;
|
||||
private static final int SOCKET_TIMEOUT_MILLISECONDS = 3_000;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Connection.class);
|
||||
|
||||
private @Nullable String ipAddress;
|
||||
|
||||
/**
|
||||
* Initializes a connection to the given ip address.
|
||||
*
|
||||
* @param ipAddress ip address of the connection
|
||||
*/
|
||||
public Connection(@Nullable final String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ip address to connect to.
|
||||
*
|
||||
* @param ipAddress The ip address to connect to
|
||||
*/
|
||||
public void setIpAddress(final String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the command, which is a json string, encrypted to the device and decrypts the json result and returns it
|
||||
*
|
||||
* @param command json command to send to the device
|
||||
* @return decrypted returned json result from the device
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
public synchronized String sendCommand(final String command) throws IOException {
|
||||
logger.trace("Executing command: {}", command);
|
||||
try (Socket socket = createSocket(); final OutputStream outputStream = socket.getOutputStream()) {
|
||||
outputStream.write(CryptUtil.encryptWithLength(command));
|
||||
final String response = readReturnValue(socket);
|
||||
|
||||
logger.trace("Command response: {}", response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and decrypts result returned from the device.
|
||||
*
|
||||
* @param socket socket to read result from
|
||||
* @return decrypted result
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
private String readReturnValue(final Socket socket) throws IOException {
|
||||
try (InputStream is = socket.getInputStream()) {
|
||||
return CryptUtil.decryptWithLength(is);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around socket creation to make mocking possible.
|
||||
*
|
||||
* @return new Socket instance
|
||||
* @throws UnknownHostException exception in case the host could not be determined
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
protected Socket createSocket() throws UnknownHostException, IOException {
|
||||
if (ipAddress == null) {
|
||||
throw new IOException("Ip address not set. Wait for discovery or manually trigger discovery process.");
|
||||
}
|
||||
final Socket socket = new Socket(ipAddress, TP_LINK_SMART_HOME_PORT);
|
||||
|
||||
socket.setSoTimeout(SOCKET_TIMEOUT_MILLISECONDS);
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Util class to encypt and decrypt data to be sent to and from the smart plug.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class CryptUtil {
|
||||
|
||||
private static final int KEY = 171;
|
||||
|
||||
private CryptUtil() {
|
||||
// Util class
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the byte array of the specified length. The length is necessary because the byte array might be larger
|
||||
* than the actual content.
|
||||
*
|
||||
* @param data byte array containing the data
|
||||
* @param length number of bytes in the byte array to read
|
||||
* @return decrypted String of the byte array
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
public static String decrypt(byte[] data, int length) throws IOException {
|
||||
try (ByteArrayInputStream is = new ByteArrayInputStream(data)) {
|
||||
return decrypt(is, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the byte data in the input stream. In the first 4 bytes the length of the data in the byte array is
|
||||
* coded.
|
||||
*
|
||||
* @param inputStream input stream containing length and data
|
||||
* @return decrypted String of the inputstream
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
public static String decryptWithLength(InputStream inputStream) throws IOException {
|
||||
try (DataInputStream is = new DataInputStream(inputStream)) {
|
||||
return decrypt(is, is.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the byte data in the input stream with the length as given.
|
||||
*
|
||||
* @param inputStream input stream
|
||||
* @param length the number of bytes to read
|
||||
* @return decrypted String of the inputstream
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
private static String decrypt(InputStream inputStream, int length) throws IOException {
|
||||
final byte[] decryptedData = new byte[length];
|
||||
int in;
|
||||
int key = KEY;
|
||||
int i = 0;
|
||||
while (i < length && (in = inputStream.read()) != -1) {
|
||||
final int nextKey = in;
|
||||
decryptedData[i++] = (byte) (in ^ key);
|
||||
key = nextKey;
|
||||
}
|
||||
return new String(decryptedData, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the string into a byte array with the first for bytes specifying the length of the given String. The
|
||||
* length is not encrypted.
|
||||
*
|
||||
* @param string String to encrypt
|
||||
* @return byte array with length and encrypted string
|
||||
*/
|
||||
public static byte[] encryptWithLength(String string) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(4 + string.length());
|
||||
bb.putInt(string.length());
|
||||
bb.put(encrypt(string));
|
||||
return bb.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the string into a byte array.
|
||||
*
|
||||
* @param string String to encrypt
|
||||
* @return byte array with encrypted string
|
||||
*/
|
||||
public static byte[] encrypt(String string) {
|
||||
byte[] buffer = new byte[string.length()];
|
||||
byte key = (byte) KEY;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
buffer[i] = (byte) (string.charAt(i) ^ key);
|
||||
key = buffer[i];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.DeviceType;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class PropertiesCollector {
|
||||
|
||||
private PropertiesCollector() {
|
||||
// Util class
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all properties of the thing from the {@link Sysinfo} object.
|
||||
*
|
||||
* @param thingType thing to get the properties for
|
||||
* @param ipAddress ip address of the device
|
||||
* @param sysinfo system info data returned from the device
|
||||
* @return map of properties
|
||||
*/
|
||||
public static Map<String, Object> collectProperties(TPLinkSmartHomeThingType thingType, String ipAddress,
|
||||
Sysinfo sysinfo) {
|
||||
final Map<String, Object> properties = new TreeMap<>();
|
||||
|
||||
putNonNull(properties, CONFIG_IP, ipAddress);
|
||||
if (thingType.getDeviceType() == DeviceType.RANGE_EXTENDER) {
|
||||
collectPropertiesRangeExtender(properties, sysinfo);
|
||||
} else {
|
||||
collectProperties(properties, sysinfo);
|
||||
if (thingType.getDeviceType() == DeviceType.BULB) {
|
||||
collectPropertiesBulb(properties, sysinfo);
|
||||
} else {
|
||||
collectPropertiesOther(properties, sysinfo);
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect generic properties.
|
||||
*
|
||||
* @param properties properties object to store properties in
|
||||
* @param sysinfo system info data returned from the device
|
||||
*/
|
||||
private static void collectProperties(Map<String, Object> properties, Sysinfo sysinfo) {
|
||||
putNonNull(properties, CONFIG_DEVICE_ID, sysinfo.getDeviceId());
|
||||
putNonNull(properties, PROPERTY_MODEL, sysinfo.getModel());
|
||||
putNonNull(properties, PROPERTY_HARDWARE_VERSION, sysinfo.getHwVer());
|
||||
putNonNull(properties, PROPERTY_SOFWARE_VERSION, sysinfo.getSwVer());
|
||||
putNonNull(properties, PROPERTY_HARDWARE_ID, sysinfo.getHwId());
|
||||
putNonNull(properties, PROPERTY_OEM_ID, sysinfo.getOemId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Smart Bulb specific properties.
|
||||
*
|
||||
* @param properties properties object to store properties in
|
||||
* @param sysinfo system info data returned from the device
|
||||
*/
|
||||
private static void collectPropertiesBulb(Map<String, Object> properties, Sysinfo sysinfo) {
|
||||
putNonNull(properties, PROPERTY_TYPE, sysinfo.getType());
|
||||
putNonNull(properties, PROPERTY_MAC, sysinfo.getMac());
|
||||
putNonNull(properties, PROPERTY_PROTOCOL_NAME, sysinfo.getProtocolName());
|
||||
putNonNull(properties, PROPERTY_PROTOCOL_VERSION, sysinfo.getProtocolVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Smart Range Extender specific properties.
|
||||
*
|
||||
* @param properties properties object to store properties in
|
||||
* @param sysinfo system info data returned from the device
|
||||
*/
|
||||
private static void collectPropertiesRangeExtender(Map<String, Object> properties, Sysinfo sysinfo) {
|
||||
final Sysinfo system = sysinfo.getSystem();
|
||||
collectProperties(properties, system);
|
||||
putNonNull(properties, PROPERTY_TYPE, system.getType());
|
||||
putNonNull(properties, PROPERTY_MAC, system.getMac());
|
||||
putNonNull(properties, PROPERTY_DEVICE_NAME, system.getDevName());
|
||||
putNonNull(properties, PROPERTY_FEATURE, sysinfo.getPlug().getFeature());
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Smart Switch specific properties.
|
||||
*
|
||||
* @param properties properties object to store properties in
|
||||
* @param sysinfo system info data returned from the device
|
||||
*/
|
||||
private static void collectPropertiesOther(Map<String, Object> properties, Sysinfo sysinfo) {
|
||||
putNonNull(properties, PROPERTY_TYPE, sysinfo.getType());
|
||||
putNonNull(properties, PROPERTY_MAC, sysinfo.getMac());
|
||||
putNonNull(properties, PROPERTY_DEVICE_NAME, sysinfo.getDevName());
|
||||
putNonNull(properties, PROPERTY_FIRMWARE_ID, sysinfo.getFwId());
|
||||
putNonNull(properties, PROPERTY_FEATURE, sysinfo.getFeature());
|
||||
}
|
||||
|
||||
private static void putNonNull(Map<String, Object> properties, String key, @Nullable String value) {
|
||||
if (value != null) {
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Service to get the actual ip of a TP-Link Smart Home device as registered on the network.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface TPLinkIpAddressService {
|
||||
|
||||
/**
|
||||
* Returns the last known ip address of the given device id. If no ip address known null is returned.
|
||||
*
|
||||
* @param deviceId id of the device to get the ip address of
|
||||
* @return ip address or null
|
||||
*/
|
||||
@Nullable
|
||||
String getLastKnownIpAddress(String deviceId);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* This class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Added channel and property keys
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class TPLinkSmartHomeBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "tplinksmarthome";
|
||||
|
||||
// List of all switch channel ids
|
||||
public static final String CHANNEL_SWITCH = "switch";
|
||||
|
||||
// List of all plug channel ids
|
||||
public static final String CHANNEL_LED = "led";
|
||||
|
||||
// List of all bulb channel ids
|
||||
public static final String CHANNEL_BRIGHTNESS = "brightness";
|
||||
public static final String CHANNEL_COLOR = "color";
|
||||
public static final String CHANNEL_COLOR_TEMPERATURE = "colorTemperature";
|
||||
public static final String CHANNEL_COLOR_TEMPERATURE_ABS = "colorTemperatureAbs";
|
||||
public static final int COLOR_TEMPERATURE_1_MIN = 2700;
|
||||
public static final int COLOR_TEMPERATURE_1_MAX = 6500;
|
||||
public static final int COLOR_TEMPERATURE_2_MIN = 2500;
|
||||
public static final int COLOR_TEMPERATURE_2_MAX = 9000;
|
||||
|
||||
public static final Set<String> CHANNELS_BULB_SWITCH = Stream.of(CHANNEL_BRIGHTNESS, CHANNEL_COLOR,
|
||||
CHANNEL_COLOR_TEMPERATURE, CHANNEL_COLOR_TEMPERATURE_ABS, CHANNEL_SWITCH).collect(Collectors.toSet());
|
||||
|
||||
// List of all energy channel ids
|
||||
public static final String CHANNEL_ENERGY_POWER = "power";
|
||||
public static final String CHANNEL_ENERGY_TOTAL = "energyUsage";
|
||||
public static final String CHANNEL_ENERGY_VOLTAGE = "voltage";
|
||||
public static final String CHANNEL_ENERGY_CURRENT = "current";
|
||||
public static final Set<String> CHANNELS_ENERGY = Stream
|
||||
.of(CHANNEL_ENERGY_POWER, CHANNEL_ENERGY_TOTAL, CHANNEL_ENERGY_VOLTAGE, CHANNEL_ENERGY_CURRENT)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// List of all misc channel ids
|
||||
public static final String CHANNEL_RSSI = "rssi";
|
||||
|
||||
// List of all group channel ids
|
||||
public static final String CHANNEL_SWITCH_GROUP = "group";
|
||||
public static final String CHANNEL_OUTLET_GROUP_PREFIX = "outlet";
|
||||
|
||||
// List of configuration keys
|
||||
public static final String CONFIG_IP = "ipAddress";
|
||||
public static final String CONFIG_DEVICE_ID = "deviceId";
|
||||
public static final String CONFIG_REFRESH = "refresh";
|
||||
// Only for bulbs
|
||||
public static final String CONFIG_TRANSITION_PERIOD = "transitionPeriod";
|
||||
|
||||
// List of property keys
|
||||
public static final String PROPERTY_TYPE = "type";
|
||||
public static final String PROPERTY_MODEL = "model";
|
||||
public static final String PROPERTY_DEVICE_NAME = "device name";
|
||||
public static final String PROPERTY_MAC = "mac";
|
||||
public static final String PROPERTY_HARDWARE_VERSION = "hardware version";
|
||||
public static final String PROPERTY_SOFWARE_VERSION = "sofware version";
|
||||
public static final String PROPERTY_HARDWARE_ID = "hardware id";
|
||||
public static final String PROPERTY_FIRMWARE_ID = "firmware id";
|
||||
public static final String PROPERTY_OEM_ID = "oem id";
|
||||
public static final String PROPERTY_FEATURE = "feature";
|
||||
public static final String PROPERTY_PROTOCOL_NAME = "protocol name";
|
||||
public static final String PROPERTY_PROTOCOL_VERSION = "protocol version";
|
||||
|
||||
public static final int FORCED_REFRESH_BOUNDERY_SECONDS = 60;
|
||||
public static final int FORCED_REFRESH_BOUNDERY_SWITCHED_SECONDS = 5;
|
||||
|
||||
private TPLinkSmartHomeBindingConstants() {
|
||||
// Constants class
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
/**
|
||||
* Data class representing the user configurable settings of the device
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class TPLinkSmartHomeConfiguration {
|
||||
|
||||
/**
|
||||
* IP Address of the device.
|
||||
*/
|
||||
public String ipAddress;
|
||||
|
||||
/**
|
||||
* The id of the device;
|
||||
*/
|
||||
public String deviceId;
|
||||
|
||||
/**
|
||||
* Refresh rate for the device in seconds.
|
||||
*/
|
||||
public int refresh;
|
||||
|
||||
/**
|
||||
* Transition period of light bulb state changes in seconds.
|
||||
*/
|
||||
public int transitionPeriod;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.CONFIG_DEVICE_ID;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link TPLinkSmartHomeDiscoveryService} detects new Smart Home Bulbs, Plugs and Switches by sending a UDP network
|
||||
* broadcast and parsing the answer into a thing.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Complete make-over, reorganized code and code cleanup.
|
||||
*/
|
||||
@Component(service = { DiscoveryService.class,
|
||||
TPLinkIpAddressService.class }, configurationPid = "discovery.tplinksmarthome")
|
||||
@NonNullByDefault
|
||||
public class TPLinkSmartHomeDiscoveryService extends AbstractDiscoveryService implements TPLinkIpAddressService {
|
||||
|
||||
private static final String BROADCAST_IP = "255.255.255.255";
|
||||
private static final int DISCOVERY_TIMEOUT_SECONDS = 8;
|
||||
private static final int UDP_PACKET_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(DISCOVERY_TIMEOUT_SECONDS - 1);
|
||||
private static final long REFRESH_INTERVAL_MINUTES = 1;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(TPLinkSmartHomeDiscoveryService.class);
|
||||
private final Commands commands = new Commands();
|
||||
private final Map<String, String> idInetAddressCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final DatagramPacket discoverPacket;
|
||||
private final byte[] buffer = new byte[2048];
|
||||
private @NonNullByDefault({}) DatagramSocket discoverSocket;
|
||||
private @NonNullByDefault({}) ScheduledFuture<?> discoveryJob;
|
||||
|
||||
public TPLinkSmartHomeDiscoveryService() throws UnknownHostException {
|
||||
super(SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT_SECONDS);
|
||||
final InetAddress broadcast = InetAddress.getByName(BROADCAST_IP);
|
||||
final byte[] discoverbuffer = CryptUtil.encrypt(Commands.getSysinfo());
|
||||
discoverPacket = new DatagramPacket(discoverbuffer, discoverbuffer.length, broadcast,
|
||||
Connection.TP_LINK_SMART_HOME_PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getLastKnownIpAddress(String deviceId) {
|
||||
return idInetAddressCache.get(deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
discoveryJob = scheduler.scheduleWithFixedDelay(this::startScan, 0, REFRESH_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
stopScan();
|
||||
if (discoveryJob != null && !discoveryJob.isCancelled()) {
|
||||
discoveryJob.cancel(true);
|
||||
discoveryJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Start scan for TP-Link Smart devices.");
|
||||
synchronized (this) {
|
||||
try {
|
||||
idInetAddressCache.clear();
|
||||
discoverSocket = sendDiscoveryPacket();
|
||||
// Runs until the socket call gets a time out and throws an exception. When a time out is triggered it
|
||||
// means no data was present and nothing new to discover.
|
||||
while (true) {
|
||||
if (discoverSocket == null) {
|
||||
break;
|
||||
}
|
||||
final DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||
|
||||
discoverSocket.receive(packet);
|
||||
logger.debug("TP-Link Smart device discovery returned package with length {}", packet.getLength());
|
||||
if (packet.getLength() > 0) {
|
||||
detectThing(packet);
|
||||
}
|
||||
}
|
||||
} catch (SocketTimeoutException e) {
|
||||
logger.debug("Discovering poller timeout...");
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error during discovery: {}", e.getMessage());
|
||||
} finally {
|
||||
closeDiscoverSocket();
|
||||
removeOlderResults(getTimestampOfLastScan());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopScan() {
|
||||
logger.debug("Stop scan for TP-Link Smart devices.");
|
||||
closeDiscoverSocket();
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a {@link DatagramSocket} and sends a packet for discovery of TP-Link Smart Home devices.
|
||||
*
|
||||
* @return Returns the new socket
|
||||
* @throws IOException exception in case sending the packet failed
|
||||
*/
|
||||
protected DatagramSocket sendDiscoveryPacket() throws IOException {
|
||||
final DatagramSocket ds = new DatagramSocket(null);
|
||||
|
||||
ds.setBroadcast(true);
|
||||
ds.setSoTimeout(UDP_PACKET_TIMEOUT_MS);
|
||||
ds.send(discoverPacket);
|
||||
logger.trace("Discovery package sent.");
|
||||
return ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the discovery socket and cleans the value. No need for synchronization as this method is called from a
|
||||
* synchronized context.
|
||||
*/
|
||||
private void closeDiscoverSocket() {
|
||||
if (discoverSocket != null) {
|
||||
discoverSocket.close();
|
||||
discoverSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detected a device (thing) and get process the data from the device and report it discovered.
|
||||
*
|
||||
* @param packet containing data of detected device
|
||||
* @throws IOException in case decrypting of the data failed
|
||||
*/
|
||||
private void detectThing(DatagramPacket packet) throws IOException {
|
||||
final String ipAddress = packet.getAddress().getHostAddress();
|
||||
final String rawData = CryptUtil.decrypt(packet.getData(), packet.getLength());
|
||||
final Sysinfo sysinfoRaw = commands.getSysinfoReponse(rawData);
|
||||
final Sysinfo sysinfo = sysinfoRaw.getActualSysinfo();
|
||||
|
||||
logger.trace("Detected TP-Link Smart Home device: {}", rawData);
|
||||
final String deviceId = sysinfo.getDeviceId();
|
||||
logger.debug("TP-Link Smart Home device '{}' with id {} found on {} ", sysinfo.getAlias(), deviceId, ipAddress);
|
||||
idInetAddressCache.put(deviceId, ipAddress);
|
||||
final Optional<TPLinkSmartHomeThingType> thingType = getThingTypeUID(sysinfo.getModel());
|
||||
|
||||
if (thingType.isPresent()) {
|
||||
final ThingTypeUID thingTypeUID = thingType.get().thingTypeUID();
|
||||
final ThingUID thingUID = new ThingUID(thingTypeUID,
|
||||
deviceId.substring(deviceId.length() - 6, deviceId.length()));
|
||||
final Map<String, Object> properties = PropertiesCollector.collectProperties(thingType.get(), ipAddress,
|
||||
sysinfoRaw);
|
||||
final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withLabel(sysinfo.getAlias()).withRepresentationProperty(CONFIG_DEVICE_ID)
|
||||
.withProperties(properties).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
} else {
|
||||
logger.debug("Detected, but ignoring unsupported TP-Link Smart Home device model '{}'", sysinfo.getModel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@link ThingTypeUID} based on the model value returned by the device.
|
||||
*
|
||||
* @param model model value returned by the device
|
||||
* @return {@link ThingTypeUID} or null if device not recognized
|
||||
*/
|
||||
private Optional<TPLinkSmartHomeThingType> getThingTypeUID(String model) {
|
||||
final String modelLC = model.toLowerCase(Locale.ENGLISH);
|
||||
return SUPPORTED_THING_TYPES_LIST.stream().filter(type -> modelLC.startsWith(type.thingTypeUID().getId()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.BulbDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.DimmerDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.EnergySwitchDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.PowerStripDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.RangeExtenderDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.SmartHomeDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.SwitchDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.handler.SmartHomeHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link TPLinkSmartHomeHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Specific handlers for different type of devices.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tplinksmarthome")
|
||||
public class TPLinkSmartHomeHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private @NonNullByDefault({}) TPLinkIpAddressService ipAddressService;
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
final ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
final TPLinkSmartHomeThingType type = TPLinkSmartHomeThingType.THING_TYPE_MAP.get(thingTypeUID);
|
||||
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
final SmartHomeDevice device;
|
||||
|
||||
switch (type.getDeviceType()) {
|
||||
case BULB:
|
||||
if (TPLinkSmartHomeThingType.isBulbDeviceWithTemperatureColor1(thingTypeUID)) {
|
||||
device = new BulbDevice(thingTypeUID, COLOR_TEMPERATURE_1_MIN, COLOR_TEMPERATURE_1_MAX);
|
||||
} else if (TPLinkSmartHomeThingType.isBulbDeviceWithTemperatureColor2(thingTypeUID)) {
|
||||
device = new BulbDevice(thingTypeUID, COLOR_TEMPERATURE_2_MIN, COLOR_TEMPERATURE_2_MAX);
|
||||
} else {
|
||||
device = new BulbDevice(thingTypeUID);
|
||||
}
|
||||
break;
|
||||
case DIMMER:
|
||||
device = new DimmerDevice();
|
||||
break;
|
||||
case PLUG:
|
||||
if (HS110.is(thingTypeUID)) {
|
||||
device = new EnergySwitchDevice();
|
||||
} else {
|
||||
device = new SwitchDevice();
|
||||
}
|
||||
break;
|
||||
case SWITCH:
|
||||
device = new SwitchDevice();
|
||||
break;
|
||||
case RANGE_EXTENDER:
|
||||
device = new RangeExtenderDevice();
|
||||
break;
|
||||
case STRIP:
|
||||
device = new PowerStripDevice(type);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return new SmartHomeHandler(thing, device, type, ipAddressService);
|
||||
}
|
||||
|
||||
@Reference
|
||||
protected void setTPLinkIpAddressCache(TPLinkIpAddressService ipAddressCache) {
|
||||
this.ipAddressService = ipAddressCache;
|
||||
}
|
||||
|
||||
protected void unsetTPLinkIpAddressCache(TPLinkIpAddressService ipAddressCache) {
|
||||
this.ipAddressService = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* ThingType enum with all supported TP-Link Smart Home devices.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum TPLinkSmartHomeThingType {
|
||||
|
||||
// Bulb Thing Type UIDs
|
||||
KB100("kb100", DeviceType.BULB),
|
||||
KB130("kb130", DeviceType.BULB),
|
||||
LB100("lb100", DeviceType.BULB),
|
||||
LB110("lb110", DeviceType.BULB),
|
||||
LB120("lb120", DeviceType.BULB),
|
||||
LB130("lb130", DeviceType.BULB),
|
||||
LB200("lb200", DeviceType.BULB),
|
||||
LB230("lb230", DeviceType.BULB),
|
||||
KL50("kl50", DeviceType.BULB),
|
||||
KL60("kl60", DeviceType.BULB),
|
||||
KL110("kl110", DeviceType.BULB),
|
||||
KL120("kl120", DeviceType.BULB),
|
||||
KL130("kl130", DeviceType.BULB),
|
||||
|
||||
// Plug Thing Type UIDs
|
||||
HS100("hs100", DeviceType.PLUG),
|
||||
HS103("hs103", DeviceType.PLUG),
|
||||
HS105("hs105", DeviceType.PLUG),
|
||||
HS110("hs110", DeviceType.PLUG),
|
||||
KP100("kp100", DeviceType.PLUG),
|
||||
KP105("kp105", DeviceType.PLUG),
|
||||
|
||||
// Switch Thing Type UIDs
|
||||
HS200("hs200", DeviceType.SWITCH),
|
||||
HS210("hs210", DeviceType.SWITCH),
|
||||
|
||||
// Dimmer Thing Type UIDs
|
||||
HS220("hs220", DeviceType.DIMMER),
|
||||
|
||||
// Power Strip Thing Type UIDs.
|
||||
HS107("hs107", DeviceType.STRIP, 2),
|
||||
HS300("hs300", DeviceType.STRIP, 6),
|
||||
KP200("kp200", DeviceType.STRIP, 2),
|
||||
KP303("kp303", DeviceType.STRIP, 3),
|
||||
KP400("kp400", DeviceType.STRIP, 2),
|
||||
|
||||
// Range Extender Thing Type UIDs
|
||||
RE270K("re270", DeviceType.RANGE_EXTENDER),
|
||||
RE370K("re370", DeviceType.RANGE_EXTENDER);
|
||||
|
||||
/**
|
||||
* All supported Smart Home devices in a list.
|
||||
*/
|
||||
public static final List<TPLinkSmartHomeThingType> SUPPORTED_THING_TYPES_LIST = Arrays
|
||||
.asList(TPLinkSmartHomeThingType.values());
|
||||
|
||||
/**
|
||||
* All {@link ThingTypeUID}s of all supported Smart Home devices.
|
||||
*/
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = SUPPORTED_THING_TYPES_LIST.stream()
|
||||
.map(TPLinkSmartHomeThingType::thingTypeUID).collect(Collectors.toSet());
|
||||
|
||||
/**
|
||||
* A map of all {@link TPLinkSmartHomeThingType} mapped to {@link ThingTypeUID}.
|
||||
*/
|
||||
public static final Map<ThingTypeUID, TPLinkSmartHomeThingType> THING_TYPE_MAP = SUPPORTED_THING_TYPES_LIST.stream()
|
||||
.collect(Collectors.toMap(TPLinkSmartHomeThingType::thingTypeUID, Function.identity()));
|
||||
private static final List<TPLinkSmartHomeThingType> BULB_WITH_TEMPERATURE_COLOR_1 = Stream.of(LB120, KL120)
|
||||
.collect(Collectors.toList());
|
||||
private static final List<TPLinkSmartHomeThingType> BULB_WITH_TEMPERATURE_COLOR_2 = Stream
|
||||
.of(KB130, KL130, LB130, LB230).collect(Collectors.toList());
|
||||
|
||||
private final ThingTypeUID thingTypeUID;
|
||||
private final DeviceType type;
|
||||
private final int sockets;
|
||||
|
||||
TPLinkSmartHomeThingType(final String name, final DeviceType type) {
|
||||
this(name, type, 0);
|
||||
}
|
||||
|
||||
TPLinkSmartHomeThingType(final String name, final DeviceType type, int sockets) {
|
||||
thingTypeUID = new ThingTypeUID(TPLinkSmartHomeBindingConstants.BINDING_ID, name);
|
||||
this.type = type;
|
||||
this.sockets = sockets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the type of the device.
|
||||
*/
|
||||
public DeviceType getDeviceType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link ThingTypeUID} of this device.
|
||||
*/
|
||||
public ThingTypeUID thingTypeUID() {
|
||||
return thingTypeUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the number of sockets. Only for Strip devices.
|
||||
*/
|
||||
public int getSockets() {
|
||||
return sockets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given {@link ThingTypeUID} matches a device that is a bulb with color temperature ranges 1
|
||||
* (2700 to 6500k).
|
||||
*
|
||||
* @param thingTypeUID if the check
|
||||
* @return true if it's a bulb device with color temperature range 1
|
||||
*/
|
||||
public static boolean isBulbDeviceWithTemperatureColor1(ThingTypeUID thingTypeUID) {
|
||||
return isDevice(thingTypeUID, BULB_WITH_TEMPERATURE_COLOR_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given {@link ThingTypeUID} matches a device that is a bulb with color temperature ranges 2
|
||||
* (2500 to 9000k).
|
||||
*
|
||||
* @param thingTypeUID if the check
|
||||
* @return true if it's a bulb device with color temperature range 2
|
||||
*/
|
||||
public static boolean isBulbDeviceWithTemperatureColor2(ThingTypeUID thingTypeUID) {
|
||||
return isDevice(thingTypeUID, BULB_WITH_TEMPERATURE_COLOR_2);
|
||||
}
|
||||
|
||||
private static boolean isDevice(ThingTypeUID thingTypeUID, List<TPLinkSmartHomeThingType> thingTypes) {
|
||||
return thingTypes.stream().anyMatch(t -> t.is(thingTypeUID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given {@link ThingTypeUID} matches the {@link ThingTypeUID} in this enum.
|
||||
*
|
||||
* @param otherThingTypeUID to check
|
||||
* @return true if matches
|
||||
*/
|
||||
public boolean is(ThingTypeUID otherThingTypeUID) {
|
||||
return thingTypeUID.equals(otherThingTypeUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum indicating the type of the device.
|
||||
*/
|
||||
public enum DeviceType {
|
||||
/**
|
||||
* Light Bulb device.
|
||||
*/
|
||||
BULB,
|
||||
/**
|
||||
* Dimmer device.
|
||||
*/
|
||||
DIMMER,
|
||||
/**
|
||||
* Plug device.
|
||||
*/
|
||||
PLUG,
|
||||
/**
|
||||
* Wi-Fi range extender device with plug.
|
||||
*/
|
||||
RANGE_EXTENDER,
|
||||
/**
|
||||
* Power strip device.
|
||||
*/
|
||||
STRIP,
|
||||
/**
|
||||
* Switch device.
|
||||
*/
|
||||
SWITCH
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.LightState;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightStateResponse;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home Light Bulb.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BulbDevice extends SmartHomeDevice {
|
||||
|
||||
protected Commands commands = new Commands();
|
||||
|
||||
private final int colorTempMin;
|
||||
private final int colorTempMax;
|
||||
private final int colorTempRangeFactor;
|
||||
|
||||
public BulbDevice(ThingTypeUID thingTypeUID) {
|
||||
this(thingTypeUID, 0, 0);
|
||||
}
|
||||
|
||||
public BulbDevice(ThingTypeUID thingTypeUID, int colorTempMin, int colorTempMax) {
|
||||
this.colorTempMin = colorTempMin;
|
||||
this.colorTempMax = colorTempMax;
|
||||
colorTempRangeFactor = (colorTempMax - colorTempMin) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUpdateCommand() {
|
||||
return Commands.getRealtimeBulbAndSysinfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
|
||||
final String channelId = channelUid.getId();
|
||||
final int transitionPeriod = configuration.transitionPeriod;
|
||||
final HasErrorResponse response;
|
||||
|
||||
if (command instanceof OnOffType) {
|
||||
response = handleOnOffType(channelId, (OnOffType) command, transitionPeriod);
|
||||
} else if (command instanceof HSBType) {
|
||||
response = handleHSBType(channelId, (HSBType) command, transitionPeriod);
|
||||
} else if (command instanceof DecimalType) {
|
||||
response = handleDecimalType(channelId, (DecimalType) command, transitionPeriod);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
checkErrors(response);
|
||||
return response != null;
|
||||
}
|
||||
|
||||
private @Nullable HasErrorResponse handleOnOffType(String channelID, OnOffType onOff, int transitionPeriod)
|
||||
throws IOException {
|
||||
if (CHANNELS_BULB_SWITCH.contains(channelID)) {
|
||||
return commands.setTransitionLightStateResponse(
|
||||
connection.sendCommand(commands.setLightState(onOff, transitionPeriod)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable HasErrorResponse handleDecimalType(String channelID, DecimalType command, int transitionPeriod)
|
||||
throws IOException {
|
||||
if (CHANNEL_COLOR.equals(channelID) || CHANNEL_BRIGHTNESS.equals(channelID)) {
|
||||
return commands.setTransitionLightStateResponse(
|
||||
connection.sendCommand(commands.setBrightness(command.intValue(), transitionPeriod)));
|
||||
} else if (CHANNEL_COLOR_TEMPERATURE.equals(channelID)) {
|
||||
return handleColorTemperature(convertPercentageToKelvin(command.intValue()), transitionPeriod);
|
||||
} else if (CHANNEL_COLOR_TEMPERATURE_ABS.equals(channelID)) {
|
||||
return handleColorTemperature(guardColorTemperature(command.intValue()), transitionPeriod);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable TransitionLightStateResponse handleColorTemperature(int colorTemperature, int transitionPeriod)
|
||||
throws IOException {
|
||||
return commands.setTransitionLightStateResponse(
|
||||
connection.sendCommand(commands.setColorTemperature(colorTemperature, transitionPeriod)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private HasErrorResponse handleHSBType(String channelID, HSBType command, int transitionPeriod) throws IOException {
|
||||
if (CHANNEL_COLOR.equals(channelID)) {
|
||||
return commands.setTransitionLightStateResponse(
|
||||
connection.sendCommand(commands.setColor(command, transitionPeriod)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
|
||||
final LightState lightState = deviceState.getSysinfo().getLightState();
|
||||
final State state;
|
||||
|
||||
switch (channelUid.getId()) {
|
||||
case CHANNEL_BRIGHTNESS:
|
||||
state = lightState.getBrightness();
|
||||
break;
|
||||
case CHANNEL_COLOR:
|
||||
state = new HSBType(lightState.getHue(), lightState.getSaturation(), lightState.getBrightness());
|
||||
break;
|
||||
case CHANNEL_COLOR_TEMPERATURE:
|
||||
state = new PercentType(convertKelvinToPercentage(lightState.getColorTemp()));
|
||||
break;
|
||||
case CHANNEL_COLOR_TEMPERATURE_ABS:
|
||||
state = new DecimalType(guardColorTemperature(lightState.getColorTemp()));
|
||||
break;
|
||||
case CHANNEL_SWITCH:
|
||||
state = lightState.getOnOff();
|
||||
break;
|
||||
case CHANNEL_ENERGY_POWER:
|
||||
state = new DecimalType(deviceState.getRealtime().getPower());
|
||||
break;
|
||||
default:
|
||||
state = UnDefType.UNDEF;
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
private int convertPercentageToKelvin(int percentage) {
|
||||
return guardColorTemperature(colorTempMin + colorTempRangeFactor * percentage);
|
||||
}
|
||||
|
||||
private int convertKelvinToPercentage(int colorTemperature) {
|
||||
return (guardColorTemperature(colorTemperature) - colorTempMin) / colorTempRangeFactor;
|
||||
}
|
||||
|
||||
private int guardColorTemperature(int colorTemperature) {
|
||||
return Math.max(colorTempMin, Math.min(colorTempMax, colorTemperature));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo;
|
||||
|
||||
/**
|
||||
* Data class to store device state.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DeviceState {
|
||||
|
||||
private final Commands commands = new Commands();
|
||||
private final Realtime realtime;
|
||||
private final Sysinfo sysinfo;
|
||||
|
||||
/**
|
||||
* Initializes the device state given the json response from the device.
|
||||
*
|
||||
* @param state device state as json string
|
||||
*/
|
||||
public DeviceState(String state) {
|
||||
sysinfo = commands.getSysinfoReponse(state);
|
||||
realtime = commands.getRealtimeResponse(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the device energy data (if present)
|
||||
*/
|
||||
public Realtime getRealtime() {
|
||||
return realtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the device state
|
||||
*/
|
||||
public Sysinfo getSysinfo() {
|
||||
return sysinfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.CHANNEL_BRIGHTNESS;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home device with a dimmer (HS220).
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DimmerDevice extends SwitchDevice {
|
||||
|
||||
@Override
|
||||
protected @Nullable HasErrorResponse setOnOffState(ChannelUID channelUid, OnOffType onOff) throws IOException {
|
||||
return commands.setSwitchStateResponse(connection.sendCommand(commands.setSwitchState(onOff)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
|
||||
return CHANNEL_BRIGHTNESS.equals(channelUid.getId()) ? handleBrightnessChannel(channelUid, command)
|
||||
: super.handleCommand(channelUid, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the brightness channel. Because the device has different commands for setting the device on/off and
|
||||
* setting the brightness the on/off command must be send to the device as well when the brightness.
|
||||
*
|
||||
* @param channelUid uid of the channel to handle
|
||||
* @param command command to the send
|
||||
* @return returns true if the command was handled
|
||||
* @throws IOException throws an {@link IOException} if the command handling failed
|
||||
*/
|
||||
private boolean handleBrightnessChannel(ChannelUID channelUid, Command command) throws IOException {
|
||||
HasErrorResponse response = null;
|
||||
|
||||
if (command instanceof OnOffType) {
|
||||
response = setOnOffState(channelUid, (OnOffType) command);
|
||||
} else if (command instanceof PercentType) {
|
||||
PercentType percentCommand = (PercentType) command;
|
||||
|
||||
// Don't send value 0 as brightness value as it will give an error from the device.
|
||||
if (percentCommand.intValue() > 0) {
|
||||
response = commands.setDimmerBrightnessResponse(
|
||||
connection.sendCommand(commands.setDimmerBrightness(percentCommand.intValue())));
|
||||
checkErrors(response);
|
||||
if (response == null) {
|
||||
return false;
|
||||
}
|
||||
response = setOnOffState(channelUid, OnOffType.ON);
|
||||
} else {
|
||||
response = setOnOffState(channelUid, OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
checkErrors(response);
|
||||
return response != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
|
||||
if (CHANNEL_BRIGHTNESS.equals(channelUid.getId())) {
|
||||
return deviceState.getSysinfo().getRelayState() == OnOffType.OFF ? PercentType.ZERO
|
||||
: new PercentType(deviceState.getSysinfo().getBrightness());
|
||||
} else {
|
||||
return super.updateChannel(channelUid, deviceState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home Switch device that also can measure energy usage.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergySwitchDevice extends SwitchDevice {
|
||||
|
||||
@Override
|
||||
public String getUpdateCommand() {
|
||||
return Commands.getRealtimeAndSysinfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
|
||||
final State state;
|
||||
final String matchChannelId = channelUid.isInGroup() ? channelUid.getIdWithoutGroup() : channelUid.getId();
|
||||
|
||||
if (CHANNELS_ENERGY.contains(matchChannelId)) {
|
||||
state = updateEnergyChannel(matchChannelId, deviceState.getRealtime());
|
||||
} else {
|
||||
state = super.updateChannel(channelUid, deviceState);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state for an energy channel.
|
||||
*
|
||||
* @param channelId Id of the energy channel to get the state
|
||||
* @param realtime data object containing the data from the device
|
||||
* @return state object for the given channel
|
||||
*/
|
||||
protected State updateEnergyChannel(String channelId, Realtime realtime) {
|
||||
final State value;
|
||||
|
||||
switch (channelId) {
|
||||
case CHANNEL_ENERGY_CURRENT:
|
||||
value = new QuantityType<>(realtime.getCurrent(), SmartHomeUnits.AMPERE);
|
||||
break;
|
||||
case CHANNEL_ENERGY_TOTAL:
|
||||
value = new QuantityType<>(realtime.getTotal(), SmartHomeUnits.KILOWATT_HOUR);
|
||||
break;
|
||||
case CHANNEL_ENERGY_VOLTAGE:
|
||||
value = new QuantityType<>(realtime.getVoltage(), SmartHomeUnits.VOLT);
|
||||
break;
|
||||
case CHANNEL_ENERGY_POWER:
|
||||
value = new QuantityType<>(realtime.getPower(), SmartHomeUnits.WATT);
|
||||
break;
|
||||
default:
|
||||
value = UnDefType.UNDEF;
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo.Outlet;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home device with multiple sockets, like the HS107 and HS300.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PowerStripDevice extends EnergySwitchDevice {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PowerStripDevice.class);
|
||||
|
||||
private final List<@Nullable Realtime> realTimeCacheList;
|
||||
private final List<@Nullable String> childIds;
|
||||
|
||||
public PowerStripDevice(final TPLinkSmartHomeThingType type) {
|
||||
final int nrOfSockets = type.getSockets();
|
||||
|
||||
realTimeCacheList = new ArrayList<>(nrOfSockets);
|
||||
childIds = new ArrayList<>(Collections.nCopies(nrOfSockets, ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUpdateCommand() {
|
||||
return Commands.getSysinfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshedDeviceState(@Nullable final DeviceState deviceState) {
|
||||
if (deviceState != null) {
|
||||
for (int i = 0; i < childIds.size(); i++) {
|
||||
childIds.set(i, deviceState.getSysinfo().getChildren().get(i).getId());
|
||||
realTimeCacheList.add(i, refreshCache(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected State getOnOffState(final DeviceState deviceState) {
|
||||
// Global On/Off state is determined by the combined state of all sockets. If 1 socket is on, the state is on.
|
||||
return OnOffType
|
||||
.from(deviceState.getSysinfo().getChildren().stream().anyMatch(e -> OnOffType.ON.equals(e.getState())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State updateChannel(final ChannelUID channelUid, final DeviceState deviceState) {
|
||||
final int idx = channelToIndex(channelUid);
|
||||
|
||||
if (idx >= 0 && idx < childIds.size()) {
|
||||
final Outlet outlet = deviceState.getSysinfo().getChildren().get(idx);
|
||||
final String baseChannel = channelUid.getIdWithoutGroup();
|
||||
|
||||
if (CHANNEL_SWITCH.equals(baseChannel)) {
|
||||
return outlet.getState();
|
||||
} else if (CHANNELS_ENERGY.contains(baseChannel)) {
|
||||
final Realtime realTime = realTimeCacheList.get(idx);
|
||||
|
||||
return realTime == null ? UnDefType.UNDEF : updateEnergyChannel(baseChannel, realTime);
|
||||
}
|
||||
} else {
|
||||
if (idx >= 0) {
|
||||
logger.debug("For channel update the index '{}' could be mapped to a channel. passed channel: {}", idx,
|
||||
channelUid);
|
||||
}
|
||||
}
|
||||
return super.updateChannel(channelUid, deviceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String getChildId(final ChannelUID channelUid) {
|
||||
final int idx = channelToIndex(channelUid);
|
||||
|
||||
return idx >= 0 && idx < childIds.size() ? childIds.get(idx) : null;
|
||||
}
|
||||
|
||||
private int channelToIndex(final ChannelUID channelUid) {
|
||||
final String groupId = channelUid.getGroupId();
|
||||
|
||||
return (groupId != null && groupId.startsWith(CHANNEL_OUTLET_GROUP_PREFIX)
|
||||
? Integer.parseInt(groupId.substring(CHANNEL_OUTLET_GROUP_PREFIX.length()))
|
||||
: 0) - 1;
|
||||
}
|
||||
|
||||
private @Nullable Realtime refreshCache(final int idx) {
|
||||
try {
|
||||
final String childId = childIds.get(idx);
|
||||
|
||||
return childId == null ? null
|
||||
: commands.getRealtimeResponse(connection.sendCommand(Commands.getRealtimeWithContext(childId)));
|
||||
} catch (final IOException e) {
|
||||
return null;
|
||||
} catch (final RuntimeException e) {
|
||||
logger.debug(
|
||||
"Obtaining realtime data for channel-'{}' unexpectedly crashed. If this keeps happening please report: ",
|
||||
idx, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetRelayState;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home range extender with smart plug.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RangeExtenderDevice extends SwitchDevice {
|
||||
|
||||
@Override
|
||||
protected State getOnOffState(DeviceState deviceState) {
|
||||
return deviceState.getSysinfo().getPlug().getRelayStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable SetRelayState setOnOffState(ChannelUID channelUid, OnOffType onOff) throws IOException {
|
||||
// It's unknown what the command is to send to the device so it's not supported.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Connection;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ErrorResponse;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Abstract class as base for Smart Home device implementations.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class SmartHomeDevice {
|
||||
|
||||
protected final Commands commands = new Commands();
|
||||
protected @NonNullByDefault({}) Connection connection;
|
||||
protected @NonNullByDefault({}) TPLinkSmartHomeConfiguration configuration;
|
||||
|
||||
/**
|
||||
* Checks if the response object contains errors and if so throws an {@link IOException} when an error code was set.
|
||||
*
|
||||
* @param response The response to check for errors.
|
||||
* @throws IOException if an error code was set in the response object
|
||||
*/
|
||||
protected void checkErrors(@Nullable HasErrorResponse response) throws IOException {
|
||||
final ErrorResponse errorResponse = response == null ? null : response.getErrorResponse();
|
||||
|
||||
if (errorResponse != null && errorResponse.getErrorCode() != 0) {
|
||||
throw new IOException("Error (" + errorResponse.getErrorCode() + "): " + errorResponse.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets connection and configuration values.
|
||||
*
|
||||
* @param connection The connection to the device
|
||||
* @param configuration The global configuration
|
||||
*/
|
||||
public void initialize(Connection connection, TPLinkSmartHomeConfiguration configuration) {
|
||||
this.connection = connection;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the json string to send to the device to get the state of the device.
|
||||
*/
|
||||
public abstract String getUpdateCommand();
|
||||
|
||||
/**
|
||||
* Handle the command for the given channel
|
||||
*
|
||||
* @param channelUID The channel the command is for
|
||||
* @param command The command to be send to the device
|
||||
* @return Returns true if the commands successfully was send to the device
|
||||
* @throws IOException In case of communications error or the device returned an error
|
||||
*/
|
||||
public abstract boolean handleCommand(ChannelUID channelUID, Command command) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the {@link State} value for the given value extracted from the deviceState data.
|
||||
*
|
||||
* @param channelUid channel to get state for
|
||||
* @param deviceState state object containing the state
|
||||
* @return {@link State} value for the given channel
|
||||
*/
|
||||
public abstract State updateChannel(ChannelUID channelUid, DeviceState deviceState);
|
||||
|
||||
/**
|
||||
* Called with the new device state after the new device state is retrieved from the device.
|
||||
*
|
||||
* @param deviceState new device state
|
||||
*/
|
||||
public void refreshedDeviceState(@Nullable DeviceState deviceState) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* TP-Link Smart Home device with a switch, like Smart Plugs and Switches.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SwitchDevice extends SmartHomeDevice {
|
||||
|
||||
@Override
|
||||
public String getUpdateCommand() {
|
||||
return Commands.getSysinfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
|
||||
return command instanceof OnOffType && handleOnOffType(channelUid, (OnOffType) command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the switch state.
|
||||
*
|
||||
* @param deviceState data object containing the state
|
||||
* @return the switch state
|
||||
*/
|
||||
protected State getOnOffState(DeviceState deviceState) {
|
||||
return deviceState.getSysinfo().getRelayState();
|
||||
}
|
||||
|
||||
private boolean handleOnOffType(ChannelUID channelUid, OnOffType onOff) throws IOException {
|
||||
final HasErrorResponse response;
|
||||
final String baseChannelId = getBaseChannel(channelUid);
|
||||
|
||||
if (CHANNEL_SWITCH.contentEquals(baseChannelId)) {
|
||||
response = setOnOffState(channelUid, onOff);
|
||||
} else if (CHANNEL_LED.contentEquals(baseChannelId)) {
|
||||
response = commands
|
||||
.setLedOnResponse(connection.sendCommand(commands.setLedOn(onOff, getChildId(channelUid))));
|
||||
} else {
|
||||
response = null;
|
||||
}
|
||||
checkErrors(response);
|
||||
return response != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the {@link OnOffType} command to the device and returns the returned answer.
|
||||
*
|
||||
* @param channelUid channel Id to use to determine child id
|
||||
* @param onOff command to the send
|
||||
* @return state returned by the device
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
protected @Nullable HasErrorResponse setOnOffState(ChannelUID channelUid, OnOffType onOff) throws IOException {
|
||||
return commands
|
||||
.setRelayStateResponse(connection.sendCommand(commands.setRelayState(onOff, getChildId(channelUid))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
|
||||
final String baseChannelId = getBaseChannel(channelUid);
|
||||
|
||||
if (CHANNEL_SWITCH.equals(baseChannelId)) {
|
||||
return getOnOffState(deviceState);
|
||||
} else if (CHANNEL_LED.equals(baseChannelId)) {
|
||||
return deviceState.getSysinfo().getLedOff();
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child Id for the given channel if the device supports children and it's a channel for a specific
|
||||
* child.
|
||||
*
|
||||
* @param channelUid channel Id to get the child id for
|
||||
* @return null or child id
|
||||
*/
|
||||
protected @Nullable String getChildId(ChannelUID channelUid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getBaseChannel(ChannelUID channelUid) {
|
||||
return channelUid.isInGroup() ? channelUid.getIdWithoutGroup() : channelUid.getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.handler;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Connection;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkIpAddressService;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.DeviceType;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.DeviceState;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.SmartHomeDevice;
|
||||
import org.openhab.core.cache.ExpiringCache;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler class for TP-Link Smart Home devices.
|
||||
*
|
||||
* @author Christian Fischer - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Rewrite to generic TP-Link Smart Home Handler
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SmartHomeHandler extends BaseThingHandler {
|
||||
|
||||
private static final Duration ONE_SECOND = Duration.ofSeconds(1);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SmartHomeHandler.class);
|
||||
|
||||
private final SmartHomeDevice smartHomeDevice;
|
||||
private final TPLinkIpAddressService ipAddressService;
|
||||
private final int forceRefreshThreshold;
|
||||
|
||||
private @NonNullByDefault({}) TPLinkSmartHomeConfiguration configuration;
|
||||
private @NonNullByDefault({}) Connection connection;
|
||||
private @NonNullByDefault({}) ScheduledFuture<?> refreshJob;
|
||||
private @NonNullByDefault({}) ExpiringCache<@Nullable DeviceState> cache;
|
||||
/**
|
||||
* Cache to avoid refresh is called multiple time in 1 second.
|
||||
*/
|
||||
private @NonNullByDefault({}) ExpiringCache<@Nullable DeviceState> fastCache;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param thing The thing to handle
|
||||
* @param smartHomeDevice Specific Smart Home device handler
|
||||
* @param type The device type
|
||||
* @param ipAddressService Cache keeping track of ip addresses of tp link devices
|
||||
*/
|
||||
public SmartHomeHandler(Thing thing, SmartHomeDevice smartHomeDevice, TPLinkSmartHomeThingType type,
|
||||
TPLinkIpAddressService ipAddressService) {
|
||||
super(thing);
|
||||
this.smartHomeDevice = smartHomeDevice;
|
||||
this.ipAddressService = ipAddressService;
|
||||
this.forceRefreshThreshold = type.getDeviceType() == DeviceType.SWITCH
|
||||
|| type.getDeviceType() == DeviceType.DIMMER ? FORCED_REFRESH_BOUNDERY_SWITCHED_SECONDS
|
||||
: FORCED_REFRESH_BOUNDERY_SECONDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUid, Command command) {
|
||||
try {
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannelState(channelUid, fastCache.getValue());
|
||||
} else if (smartHomeDevice.handleCommand(channelUid, command)) {
|
||||
// After a command always refresh the cache to make sure the cache has the latest data
|
||||
updateChannelState(channelUid, forceCacheUpdate());
|
||||
} else {
|
||||
logger.debug("Command {} is not supported for channel: {}", command, channelUid.getId());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (refreshJob != null && !refreshJob.isCancelled()) {
|
||||
refreshJob.cancel(true);
|
||||
refreshJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
configuration = getConfigAs(TPLinkSmartHomeConfiguration.class);
|
||||
if (StringUtil.isBlank(configuration.ipAddress) && StringUtil.isBlank(configuration.deviceId)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"No ip address or the device id configured.");
|
||||
return;
|
||||
}
|
||||
logger.debug("Initializing TP-Link Smart device on ip '{}' or deviceId '{}' ", configuration.ipAddress,
|
||||
configuration.deviceId);
|
||||
connection = createConnection(configuration);
|
||||
smartHomeDevice.initialize(connection, configuration);
|
||||
cache = new ExpiringCache<>(Duration.ofSeconds(configuration.refresh), this::refreshCache);
|
||||
// If refresh > threshold fast cache invalidates after 1 second, else it behaves just as the 'normal' cache
|
||||
fastCache = configuration.refresh > forceRefreshThreshold
|
||||
? new ExpiringCache<>(ONE_SECOND, this::forceCacheUpdate)
|
||||
: cache;
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
// While config.xml defines refresh as min 1, this check is used to run a test that doesn't start refresh.
|
||||
if (configuration.refresh > 0) {
|
||||
startAutomaticRefresh(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new Connection. Methods makes mocking of the connection in tests possible.
|
||||
*
|
||||
* @param config configuration to be used by the connection
|
||||
* @return new Connection object
|
||||
*/
|
||||
Connection createConnection(TPLinkSmartHomeConfiguration config) {
|
||||
return new Connection(config.ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the cache to force an update. It returns the refreshed cached value.
|
||||
*
|
||||
* @return the refreshed value
|
||||
*/
|
||||
private @Nullable DeviceState forceCacheUpdate() {
|
||||
cache.invalidateValue();
|
||||
return cache.getValue();
|
||||
}
|
||||
|
||||
private @Nullable DeviceState refreshCache() {
|
||||
try {
|
||||
updateIpAddress();
|
||||
final DeviceState deviceState = new DeviceState(connection.sendCommand(smartHomeDevice.getUpdateCommand()));
|
||||
updateDeviceId(deviceState.getSysinfo().getDeviceId());
|
||||
smartHomeDevice.refreshedDeviceState(deviceState);
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
return deviceState;
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
return null;
|
||||
} catch (RuntimeException e) {
|
||||
logger.debug("Obtaining new device data unexpectedly crashed. If this keeps happening please report: ", e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.DISABLED, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current configured ip addres is still the same as by which the device is registered on the network.
|
||||
* If there is a different ip address for this device it will update the configuration with this ip and start using
|
||||
* this ip address.
|
||||
*/
|
||||
private void updateIpAddress() {
|
||||
if (configuration.deviceId == null) {
|
||||
// The device id is needed to get the ip address so if not known no need to continue.
|
||||
return;
|
||||
}
|
||||
String lastKnownIpAddress = ipAddressService.getLastKnownIpAddress(configuration.deviceId);
|
||||
|
||||
if (lastKnownIpAddress != null && !lastKnownIpAddress.equals(configuration.ipAddress)) {
|
||||
Configuration editConfig = editConfiguration();
|
||||
editConfig.put(CONFIG_IP, lastKnownIpAddress);
|
||||
updateConfiguration(editConfig);
|
||||
configuration.ipAddress = lastKnownIpAddress;
|
||||
connection.setIpAddress(lastKnownIpAddress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the device id configuration if it's not set or throws an {@link IllegalArgumentException} if the
|
||||
* configured device id doesn't match with the id reported by the device.
|
||||
*
|
||||
* @param actualDeviceId The id of the device as actual returned by the device.
|
||||
* @throws IllegalArgumentException if the configured device id doesn't match with the id reported by the device
|
||||
* itself.
|
||||
*/
|
||||
private void updateDeviceId(String actualDeviceId) {
|
||||
if (StringUtil.isBlank(configuration.deviceId)) {
|
||||
Configuration editConfig = editConfiguration();
|
||||
editConfig.put(CONFIG_DEVICE_ID, actualDeviceId);
|
||||
updateConfiguration(editConfig);
|
||||
configuration.deviceId = actualDeviceId;
|
||||
} else if (!StringUtil.isBlank(actualDeviceId) && !actualDeviceId.equals(configuration.deviceId)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("The configured device '%s' doesn't match with the id the device reports: '%s'.",
|
||||
configuration.deviceId, actualDeviceId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the background refresh thread.
|
||||
*/
|
||||
private void startAutomaticRefresh(TPLinkSmartHomeConfiguration config) {
|
||||
if (refreshJob == null || refreshJob.isCancelled()) {
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::refreshChannels, config.refresh, config.refresh,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
void refreshChannels() {
|
||||
logger.trace("Update Channels for:{}", thing.getUID());
|
||||
getThing().getChannels().forEach(channel -> updateChannelState(channel.getUID(), cache.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state from the device data for the channel given the data..
|
||||
*
|
||||
* @param channelUID channel to update
|
||||
* @param deviceState the state object containing the value to set of the channel
|
||||
*
|
||||
*/
|
||||
private void updateChannelState(ChannelUID channelUID, @Nullable DeviceState deviceState) {
|
||||
if (!isLinked(channelUID)) {
|
||||
return;
|
||||
}
|
||||
String channelId = channelUID.isInGroup() ? channelUID.getIdWithoutGroup() : channelUID.getId();
|
||||
final State state;
|
||||
|
||||
if (deviceState == null) {
|
||||
state = UnDefType.UNDEF;
|
||||
} else if (CHANNEL_RSSI.equals(channelId)) {
|
||||
state = new QuantityType<>(deviceState.getSysinfo().getRssi(), SmartHomeUnits.DECIBEL_MILLIWATTS);
|
||||
} else {
|
||||
state = smartHomeDevice.updateChannel(channelUID, deviceState);
|
||||
}
|
||||
updateState(channelUID, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Class to be extended by state classes that support context. i.e. has multiple children that can be controlled.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class ContextState {
|
||||
|
||||
public static class Context {
|
||||
@Expose
|
||||
private String[] childIds = new String[1];
|
||||
|
||||
public void setChildId(String childId) {
|
||||
this.childIds[0] = childId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return " child_ids:[" + childIds[0] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Expose
|
||||
private Context context;
|
||||
|
||||
public void setChildId(String childId) {
|
||||
context = new Context();
|
||||
context.setChildId(childId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return context == null ? "" : context.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Base class for responses containing the common error response fields.
|
||||
* Only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class ErrorResponse implements HasErrorResponse {
|
||||
|
||||
@Expose(serialize = false)
|
||||
private int errCode;
|
||||
@Expose(serialize = false)
|
||||
private String errMsg;
|
||||
|
||||
/**
|
||||
* @return the error code
|
||||
*/
|
||||
public int getErrorCode() {
|
||||
return errCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error message
|
||||
*/
|
||||
public String getErrorMessage() {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{err_code:" + errCode + ", err_msg:'" + errMsg + "'}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class for getting the tp-Link Smart Plug energy state.
|
||||
* Only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GetRealtime extends ContextState {
|
||||
|
||||
public static class EMeter {
|
||||
private Realtime getRealtime = new Realtime();
|
||||
|
||||
public Realtime getRealtime() {
|
||||
return getRealtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "get_realtime:{" + getRealtime + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName(value = "emeter", alternate = "smartlife.iot.common.emeter")
|
||||
private EMeter emeter = new EMeter();
|
||||
|
||||
public Realtime getRealtime() {
|
||||
return emeter.getRealtime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GetRealtime {emeter:{" + emeter + "}}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Data class for getting the tp-Link Smart Plug state.
|
||||
* Only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GetSysinfo {
|
||||
|
||||
public static class System {
|
||||
private Sysinfo getSysinfo = new Sysinfo();
|
||||
|
||||
public Sysinfo getGetSysinfo() {
|
||||
return getSysinfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "get_sysinfo:{" + getSysinfo + "}";
|
||||
}
|
||||
}
|
||||
|
||||
private System system = new System();
|
||||
|
||||
public Sysinfo getSysinfo() {
|
||||
return system.getGetSysinfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GetSysinfo {system:{" + system + "}}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Util class to create a {@link Gson} object.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class GsonUtil {
|
||||
|
||||
private GsonUtil() {
|
||||
// Util class
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Gson} object.
|
||||
*
|
||||
* @return new {@link Gson} object.
|
||||
*/
|
||||
public static Gson createGson() {
|
||||
return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Gson} object that uses the {@link Expose} annotation..
|
||||
*
|
||||
* @return new {@link Gson} object.
|
||||
*/
|
||||
public static Gson createGsonWithExpose() {
|
||||
return new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
|
||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
/**
|
||||
* Interface for data objects that have an error code in their response.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface HasErrorResponse {
|
||||
/**
|
||||
* @return returns the object containing the error response
|
||||
*/
|
||||
ErrorResponse getErrorResponse();
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
|
||||
/**
|
||||
* Data class for reading the retrieved state of a Smart Home light bulb.
|
||||
* Mostly only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class LightState extends ErrorResponse {
|
||||
|
||||
private int brightness;
|
||||
private int colorTemp;
|
||||
private int hue;
|
||||
private int ignoreDefault;
|
||||
private String mode;
|
||||
private int onOff;
|
||||
private int saturation;
|
||||
|
||||
public PercentType getBrightness() {
|
||||
return onOff > 0 ? new PercentType(brightness) : PercentType.ZERO;
|
||||
}
|
||||
|
||||
public int getColorTemp() {
|
||||
return colorTemp;
|
||||
}
|
||||
|
||||
public DecimalType getHue() {
|
||||
return new DecimalType(hue);
|
||||
}
|
||||
|
||||
public int getIgnoreDefault() {
|
||||
return ignoreDefault;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public OnOffType getOnOff() {
|
||||
return onOff == 1 ? OnOffType.ON : OnOffType.OFF;
|
||||
}
|
||||
|
||||
public PercentType getSaturation() {
|
||||
return new PercentType(saturation);
|
||||
}
|
||||
|
||||
public void setOnOff(OnOffType onOff) {
|
||||
this.onOff = onOff == OnOffType.ON ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "brightness:" + brightness + ", color_temp:" + colorTemp + ", hue:" + hue + ", ignore_default:"
|
||||
+ ignoreDefault + ", mode:" + mode + ", on_off:" + onOff + ", saturation:" + saturation
|
||||
+ super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
/**
|
||||
* Data class for reading tp-Link Smart Plug energy monitoring.
|
||||
* Only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class Realtime extends ErrorResponse {
|
||||
|
||||
private static final int MILLIWATT_TO_WATT = 1000;
|
||||
private static final int MILLIAMP_TO_AMP = 1000;
|
||||
private static final int WATTHOUR_TO_KILOWATTHOUR = 1000;
|
||||
private static final int MILLIVOLT_TO_VOLT = 1000;
|
||||
|
||||
private double current;
|
||||
private double power;
|
||||
private double total;
|
||||
private double voltage;
|
||||
|
||||
// JSON names used for v2 hardware
|
||||
private double currentMa;
|
||||
private double powerMw;
|
||||
private double totalWh;
|
||||
private double voltageMv;
|
||||
|
||||
public double getCurrent() {
|
||||
return currentMa > 0.0 ? currentMa / MILLIAMP_TO_AMP : current;
|
||||
}
|
||||
|
||||
public double getPower() {
|
||||
return powerMw > 0.0 ? powerMw / MILLIWATT_TO_WATT : power;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return totalWh > 0.0 ? totalWh / WATTHOUR_TO_KILOWATTHOUR : total;
|
||||
}
|
||||
|
||||
public double getVoltage() {
|
||||
return voltageMv > 0.0 ? voltageMv / MILLIVOLT_TO_VOLT : voltage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "current:" + getCurrent() + ", power:" + getPower() + ", total:" + getTotal() + ", voltage:"
|
||||
+ getVoltage() + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class to set the Brightness of a Smart Home dimmer (HS220).
|
||||
* Setter methods for data and getter for error response.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SetBrightness implements HasErrorResponse {
|
||||
|
||||
public static class Brightness extends ErrorResponse {
|
||||
@Expose(deserialize = false)
|
||||
private int brightness;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "brightness:" + brightness + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dimmer {
|
||||
@Expose
|
||||
private Brightness setBrightness = new Brightness();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "set_brightness:{" + setBrightness + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Expose
|
||||
@SerializedName("smartlife.iot.dimmer")
|
||||
private Dimmer dimmer = new Dimmer();
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return dimmer.setBrightness;
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
dimmer.setBrightness.brightness = brightness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "smartlife.iot.dimmer:{" + dimmer + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Data class to set the led of a Smart Home device on or off.
|
||||
* Only setter methods as the object is only used to send values.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class SetLedOff extends ContextState implements HasErrorResponse {
|
||||
|
||||
public static class LedOff extends ErrorResponse {
|
||||
@Expose
|
||||
private int off;
|
||||
|
||||
public void setOff(int off) {
|
||||
this.off = off;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "off:" + off + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class System {
|
||||
@Expose
|
||||
private LedOff setLedOff = new LedOff();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "set_led_off:{" + setLedOff + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Expose
|
||||
private System system = new System();
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return system.setLedOff;
|
||||
}
|
||||
|
||||
public void setLed(OnOffType onOff) {
|
||||
system.setLedOff.setOff(onOff == OnOffType.OFF ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetLedOff {system:{" + system + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Data class for setting the TP-Link Smart Plug state and retrieving the result.
|
||||
* Only setter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class SetRelayState extends ContextState implements HasErrorResponse {
|
||||
|
||||
public static class RelayState extends ErrorResponse {
|
||||
@Expose(deserialize = false)
|
||||
private int state;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "state:" + state;
|
||||
}
|
||||
}
|
||||
|
||||
public static class System {
|
||||
@Expose
|
||||
private RelayState setRelayState = new RelayState();
|
||||
|
||||
public void setRelayState(OnOffType onOff) {
|
||||
setRelayState.state = onOff == OnOffType.ON ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "set_relay_state:{" + setRelayState + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Expose
|
||||
private System system = new System();
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return system.setRelayState;
|
||||
}
|
||||
|
||||
public void setRelayState(OnOffType onOff) {
|
||||
system.setRelayState(onOff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetRelayState {system:{" + system + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class for setting the TP-Link Smart Dimmer (HS220) state and retrieving the result.
|
||||
* Only setter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class SetSwitchState implements HasErrorResponse {
|
||||
|
||||
public static class State extends ErrorResponse {
|
||||
@Expose(deserialize = false)
|
||||
private int state;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "state:" + state;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dimmer {
|
||||
@Expose
|
||||
private State setSwitchState = new State();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "set_switch_state:{" + setSwitchState + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Expose
|
||||
@SerializedName("smartlife.iot.dimmer")
|
||||
private Dimmer dimmer = new Dimmer();
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return dimmer.setSwitchState;
|
||||
}
|
||||
|
||||
public void setSwitchState(OnOffType onOff) {
|
||||
dimmer.setSwitchState.state = onOff == OnOffType.ON ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetSwitchState {smartlife.iot.dimmer:{" + dimmer + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class for reading TP-Link Smart Home device state.
|
||||
* Only getter methods as the values are set by gson based on the retrieved json.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class Sysinfo extends ErrorResponse {
|
||||
|
||||
public static class CtrlProtocols {
|
||||
private String name;
|
||||
private String version;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "name:" + name + ", version:" + version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With default light state state. The default light state is set when the device is off. If the device is on the
|
||||
* state is in the parent fields.
|
||||
*/
|
||||
public static class WithDefaultLightState extends LightState {
|
||||
private LightState dftOnState;
|
||||
|
||||
public LightState getLightState() {
|
||||
if (dftOnState == null) {
|
||||
return this;
|
||||
} else {
|
||||
dftOnState.setOnOff(getOnOff());
|
||||
return dftOnState;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ", dftOnState:{" + dftOnState + "}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of the plug as set in the range extender products.
|
||||
*/
|
||||
public static class Plug {
|
||||
private String feature;
|
||||
private String relayStatus;
|
||||
|
||||
public String getFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
public OnOffType getRelayStatus() {
|
||||
return "ON".equals(relayStatus) ? OnOffType.ON : OnOffType.OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of a single outlet on power strip.
|
||||
*/
|
||||
public static class Outlet {
|
||||
private String alias;
|
||||
private String id;
|
||||
private long onTime;
|
||||
private int state;
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getOnTime() {
|
||||
return onTime;
|
||||
}
|
||||
|
||||
public OnOffType getState() {
|
||||
return state == 1 ? OnOffType.ON : OnOffType.OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of the range extended Wi-Fi.
|
||||
*/
|
||||
public static class RangeextenderWireless {
|
||||
private int w2gRssi;
|
||||
|
||||
public int getW2gRssi() {
|
||||
return w2gRssi;
|
||||
}
|
||||
}
|
||||
|
||||
private String swVer;
|
||||
private String hwVer;
|
||||
private String model;
|
||||
@SerializedName("deviceId")
|
||||
private String deviceId;
|
||||
@SerializedName("hwId")
|
||||
private String hwId;
|
||||
@SerializedName("oemId")
|
||||
private String oemId;
|
||||
private String alias;
|
||||
private String activeMode;
|
||||
private int rssi;
|
||||
@SerializedName(value = "type", alternate = "mic_type")
|
||||
private String type;
|
||||
@SerializedName(value = "mac", alternate = { "mic_mac", "ethernet_mac" })
|
||||
private String mac;
|
||||
|
||||
// switch and plug specific system info
|
||||
@SerializedName("fwId")
|
||||
private String fwId;
|
||||
private String devName;
|
||||
private String iconHash;
|
||||
private int relayState; // 0 is off, 1 is on
|
||||
private long onTime;
|
||||
private String feature; // HS100 -> TIM, HS110 -> TIM:ENE
|
||||
// Disabled updating as it's a different type for different devices.
|
||||
// private int updating;
|
||||
private int ledOff;
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
|
||||
// powerstrip/multiple plugs support.
|
||||
private int childNum;
|
||||
private List<Outlet> children = new ArrayList<>();
|
||||
|
||||
// dimmer specific system info
|
||||
private int brightness;
|
||||
|
||||
// bulb specific system info
|
||||
private boolean isFactory;
|
||||
private String discoVer;
|
||||
private CtrlProtocols ctrlProtocols;
|
||||
private WithDefaultLightState lightState = new WithDefaultLightState();
|
||||
|
||||
// range extender specific system info
|
||||
private String ledStatus;
|
||||
private Plug plug = new Plug();
|
||||
private Sysinfo system;
|
||||
@SerializedName("rangeextender.wireless")
|
||||
private RangeextenderWireless reWireless;
|
||||
|
||||
public String getSwVer() {
|
||||
return swVer;
|
||||
}
|
||||
|
||||
public String getHwVer() {
|
||||
return hwVer;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public String getHwId() {
|
||||
return hwId;
|
||||
}
|
||||
|
||||
public String getFwId() {
|
||||
return fwId;
|
||||
}
|
||||
|
||||
public String getOemId() {
|
||||
return oemId;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getDevName() {
|
||||
return devName;
|
||||
}
|
||||
|
||||
public String getIconHash() {
|
||||
return iconHash;
|
||||
}
|
||||
|
||||
public OnOffType getRelayState() {
|
||||
return relayState == 1 ? OnOffType.ON : OnOffType.OFF;
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
public long getOnTime() {
|
||||
return onTime;
|
||||
}
|
||||
|
||||
public String getActiveMode() {
|
||||
return activeMode;
|
||||
}
|
||||
|
||||
public String getFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
public int getRssi() {
|
||||
// for range extender use the 2g rssi.
|
||||
return reWireless == null ? rssi : reWireless.getW2gRssi();
|
||||
}
|
||||
|
||||
public OnOffType getLedOff() {
|
||||
return ledOff == 1 ? OnOffType.OFF : OnOffType.ON;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public boolean isFactory() {
|
||||
return isFactory;
|
||||
}
|
||||
|
||||
public String getDiscoVer() {
|
||||
return discoVer;
|
||||
}
|
||||
|
||||
public String getProtocolName() {
|
||||
return ctrlProtocols == null ? null : ctrlProtocols.getName();
|
||||
}
|
||||
|
||||
public String getProtocolVersion() {
|
||||
return ctrlProtocols == null ? null : ctrlProtocols.getVersion();
|
||||
}
|
||||
|
||||
public LightState getLightState() {
|
||||
return lightState.getLightState();
|
||||
}
|
||||
|
||||
public OnOffType getLedStatus() {
|
||||
return "ON".equals(ledStatus) ? OnOffType.OFF : OnOffType.ON;
|
||||
}
|
||||
|
||||
public Plug getPlug() {
|
||||
return plug;
|
||||
}
|
||||
|
||||
public int getChildNum() {
|
||||
return childNum;
|
||||
}
|
||||
|
||||
public List<Outlet> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public Sysinfo getSystem() {
|
||||
return system;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Sysinfo} object independent of the device. The range extender devices have the system
|
||||
* information in another place as the other devices. This method returns the object independent of how the device
|
||||
* returns it.
|
||||
*
|
||||
* @return device independent {@link Sysinfo} object.
|
||||
*/
|
||||
public Sysinfo getActualSysinfo() {
|
||||
return system == null ? this : system;
|
||||
}
|
||||
|
||||
public RangeextenderWireless getReWireless() {
|
||||
return reWireless;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sysinfo [swVer=" + swVer + ", hwVer=" + hwVer + ", model=" + model + ", deviceId=" + deviceId
|
||||
+ ", hwId=" + hwId + ", oemId=" + oemId + ", alias=" + alias + ", activeMode=" + activeMode + ", rssi="
|
||||
+ rssi + ", type=" + type + ", mac=" + mac + ", fwId=" + fwId + ", devName=" + devName + ", iconHash="
|
||||
+ iconHash + ", relayState=" + relayState + ", brightness=" + brightness + ", onTime=" + onTime
|
||||
+ ", feature=" + feature + ", ledOff=" + ledOff + ", latitude=" + latitude + ", longitude=" + longitude
|
||||
+ ", isFactory=" + isFactory + ", discoVer=" + discoVer + ", ctrlProtocols=" + ctrlProtocols
|
||||
+ ", lightState=" + lightState + ", ledStatus=" + ledStatus + ", plug=" + plug + ", system=" + system
|
||||
+ ", reWireless=" + reWireless + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class to setting different kind of states on Smart Home light bulbs.
|
||||
* Only setter methods as the object is only used to send values.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class TransitionLightState {
|
||||
|
||||
/**
|
||||
* Color sets hue, saturation and brightness.
|
||||
* color temperature present to send with default 0 value to bulb.
|
||||
*/
|
||||
public static class LightStateColor extends LightStateBrightness {
|
||||
private int colorTemp;
|
||||
private int hue;
|
||||
private int saturation;
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public void setSaturation(int saturation) {
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "colorTemp" + colorTemp + ", hue:" + hue + ", saturation:" + saturation + ", " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Color Temperature doesn't set brightness therefore separate class.
|
||||
* hue and saturation present to send with default 0 value to bulb.
|
||||
*/
|
||||
public static class LightStateColorTemperature extends LightOnOff {
|
||||
private int colorTemp;
|
||||
private int hue;
|
||||
private int saturation;
|
||||
|
||||
public void setColorTemperature(int colorTemp) {
|
||||
this.colorTemp = colorTemp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "colorTemp" + colorTemp + ", hue:" + hue + ", saturation:" + saturation + ", " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class LightStateBrightness extends LightOnOff {
|
||||
private int brightness;
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
this.brightness = brightness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "brightness:" + brightness + ", " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class LightOnOff {
|
||||
private int onOff;
|
||||
private int ignoreDefault = 1;
|
||||
private String mode = "normal";
|
||||
private int transitionPeriod;
|
||||
|
||||
public void setOnOff(OnOffType onOff) {
|
||||
this.onOff = onOff == OnOffType.ON ? 1 : 0;
|
||||
}
|
||||
|
||||
public void setTransitionPeriod(int transitionPeriod) {
|
||||
this.transitionPeriod = transitionPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "onOff:" + onOff + ", ignoreDefault:" + ignoreDefault + ", mode:" + mode + ", transitionPeriod:"
|
||||
+ transitionPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LightingService {
|
||||
private LightOnOff transitionLightState;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "transitionLightState:{" + transitionLightState + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@NonNullByDefault
|
||||
@SerializedName("smartlife.iot.smartbulb.lightingservice")
|
||||
private LightingService service = new LightingService();
|
||||
|
||||
public void setLightState(LightOnOff lightState) {
|
||||
service.transitionLightState = lightState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TransitionLightState {service:{" + service + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Data class for getting the response from the Light bulb. This class is similar to {@link TransitionLightState} but
|
||||
* has no subclasses for the light state. The other class has and makes it difficult to use to deserialize by gson.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class TransitionLightStateResponse implements HasErrorResponse {
|
||||
|
||||
public static class LightingService {
|
||||
private LightState transitionLightState;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LightingService:{" + transitionLightState + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName("smartlife.iot.smartbulb.lightingservice")
|
||||
private LightingService service = new LightingService();
|
||||
|
||||
@Override
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return service.transitionLightState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TransitionLightStateResponse {service:{" + service + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="tplinksmarthome" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>TP-Link Smart Home Binding</name>
|
||||
<description>This binding integrates the TP-Link Wi-Fi Smart Home devices.</description>
|
||||
<author>Hilbrand Bouwkamp, Christian Fischer</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:device:bulb">
|
||||
<parameter name="ipAddress" type="text">
|
||||
<context>network-address</context>
|
||||
<label>IP Address</label>
|
||||
<description>IP Address of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="deviceId" type="text">
|
||||
<label>Device Id</label>
|
||||
<description>The id of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="transitionPeriod" type="integer" min="0">
|
||||
<label>Transition Period</label>
|
||||
<description>Time the transition to the new state takes in milliseconds.</description>
|
||||
<unitLabel>milliseconds</unitLabel>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Rate</label>
|
||||
<description>Refresh of device state in seconds.</description>
|
||||
<unitLabel>seconds</unitLabel>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:device:plug">
|
||||
<parameter name="ipAddress" type="text">
|
||||
<context>network-address</context>
|
||||
<label>IP Address</label>
|
||||
<description>IP Address of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="deviceId" type="text">
|
||||
<label>Device Id</label>
|
||||
<description>The id of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Rate</label>
|
||||
<description>Refresh of device state in seconds.</description>
|
||||
<unitLabel>seconds</unitLabel>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:device:switch">
|
||||
<parameter name="ipAddress" type="text">
|
||||
<context>network-address</context>
|
||||
<label>IP Address</label>
|
||||
<description>IP Address of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="deviceId" type="text">
|
||||
<label>Device Id</label>
|
||||
<description>The id of the device.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Rate</label>
|
||||
<description>Refresh of device state in seconds.</description>
|
||||
<unitLabel>seconds</unitLabel>
|
||||
<default>1</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs100">
|
||||
<label>HS100</label>
|
||||
<description>TP-Link HS100 Smart Wi-Fi Plug</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs103">
|
||||
<label>HS103</label>
|
||||
<description>TP-Link HS103 Smart Wi-Fi Plug Lite</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs105">
|
||||
<label>HS105</label>
|
||||
<description>TP-Link HS105 Smart Wi-Fi Plug</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs107">
|
||||
<label>HS107</label>
|
||||
<description>TP-Link HS107 Smart Wi-Fi Plug, 2-Outlets</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="groupSwitch" typeId="switch-group"/>
|
||||
<channel-group id="outlet1" typeId="switch-outlet">
|
||||
<label>Outlet 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet2" typeId="switch-outlet">
|
||||
<label>Outlet 2</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs110">
|
||||
<label>HS110</label>
|
||||
<description>TP-Link HS110 Smart Wi-Fi Plug with Energy Monitoring</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="energyUsage" typeId="energy-usage"/>
|
||||
<channel id="current" typeId="current"/>
|
||||
<channel id="voltage" typeId="voltage"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs200">
|
||||
<label>HS200</label>
|
||||
<description>TP-Link HS200 Smart Wi-Fi Switch</description>
|
||||
<category>WallSwitch</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:switch"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs210">
|
||||
<label>HS210</label>
|
||||
<description>TP-Link HS210 Smart Wi-Fi Light Switch 3-Way Kit</description>
|
||||
<category>WallSwitch</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:switch"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs220">
|
||||
<label>HS220</label>
|
||||
<description>TP-Link HS220 Smart Wi-Fi Light Switch, Dimmer</description>
|
||||
<category>WallSwitch</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:switch"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="hs300">
|
||||
<label>HS300</label>
|
||||
<description>TP-Link HS300 Smart Wi-Fi Power Strip</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="group" typeId="switch-group"/>
|
||||
<channel-group id="outlet1" typeId="energy-outlet">
|
||||
<label>Outlet 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet2" typeId="energy-outlet">
|
||||
<label>Outlet 2</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet3" typeId="energy-outlet">
|
||||
<label>Outlet 3</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet4" typeId="energy-outlet">
|
||||
<label>Outlet 4</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet5" typeId="energy-outlet">
|
||||
<label>Outlet 5</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet6" typeId="energy-outlet">
|
||||
<label>Outlet 6</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kb100">
|
||||
<label>KB100</label>
|
||||
<description>TP-Link KB100 Kasa Smart Light Bulb</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kb130">
|
||||
<label>KB130</label>
|
||||
<description>TP-Link KB130 Kasa Multi-color Smart Light Bulb</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs2"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kl110">
|
||||
<label>KL110</label>
|
||||
<description>TP-Link KL110 Smart Wi-Fi LED Bulb with Brightness</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kl120">
|
||||
<label>KL120</label>
|
||||
<description>TP-Link KL120 Smart Wi-Fi LED Bulb with Tunable White Light Brightness</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs1"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kl130">
|
||||
<label>KL130</label>
|
||||
<description>TP-Link KL130 Smart Wi-Fi LED Bulb with Color Changing Hue</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs2"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kl50">
|
||||
<label>KL50</label>
|
||||
<description>Kasa Filament Smart Bulb, Soft White</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kl60">
|
||||
<label>KL60</label>
|
||||
<description>Kasa Filament Smart Bulb, Warm Amber</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kp100">
|
||||
<label>KP100</label>
|
||||
<description>TP-Link KP100 Kasa Wi-Fi Smart Plug - Slim Edition</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kp105">
|
||||
<label>KP105</label>
|
||||
<description>TP-Link KP105 Kasa Wi-Fi Smart Plug - Slim Edition</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kp200">
|
||||
<label>KP200</label>
|
||||
<description>TP-Link KP200 Smart Wi-Fi Power Outlet, 2-Sockets</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="groupSwitch" typeId="switch-group"/>
|
||||
<channel-group id="outlet1" typeId="switch-outlet">
|
||||
<label>Outlet 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet2" typeId="switch-outlet">
|
||||
<label>Outlet 2</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kp303">
|
||||
<label>KP303</label>
|
||||
<description>TP-Link HS300 Smart Wi-Fi Power Strip, 3-Outlets</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="group" typeId="switch-group"/>
|
||||
<channel-group id="outlet1" typeId="switch-outlet">
|
||||
<label>Outlet 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet2" typeId="switch-outlet">
|
||||
<label>Outlet 2</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet3" typeId="switch-outlet">
|
||||
<label>Outlet 3</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="kp400">
|
||||
<label>KP400</label>
|
||||
<description>TP-Link KP400 Smart Outdoor Plug</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="groupSwitch" typeId="switch-group"/>
|
||||
<channel-group id="outlet1" typeId="switch-outlet">
|
||||
<label>Outlet 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="outlet2" typeId="switch-outlet">
|
||||
<label>Outlet 2</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb100">
|
||||
<label>LB100</label>
|
||||
<description>TP-Link LB100 Smart Wi-Fi LED Bulb with Dimmable Light</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb110">
|
||||
<label>LB110</label>
|
||||
<description>TP-Link LB110 Smart Wi-Fi LED Bulb with Dimmable Light</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb120">
|
||||
<label>LB120</label>
|
||||
<description>TP-Link LB120 Smart Wi-Fi LED Bulb with Tunable White Light</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs1"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb130">
|
||||
<label>LB130</label>
|
||||
<description>TP-Link LB130 Smart Wi-Fi LED Bulb with Color Changing Hue</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs2"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb200">
|
||||
<label>LB200</label>
|
||||
<description>TP-Link LB200 Smart Wi-Fi LED Bulb with Dimmable Light</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="lb230">
|
||||
<label>LB230</label>
|
||||
<description>TP-Link LB230 Smart Wi-Fi LED Bulb with Color Changing Hue</description>
|
||||
<category>Lightbulb</category>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="colorTemperature" typeId="system.color-temperature"/>
|
||||
<channel id="colorTemperatureAbs" typeId="colorTemperatureAbs2"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:bulb"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="re270">
|
||||
<label>RE270K</label>
|
||||
<description>TP-Link AC750 Wi-Fi Range Extender with Smart Plug</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="switch-readonly"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<thing-type id="re370">
|
||||
<label>RE370K</label>
|
||||
<description>TP-Link AC1200 Wi-Fi Range Extender with Smart Plug</description>
|
||||
<category>PowerOutlet</category>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="switch-readonly"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>deviceId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:device:plug"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="tplinksmarthome"
|
||||
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">
|
||||
|
||||
<!-- Primary Channel types -->
|
||||
<channel-type id="switch-readonly">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch</label>
|
||||
<description>Shows the switch state of the Smart Home device.</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="led" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch Led</label>
|
||||
<description>Switch the Smart Home device led on or off.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<!-- Absolute Temperature Channel -->
|
||||
<channel-type id="colorTemperatureAbs1" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Color Temperature</label>
|
||||
<description>This channel supports adjusting the color temperature from 2700K to 6500K.</description>
|
||||
<category>ColorLight</category>
|
||||
<state min="2700" max="6500" pattern="%d K"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="colorTemperatureAbs2" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Color Temperature</label>
|
||||
<description>This channel supports adjusting the color temperature from 2500K to 9000K.</description>
|
||||
<category>ColorLight</category>
|
||||
<state min="2500" max="9000" pattern="%d K"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Energy Channel types -->
|
||||
<channel-type id="power">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Power</label>
|
||||
<description>Actual power usage.</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"></state>
|
||||
</channel-type>
|
||||
<channel-type id="energy-usage">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Energy Usage</label>
|
||||
<description>Actual energy usage.</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"></state>
|
||||
</channel-type>
|
||||
<channel-type id="current" advanced="true">
|
||||
<item-type>Number:ElectricCurrent</item-type>
|
||||
<label>Current</label>
|
||||
<description>Actual current usage.</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"></state>
|
||||
</channel-type>
|
||||
<channel-type id="voltage" advanced="true">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Voltage</label>
|
||||
<description>Actual voltage usage.</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.0f %unit%"></state>
|
||||
</channel-type>
|
||||
|
||||
<!-- Misc Channel types -->
|
||||
<channel-type id="rssi" advanced="true">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Signal</label>
|
||||
<description>Wi-Fi signal strength indicator.</description>
|
||||
<category>QualityOfService</category>
|
||||
<state readOnly="true" pattern="%d %unit%"></state>
|
||||
</channel-type>
|
||||
|
||||
<!-- Channel Groups types -->
|
||||
<channel-group-type id="switch-group">
|
||||
<label>Outlet Group</label>
|
||||
<category>PowerOutlet</category>
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="led" typeId="led"/>
|
||||
<channel id="rssi" typeId="rssi"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
<channel-group-type id="switch-outlet">
|
||||
<label>Outlet</label>
|
||||
<category>PowerOutlet</category>
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
<channel-group-type id="energy-outlet">
|
||||
<label>Outlet</label>
|
||||
<category>PowerOutlet</category>
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="energyUsage" typeId="energy-usage"/>
|
||||
<channel id="current" typeId="current"/>
|
||||
<channel id="voltage" typeId="voltage"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class ChannelUIDConstants {
|
||||
|
||||
public static final ChannelUID CHANNEL_UID_BRIGHTNESS = createChannel(LB130, CHANNEL_BRIGHTNESS);
|
||||
public static final ChannelUID CHANNEL_UID_COLOR = createChannel(LB130, CHANNEL_COLOR);
|
||||
public static final ChannelUID CHANNEL_UID_COLOR_TEMPERATURE = createChannel(LB130, CHANNEL_COLOR_TEMPERATURE);
|
||||
public static final ChannelUID CHANNEL_UID_COLOR_TEMPERATURE_ABS = createChannel(LB130,
|
||||
CHANNEL_COLOR_TEMPERATURE_ABS);
|
||||
public static final ChannelUID CHANNEL_UID_ENERGY_CURRENT = createChannel(HS110, CHANNEL_ENERGY_CURRENT);
|
||||
public static final ChannelUID CHANNEL_UID_ENERGY_POWER = createChannel(HS110, CHANNEL_ENERGY_POWER);
|
||||
public static final ChannelUID CHANNEL_UID_ENERGY_TOTAL = createChannel(HS110, CHANNEL_ENERGY_TOTAL);
|
||||
public static final ChannelUID CHANNEL_UID_ENERGY_VOLTAGE = createChannel(HS110, CHANNEL_ENERGY_VOLTAGE);
|
||||
public static final ChannelUID CHANNEL_UID_LED = createChannel(HS100, CHANNEL_LED);
|
||||
public static final ChannelUID CHANNEL_UID_OTHER = createChannel(HS100, "OTHER");
|
||||
public static final ChannelUID CHANNEL_UID_RSSI = createChannel(HS100, CHANNEL_RSSI);
|
||||
public static final ChannelUID CHANNEL_UID_SWITCH = createChannel(HS100, CHANNEL_SWITCH);
|
||||
|
||||
private static final String ID = "1234";
|
||||
|
||||
private ChannelUIDConstants() {
|
||||
// Util class
|
||||
}
|
||||
|
||||
private static ChannelUID createChannel(TPLinkSmartHomeThingType thingType, String channelId) {
|
||||
return new ChannelUID(new ThingUID(thingType.thingTypeUID(), ID), channelId);
|
||||
}
|
||||
|
||||
public static ChannelUID createChannel(TPLinkSmartHomeThingType thingType, String groupId, String channelId) {
|
||||
return new ChannelUID(new ThingUID(thingType.thingTypeUID(), ID), groupId, channelId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for {@link CryptUtil} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class CryptUtilTest {
|
||||
|
||||
private static final String TEST_STRING = "This is just a message";
|
||||
|
||||
/**
|
||||
* Test round trip of encrypt and decrypt that should return the same value.
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
@Test
|
||||
public void testCrypt() throws IOException {
|
||||
assertEquals("Crypting should result in same string", TEST_STRING,
|
||||
CryptUtil.decrypt(CryptUtil.encrypt(TEST_STRING), TEST_STRING.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test round trip of encrypt and decrypt with length that should return the same value.
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
@Test
|
||||
public void testCryptWithLength() throws IOException {
|
||||
try (final ByteArrayInputStream is = new ByteArrayInputStream(CryptUtil.encryptWithLength(TEST_STRING))) {
|
||||
assertEquals("Crypting should result in same string", TEST_STRING, CryptUtil.decryptWithLength(is));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.GetSysinfo;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
|
||||
/**
|
||||
* Test class for {@link PropertiesCollector} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PropertiesCollectorTest {
|
||||
|
||||
/**
|
||||
* Tests if properties for a bulb device are correctly parsed.
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
@Test
|
||||
public void testBulbProperties() throws IOException {
|
||||
assertProperties("bulb_get_sysinfo_response_on", TPLinkSmartHomeThingType.LB130, 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if properties for a switch device are correctly parsed.
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
@Test
|
||||
public void testSwitchProperties() throws IOException {
|
||||
assertProperties("plug_get_sysinfo_response", TPLinkSmartHomeThingType.HS100, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if properties for a range extender device are correctly parsed.
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
@Test
|
||||
public void testRangeExtenderProperties() throws IOException {
|
||||
assertProperties("rangeextender_get_sysinfo_response", TPLinkSmartHomeThingType.RE270K, 11);
|
||||
}
|
||||
|
||||
private void assertProperties(String responseFile, TPLinkSmartHomeThingType thingType, int expectedSize)
|
||||
throws IOException {
|
||||
final Map<String, Object> props = PropertiesCollector.collectProperties(thingType, "localhost",
|
||||
ModelTestUtil.jsonFromFile(responseFile, GetSysinfo.class).getSysinfo());
|
||||
|
||||
assertEquals("Number of properties not as expected for properties: " + props, expectedSize, props.size());
|
||||
props.entrySet().stream().forEach(
|
||||
entry -> assertNotNull("Property '" + entry.getKey() + "' should not be null", entry.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.core.config.discovery.DiscoveryListener;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
|
||||
/**
|
||||
* Test class for {@link TPLinkSmartHomeDiscoveryService} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class TPLinkSmartHomeDiscoveryServiceTest {
|
||||
|
||||
private static final List<Object[]> TESTS = Arrays.asList(
|
||||
new Object[][] { { "bulb_get_sysinfo_response_on", 11 }, { "rangeextender_get_sysinfo_response", 11 } });
|
||||
|
||||
@Mock
|
||||
private DatagramSocket discoverSocket;
|
||||
|
||||
@Mock
|
||||
private DiscoveryListener discoveryListener;
|
||||
|
||||
private TPLinkSmartHomeDiscoveryService discoveryService;
|
||||
|
||||
private final String filename;
|
||||
private final int propertiesSize;
|
||||
|
||||
public TPLinkSmartHomeDiscoveryServiceTest(String filename, int propertiesSize) {
|
||||
this.filename = filename;
|
||||
this.propertiesSize = propertiesSize;
|
||||
}
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static List<Object[]> data() {
|
||||
return TESTS;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
initMocks(this);
|
||||
discoveryService = new TPLinkSmartHomeDiscoveryService() {
|
||||
@Override
|
||||
protected DatagramSocket sendDiscoveryPacket() throws IOException {
|
||||
return discoverSocket;
|
||||
}
|
||||
};
|
||||
doAnswer(new Answer<Void>() {
|
||||
private int cnt;
|
||||
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
if (cnt++ > 0) {
|
||||
throw new SocketTimeoutException("Only test 1 thing discovery");
|
||||
}
|
||||
DatagramPacket packet = (DatagramPacket) invocation.getArguments()[0];
|
||||
packet.setAddress(InetAddress.getLocalHost());
|
||||
packet.setData(CryptUtil.encrypt(ModelTestUtil.readJson(filename)));
|
||||
return null;
|
||||
}
|
||||
}).when(discoverSocket).receive(any());
|
||||
discoveryService.addDiscoveryListener(discoveryListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if startScan method finds a device with expected properties.
|
||||
*/
|
||||
@Test
|
||||
public void testScan() {
|
||||
discoveryService.startScan();
|
||||
ArgumentCaptor<DiscoveryResult> discoveryResultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
|
||||
verify(discoveryListener).thingDiscovered(any(), discoveryResultCaptor.capture());
|
||||
DiscoveryResult discoveryResult = discoveryResultCaptor.getValue();
|
||||
assertEquals("Check if correct binding id found", TPLinkSmartHomeBindingConstants.BINDING_ID,
|
||||
discoveryResult.getBindingId());
|
||||
assertEquals("Check if expected number of properties found", propertiesSize,
|
||||
discoveryResult.getProperties().size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.mockito.Mock;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.BulbDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.DimmerDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.EnergySwitchDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.PowerStripDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.RangeExtenderDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.SwitchDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.handler.SmartHomeHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Test class for {@link TPLinkSmartHomeHandlerFactory}.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class TPLinkSmartHomeHandlerFactoryTest {
|
||||
|
||||
private static final String SMART_HOME_DEVICE_FIELD = "smartHomeDevice";
|
||||
|
||||
private final TPLinkSmartHomeHandlerFactory factory = new TPLinkSmartHomeHandlerFactory();
|
||||
|
||||
// @formatter:off
|
||||
private static final List<Object[]> TESTS = Arrays.asList(new Object[][] {
|
||||
{ "hs100", SwitchDevice.class },
|
||||
{ "hs110", EnergySwitchDevice.class },
|
||||
{ "hs200", SwitchDevice.class },
|
||||
{ "hs220", DimmerDevice.class },
|
||||
{ "hs300", PowerStripDevice.class },
|
||||
{ "lb100", BulbDevice.class },
|
||||
{ "lb120", BulbDevice.class },
|
||||
{ "lb130", BulbDevice.class },
|
||||
{ "lb230", BulbDevice.class },
|
||||
{ "kl110", BulbDevice.class },
|
||||
{ "kl120", BulbDevice.class },
|
||||
{ "kl130", BulbDevice.class },
|
||||
{ "re270", RangeExtenderDevice.class },
|
||||
{ "unknown", null },
|
||||
});
|
||||
// @formatter:on
|
||||
|
||||
@Mock
|
||||
Thing thing;
|
||||
|
||||
private final String name;
|
||||
private final Class<?> clazz;
|
||||
|
||||
public TPLinkSmartHomeHandlerFactoryTest(String name, Class<?> clazz) {
|
||||
this.name = name;
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Parameters(name = "{0} - {1}")
|
||||
public static List<Object[]> data() {
|
||||
return TESTS;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectClass()
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
when(thing.getThingTypeUID()).thenReturn(new ThingTypeUID(TPLinkSmartHomeBindingConstants.BINDING_ID, name));
|
||||
SmartHomeHandler handler = (SmartHomeHandler) factory.createHandler(thing);
|
||||
|
||||
if (clazz == null) {
|
||||
assertNull(name + " should not return any handler but null", handler);
|
||||
} else {
|
||||
assertNotNull(name + " should no return null handler", handler);
|
||||
Field smartHomeDeviceField = SmartHomeHandler.class.getDeclaredField(SMART_HOME_DEVICE_FIELD);
|
||||
|
||||
smartHomeDeviceField.setAccessible(true);
|
||||
assertSame(name + " should return expected device class", clazz,
|
||||
smartHomeDeviceField.get(handler).getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.LB130;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Test class for {@link BulbDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BulbDeviceTest extends DeviceTestBase<BulbDevice> {
|
||||
|
||||
private static final String DEVICE_OFF = "bulb_get_sysinfo_response_off";
|
||||
|
||||
public BulbDeviceTest() throws IOException {
|
||||
super(new BulbDevice(LB130.thingTypeUID(), COLOR_TEMPERATURE_2_MIN, COLOR_TEMPERATURE_2_MAX),
|
||||
"bulb_get_sysinfo_response_on");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws IOException {
|
||||
super.setUp();
|
||||
setSocketReturnAssert("bulb_transition_light_state_response");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandBrightness() throws IOException {
|
||||
assertInput("bulb_transition_light_state_brightness");
|
||||
assertTrue("Brightness channel should be handled",
|
||||
device.handleCommand(CHANNEL_UID_BRIGHTNESS, new PercentType(33)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandBrightnessOnOff() throws IOException {
|
||||
assertInput("bulb_transition_light_state_on");
|
||||
assertTrue("Brightness channel with OnOff state should be handled",
|
||||
device.handleCommand(CHANNEL_UID_BRIGHTNESS, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandColor() throws IOException {
|
||||
assertInput("bulb_transition_light_state_color");
|
||||
assertTrue("Color channel should be handled", device.handleCommand(CHANNEL_UID_COLOR, new HSBType("55,44,33")));
|
||||
}
|
||||
|
||||
public void testHandleCommandColorBrightness() throws IOException {
|
||||
assertInput("bulb_transition_light_state_brightness");
|
||||
assertTrue("Color channel with Percentage state (=brightness) should be handled",
|
||||
device.handleCommand(CHANNEL_UID_COLOR, new PercentType(33)));
|
||||
}
|
||||
|
||||
public void testHandleCommandColorOnOff() throws IOException {
|
||||
assertInput("bulb_transition_light_state_on");
|
||||
assertTrue("Color channel with OnOff state should be handled",
|
||||
device.handleCommand(CHANNEL_UID_COLOR, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandColorTemperature() throws IOException {
|
||||
assertInput("bulb_transition_light_state_color_temp");
|
||||
assertTrue("Color temperature channel should be handled",
|
||||
device.handleCommand(CHANNEL_UID_COLOR_TEMPERATURE, new PercentType(40)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandColorTemperatureAbs() throws IOException {
|
||||
assertInput("bulb_transition_light_state_color_temp");
|
||||
assertTrue("Color temperature channel should be handled",
|
||||
device.handleCommand(CHANNEL_UID_COLOR_TEMPERATURE_ABS, new DecimalType(5100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandColorTemperatureOnOff() throws IOException {
|
||||
assertInput("bulb_transition_light_state_on");
|
||||
assertTrue("Color temperature channel with OnOff state should be handled",
|
||||
device.handleCommand(CHANNEL_UID_COLOR_TEMPERATURE, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandSwitch() throws IOException {
|
||||
assertInput("bulb_transition_light_state_on");
|
||||
assertTrue("Switch channel should be handled", device.handleCommand(CHANNEL_UID_SWITCH, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelBrightnessOn() {
|
||||
assertEquals("Brightness should be on", new PercentType(92),
|
||||
device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelBrightnessOff() throws IOException {
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
|
||||
assertEquals("Brightness should be off", PercentType.ZERO,
|
||||
device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelColorOn() {
|
||||
assertEquals("Color should be on", new HSBType("7,44,92"),
|
||||
device.updateChannel(CHANNEL_UID_COLOR, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelColorOff() throws IOException {
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
|
||||
assertEquals("Color should be off", new HSBType("7,44,0"),
|
||||
device.updateChannel(CHANNEL_UID_COLOR, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelSwitchOn() {
|
||||
assertSame("Switch should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelSwitchOff() throws IOException {
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
|
||||
assertSame("Switch should be off", OnOffType.OFF, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelColorTemperature() {
|
||||
assertEquals("Color temperature should be set", new PercentType(2),
|
||||
device.updateChannel(CHANNEL_UID_COLOR_TEMPERATURE, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelColorTemperatureAbs() {
|
||||
assertEquals("Color temperature should be set", new DecimalType(2630),
|
||||
device.updateChannel(CHANNEL_UID_COLOR_TEMPERATURE_ABS, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOther() {
|
||||
assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
|
||||
device.updateChannel(CHANNEL_UID_OTHER, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelPower() {
|
||||
assertEquals("Power values should be set", new DecimalType(10.8),
|
||||
device.updateChannel(CHANNEL_UID_ENERGY_POWER, deviceState));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mock;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Connection;
|
||||
import org.openhab.binding.tplinksmarthome.internal.CryptUtil;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
|
||||
/**
|
||||
* Base class for tests that test classes extending {@link SmartHomeDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DeviceTestBase<T extends SmartHomeDevice> {
|
||||
|
||||
protected final T device;
|
||||
protected final Connection connection;
|
||||
protected final TPLinkSmartHomeConfiguration configuration = new TPLinkSmartHomeConfiguration();
|
||||
protected @NonNullByDefault({}) DeviceState deviceState;
|
||||
|
||||
private final String deviceStateFilename;
|
||||
|
||||
@Mock
|
||||
private @NonNullByDefault({}) Socket socket;
|
||||
@Mock
|
||||
private @NonNullByDefault({}) OutputStream outputStream;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param device Device under test
|
||||
* @param deviceStateFilename name of the file to read the device state json from to use in tests
|
||||
*
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
protected DeviceTestBase(T device, String deviceStateFilename) throws IOException {
|
||||
this.device = device;
|
||||
this.deviceStateFilename = deviceStateFilename;
|
||||
configuration.ipAddress = "localhost";
|
||||
configuration.refresh = 30;
|
||||
configuration.transitionPeriod = 10;
|
||||
connection = new Connection(configuration.ipAddress) {
|
||||
@Override
|
||||
protected Socket createSocket() throws IOException {
|
||||
return socket;
|
||||
}
|
||||
};
|
||||
device.initialize(connection, configuration);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
initMocks(this);
|
||||
when(socket.getOutputStream()).thenReturn(outputStream);
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson(deviceStateFilename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the answer to return when the socket.getInputStream() is requested. If multiple files are given they will
|
||||
* returned in order each time a call to socket.getInputStream() is done.
|
||||
*
|
||||
* @param responseFilenames names of the files to read that contains the answer. It's the unencrypted json string
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
protected void setSocketReturnAssert(String... responseFilenames) throws IOException {
|
||||
AtomicInteger index = new AtomicInteger();
|
||||
|
||||
doAnswer(i -> {
|
||||
String stateResponse = ModelTestUtil.readJson(responseFilenames[index.getAndIncrement()]);
|
||||
|
||||
return new ByteArrayInputStream(CryptUtil.encryptWithLength(stateResponse));
|
||||
}).when(socket).getInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the value passed to outputstream.write, which is the call that would be made to the actual device. This
|
||||
* checks if the value sent to the device is what is expected to be sent to the device. If multiple files are given
|
||||
* they will be used to check in order each time a call outputstream.write is done.
|
||||
*
|
||||
* @param filenames names of the files containing the reference json
|
||||
* @throws IOException exception in case device not reachable
|
||||
*/
|
||||
protected void assertInput(String... filenames) throws IOException {
|
||||
assertInput(Function.identity(), Function.identity(), filenames);
|
||||
}
|
||||
|
||||
protected void assertInput(Function<String, String> jsonProcessor, Function<String, String> expectedProcessor,
|
||||
String... filenames) throws IOException {
|
||||
AtomicInteger index = new AtomicInteger();
|
||||
|
||||
doAnswer(arg -> {
|
||||
String json = jsonProcessor.apply(ModelTestUtil.readJson(filenames[index.get()]));
|
||||
|
||||
byte[] input = (byte[]) arg.getArguments()[0];
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(input)) {
|
||||
String expectedString = expectedProcessor.apply(CryptUtil.decryptWithLength(inputStream));
|
||||
assertEquals(filenames[index.get()], json, expectedString);
|
||||
}
|
||||
index.incrementAndGet();
|
||||
return null;
|
||||
}).when(outputStream).write(any());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Test class for {@link DimmerDevice}.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DimmerDeviceTest extends DeviceTestBase<DimmerDevice> {
|
||||
|
||||
private static final PercentType BRIGHTNESS_VALUE = new PercentType(50);
|
||||
|
||||
public DimmerDeviceTest() throws IOException {
|
||||
super(new DimmerDevice(), "hs220_get_sysinfo_response_on");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandBrightnessOnOff() throws IOException {
|
||||
assertInput("dimmer_set_switch_state_on");
|
||||
setSocketReturnAssert("dimmer_set_switch_state_on");
|
||||
assertTrue("Brightness channel as OnOffType type should be handled",
|
||||
device.handleCommand(CHANNEL_UID_BRIGHTNESS, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandBrightnessZero() throws IOException {
|
||||
assertInput("dimmer_set_switch_state_off");
|
||||
setSocketReturnAssert("dimmer_set_switch_state_response");
|
||||
assertTrue("Brightness channel with percentage 0 should be handled",
|
||||
device.handleCommand(CHANNEL_UID_BRIGHTNESS, PercentType.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandBrightness() throws IOException {
|
||||
assertInput("dimmer_set_brightness", "dimmer_set_switch_state_on");
|
||||
setSocketReturnAssert("dimmer_set_brightness_response", "dimmer_set_switch_state_on");
|
||||
assertTrue("Brightness channel should be handled",
|
||||
device.handleCommand(CHANNEL_UID_BRIGHTNESS, new PercentType(17)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelSwitch() throws IOException {
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson("hs220_get_sysinfo_response_off"));
|
||||
|
||||
assertSame("Dimmer device should be off", OnOffType.OFF,
|
||||
((PercentType) device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState)).as(OnOffType.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelBrightness() {
|
||||
assertEquals("Dimmer brightness should be set", BRIGHTNESS_VALUE,
|
||||
device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOther() {
|
||||
assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
|
||||
device.updateChannel(CHANNEL_UID_OTHER, deviceState));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class to test if text read from the device is correctly decoded to handle special characters.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EncodingTest extends DeviceTestBase<SwitchDevice> {
|
||||
|
||||
public EncodingTest() throws IOException {
|
||||
super(new SwitchDevice(), "encoding_test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectDecodingOfText() throws IOException {
|
||||
assertThat("Alias incorrectly decoded", deviceState.getSysinfo().getAlias(), is("MyßmärtPlug"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Test class for {@link EnergySwitchDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
@NonNullByDefault
|
||||
public class EnergySwitchDeviceTest {
|
||||
|
||||
private static final List<Object[]> TESTS = Arrays
|
||||
.asList(new Object[][] { { "plug_get_realtime_response", }, { "plug_get_realtime_response_v2", } });
|
||||
|
||||
private final EnergySwitchDevice device = new EnergySwitchDevice();
|
||||
private final DeviceState deviceState;
|
||||
|
||||
public EnergySwitchDeviceTest(String name) throws IOException {
|
||||
deviceState = new DeviceState(ModelTestUtil.readJson(name));
|
||||
}
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static List<Object[]> data() {
|
||||
return TESTS;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelEnergyCurrent() {
|
||||
assertEquals("Energy current should have valid state value", new QuantityType<>(1 + " A"),
|
||||
device.updateChannel(CHANNEL_UID_ENERGY_CURRENT, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelEnergyTotal() {
|
||||
assertEquals("Energy total should have valid state value", new QuantityType<>(10 + " kWh"),
|
||||
device.updateChannel(CHANNEL_UID_ENERGY_TOTAL, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelEnergyVoltage() {
|
||||
State state = device.updateChannel(CHANNEL_UID_ENERGY_VOLTAGE, deviceState);
|
||||
assertEquals("Energy voltage should have valid state value", 230, ((QuantityType<?>) state).intValue());
|
||||
assertEquals("Channel patten to format voltage correctly", "230 V", state.format("%.0f %unit%"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChanneEnergyPower() {
|
||||
assertEquals("Energy power should have valid state value", new QuantityType<>(20 + " W"),
|
||||
device.updateChannel(CHANNEL_UID_ENERGY_POWER, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOther() {
|
||||
assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
|
||||
device.updateChannel(CHANNEL_UID_OTHER, deviceState));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.HS300;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.SetRelayState;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
|
||||
/**
|
||||
* Test class for {@link PowerStripDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PowerStripDeviceTest extends DeviceTestBase<PowerStripDevice> {
|
||||
|
||||
private static final ChannelUID CHANNEL_OUTLET_1 = ChannelUIDConstants.createChannel(HS300,
|
||||
CHANNEL_OUTLET_GROUP_PREFIX + '1', CHANNEL_SWITCH);
|
||||
private static final ChannelUID CHANNEL_OUTLET_2 = ChannelUIDConstants.createChannel(HS300,
|
||||
CHANNEL_OUTLET_GROUP_PREFIX + '2', CHANNEL_SWITCH);
|
||||
private static final ChannelUID CHANNEL_ENERGY_CURRENT_OUTLET_2 = ChannelUIDConstants.createChannel(HS300,
|
||||
CHANNEL_OUTLET_GROUP_PREFIX + '2', CHANNEL_ENERGY_CURRENT);
|
||||
private static final String[] REALTIME_INPUTS = IntStream.range(0, 6).mapToObj(i -> "hs300_get_realtime")
|
||||
.collect(Collectors.toList()).toArray(new String[0]);
|
||||
private static final String[] REALTIME_RESPONSES = IntStream.range(0, 6).mapToObj(i -> "plug_get_realtime_response")
|
||||
.collect(Collectors.toList()).toArray(new String[0]);
|
||||
|
||||
public PowerStripDeviceTest() throws IOException {
|
||||
super(new PowerStripDevice(HS300), "hs300_get_sysinfo_response");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
super.setUp();
|
||||
final AtomicInteger inputCounter = new AtomicInteger(0);
|
||||
final Function<String, String> inputWrapper = s -> s.replace("001", "00" + inputCounter.incrementAndGet());
|
||||
|
||||
assertInput(inputWrapper, Function.identity(), REALTIME_INPUTS);
|
||||
setSocketReturnAssert(REALTIME_RESPONSES);
|
||||
device.refreshedDeviceState(deviceState);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandSwitchChannel2() throws IOException {
|
||||
Function<String, String> normalize = s -> ModelTestUtil.GSON
|
||||
.toJson(ModelTestUtil.GSON.fromJson(s, SetRelayState.class));
|
||||
assertInput(normalize, normalize, "hs300_set_relay_state");
|
||||
setSocketReturnAssert("hs300_set_relay_state_response");
|
||||
assertTrue("Outlet channel 2 should be handled", device.handleCommand(CHANNEL_OUTLET_2, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOutlet1() {
|
||||
assertSame("Outlet 1 should be on", OnOffType.ON, device.updateChannel(CHANNEL_OUTLET_1, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOutlet2() {
|
||||
assertSame("Outlet 2 should be off", OnOffType.OFF, device.updateChannel(CHANNEL_OUTLET_2, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelEnergyCurrent() {
|
||||
assertEquals("Energy current should have valid state value", 1,
|
||||
((QuantityType<?>) device.updateChannel(CHANNEL_ENERGY_CURRENT_OUTLET_2, deviceState)).intValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Test class for {@link RangeExtenderDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RangeExtenderDeviceTest extends DeviceTestBase<RangeExtenderDevice> {
|
||||
|
||||
public RangeExtenderDeviceTest() throws IOException {
|
||||
super(new RangeExtenderDevice(), "rangeextender_get_sysinfo_response");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandSwitch() throws IOException {
|
||||
assertFalse("Switch channel not yet supported so should not be handled",
|
||||
device.handleCommand(CHANNEL_UID_SWITCH, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelSwitch() {
|
||||
assertSame("Switch should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelLed() {
|
||||
assertSame("Led should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_LED, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOther() {
|
||||
assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
|
||||
device.updateChannel(CHANNEL_UID_OTHER, deviceState));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Test class for {@link SwitchDevice} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SwitchDeviceTest extends DeviceTestBase<SwitchDevice> {
|
||||
|
||||
public SwitchDeviceTest() throws IOException {
|
||||
super(new SwitchDevice(), "plug_get_sysinfo_response");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandSwitch() throws IOException {
|
||||
assertInput("plug_set_relay_state_on");
|
||||
setSocketReturnAssert("plug_set_relay_state_on");
|
||||
assertTrue("Switch channel should be handled", device.handleCommand(CHANNEL_UID_SWITCH, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandLed() throws IOException {
|
||||
assertInput("plug_set_led_on");
|
||||
setSocketReturnAssert("plug_set_led_on");
|
||||
assertTrue("Led channel should be handled", device.handleCommand(CHANNEL_UID_LED, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelSwitch() {
|
||||
assertSame("Switch should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelLed() {
|
||||
assertSame("Led should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_LED, deviceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChannelOther() {
|
||||
assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
|
||||
device.updateChannel(CHANNEL_UID_OTHER, deviceState));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.handler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.CHANNEL_UID_SWITCH;
|
||||
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Commands;
|
||||
import org.openhab.binding.tplinksmarthome.internal.Connection;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeDiscoveryService;
|
||||
import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType;
|
||||
import org.openhab.binding.tplinksmarthome.internal.device.SmartHomeDevice;
|
||||
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link SmartHomeHandler} class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SmartHomeHandlerTest {
|
||||
|
||||
private @NonNullByDefault({}) SmartHomeHandler handler;
|
||||
|
||||
@Mock
|
||||
private @NonNullByDefault({}) Connection connection;
|
||||
@Mock
|
||||
private @NonNullByDefault({}) ThingHandlerCallback callback;
|
||||
@Mock
|
||||
private @NonNullByDefault({}) Thing thing;
|
||||
@Mock
|
||||
private @NonNullByDefault({}) SmartHomeDevice smartHomeDevice;
|
||||
@Mock
|
||||
private @NonNullByDefault({}) TPLinkSmartHomeDiscoveryService discoveryService;
|
||||
|
||||
private final Configuration configuration = new Configuration();
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
initMocks(this);
|
||||
configuration.put(CONFIG_IP, "localhost");
|
||||
configuration.put(CONFIG_REFRESH, 1);
|
||||
when(thing.getConfiguration()).thenReturn(configuration);
|
||||
when(smartHomeDevice.getUpdateCommand()).thenReturn(Commands.getSysinfo());
|
||||
when(connection.sendCommand(Commands.getSysinfo()))
|
||||
.thenReturn(ModelTestUtil.readJson("plug_get_sysinfo_response"));
|
||||
handler = new SmartHomeHandler(thing, smartHomeDevice, TPLinkSmartHomeThingType.HS100, discoveryService) {
|
||||
@Override
|
||||
Connection createConnection(TPLinkSmartHomeConfiguration config) {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
when(smartHomeDevice.handleCommand(eq(CHANNEL_UID_SWITCH), any())).thenReturn(true);
|
||||
when(callback.isChannelLinked(any())).thenReturn(true);
|
||||
handler.setCallback(callback);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
handler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeShouldCallTheCallback() throws InterruptedException {
|
||||
handler.initialize();
|
||||
ArgumentCaptor<ThingStatusInfo> statusInfoCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
|
||||
|
||||
verify(callback).statusUpdated(eq(thing), statusInfoCaptor.capture());
|
||||
ThingStatusInfo thingStatusInfo = statusInfoCaptor.getValue();
|
||||
assertEquals("Device should be unknown", ThingStatus.UNKNOWN, thingStatusInfo.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandRefreshType() {
|
||||
handler.initialize();
|
||||
assertHandleCommandRefreshType(-53);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandRefreshTypeRangeExtender() throws IOException {
|
||||
when(connection.sendCommand(Commands.getSysinfo()))
|
||||
.thenReturn(ModelTestUtil.readJson("rangeextender_get_sysinfo_response"));
|
||||
handler.initialize();
|
||||
assertHandleCommandRefreshType(-70);
|
||||
}
|
||||
|
||||
private void assertHandleCommandRefreshType(int expectedRssi) {
|
||||
handler.initialize();
|
||||
ChannelUID channelUID = ChannelUIDConstants.CHANNEL_UID_RSSI;
|
||||
handler.handleCommand(channelUID, RefreshType.REFRESH);
|
||||
ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
|
||||
verify(callback).stateUpdated(eq(channelUID), stateCaptor.capture());
|
||||
assertEquals("State of RSSI channel should be set", new QuantityType<>(expectedRssi + " dBm"),
|
||||
stateCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleCommandOther() throws InterruptedException {
|
||||
handler.initialize();
|
||||
ChannelUID channelUID = ChannelUIDConstants.CHANNEL_UID_SWITCH;
|
||||
Mockito.doReturn(OnOffType.ON).when(smartHomeDevice).updateChannel(eq(channelUID), any());
|
||||
handler.handleCommand(channelUID, RefreshType.REFRESH);
|
||||
ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
|
||||
verify(callback).stateUpdated(eq(channelUID), stateCaptor.capture());
|
||||
assertSame("State of channel switch should be set", OnOffType.ON, stateCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshChannels() {
|
||||
handler.initialize();
|
||||
handler.refreshChannels();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.tplinksmarthome.internal.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Util class for reading test resources.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class ModelTestUtil {
|
||||
|
||||
public static final Gson GSON = GsonUtil.createGson();
|
||||
|
||||
private ModelTestUtil() {
|
||||
// Util class
|
||||
}
|
||||
|
||||
/**
|
||||
* Util method to read a json file into it's data class.
|
||||
*
|
||||
* @param <T> Type of the class the json data represents.
|
||||
* @param gson gson class
|
||||
* @param filename filename of the json file to read. The file is read relative to the directory of this class
|
||||
* @param clazz Data class expected to be read from the json file
|
||||
* @return instance of clazz with read data from json file
|
||||
* @throws IOException when file could not be read.
|
||||
*/
|
||||
public static <T> T jsonFromFile(String filename, Class<T> clazz) throws IOException {
|
||||
return GSON.fromJson(readJson(filename), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Util method to read a json file. It normalizes the string by removing returns, tabs and spaces. It's not very
|
||||
* smart as it removes spaces inside json values as well. But this method is mainly intended be able to compare 2
|
||||
* json strings.
|
||||
*
|
||||
* @param filename filename of the json file to read. The file is read relative to the directory of this class
|
||||
* @return read json string
|
||||
* @throws IOException when file could not be read.
|
||||
*/
|
||||
public static String readJson(String filename) throws IOException {
|
||||
return IOUtils
|
||||
.toString(ModelTestUtil.class.getResourceAsStream(filename + ".json"), StandardCharsets.UTF_8.name())
|
||||
.replaceAll("[\n\r\t ]", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.common.emeter":{"get_realtime":{}}}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "schedule",
|
||||
"alias": "Downstairs Light",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Dimmable Light",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "80120B3D03E0B639CDF33E3CB1466490187FEF32",
|
||||
"disco_ver": "1.0",
|
||||
"err_code": 0,
|
||||
"heapsize": 309908,
|
||||
"hwId": "111E35908497A05512E259BB76801E10",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 0,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 0,
|
||||
"light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 92,
|
||||
"color_temp": 2700,
|
||||
"hue": 7,
|
||||
"mode": "normal",
|
||||
"saturation": 44
|
||||
},
|
||||
"on_off": 0
|
||||
},
|
||||
"mic_mac": "50C7BF7BE306",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "LB110(EU)",
|
||||
"oemId": "A68E15472071CB761E5CCFB388A1D8AE",
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 58,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 2,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 1,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 3,
|
||||
"saturation": 0
|
||||
}
|
||||
],
|
||||
"rssi": -61,
|
||||
"sw_ver": "1.5.5 Build 170623 Rel.090105"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"power_mw": 10800
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "Living Room Side Table",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Color Changing",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "DEVID_HERE",
|
||||
"disco_ver": "1.0",
|
||||
"heapsize": 347000,
|
||||
"hwId": "HWID_HERE",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 1,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 1,
|
||||
"light_state": {
|
||||
"brightness": 92,
|
||||
"color_temp": 2630,
|
||||
"hue": 7,
|
||||
"mode": "normal",
|
||||
"on_off": 1,
|
||||
"saturation": 44
|
||||
},
|
||||
"mic_mac": "MAC_HERE",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "LB130(US)",
|
||||
"oemId": "EOMiID_HERE",
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 50,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 0,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 75
|
||||
},
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 0,
|
||||
"hue": 120,
|
||||
"index": 2,
|
||||
"saturation": 75
|
||||
},
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 0,
|
||||
"hue": 240,
|
||||
"index": 3,
|
||||
"saturation": 75
|
||||
}
|
||||
],
|
||||
"rssi": -55,
|
||||
"sw_ver": "1.1.2 Build 160927 Rel.111100"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"power_mw": 10800
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"transition_light_state": {
|
||||
"brightness": 33,
|
||||
"on_off": 1,
|
||||
"ignore_default": 1,
|
||||
"mode": "normal",
|
||||
"transition_period": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"transition_light_state": {
|
||||
"color_temp": 0,
|
||||
"hue": 55,
|
||||
"saturation": 44,
|
||||
"brightness": 33,
|
||||
"on_off": 1,
|
||||
"ignore_default": 1,
|
||||
"mode": "normal",
|
||||
"transition_period": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"transition_light_state": {
|
||||
"color_temp": 5100,
|
||||
"hue": 0,
|
||||
"saturation": 0,
|
||||
"on_off": 1,
|
||||
"ignore_default": 1,
|
||||
"mode": "normal",
|
||||
"transition_period": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"transition_light_state": {
|
||||
"on_off": 1,
|
||||
"ignore_default": 1,
|
||||
"mode": "normal",
|
||||
"transition_period": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"transition_light_state": {
|
||||
"on_off": 1,
|
||||
"mode": "normal",
|
||||
"hue": 120,
|
||||
"saturation": 65,
|
||||
"color_temp": 0,
|
||||
"brightness": 10,
|
||||
"err_code": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.dimmer":{"set_brightness":{"brightness":17}}}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.dimmer":{"set_brightness":{"err_code":0}}}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.dimmer":{"set_switch_state":{"state":0}}}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.dimmer":{"set_switch_state":{"state":1}}}
|
||||
@@ -0,0 +1 @@
|
||||
{"smartlife.iot.dimmer":{"set_switch_state":{"err_code":0}}}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"err_code": 0,
|
||||
"sw_ver": "1.0.8 Build 151101 Rel.24452",
|
||||
"hw_ver": "1.0",
|
||||
"model": "HS100(EU)",
|
||||
"deviceId": "DEVICEID_HERE",
|
||||
"hwId": "HWID_HERE",
|
||||
"oemId": "OEMID_HERE",
|
||||
"alias": "MyßmärtPlug",
|
||||
"active_mode": "schedule",
|
||||
"rssi": -53,
|
||||
"type": "smartplug",
|
||||
"mac": "MAC_ADD_HERE",
|
||||
"fwId": "FWID_HERE",
|
||||
"dev_name": "Wi-Fi Smart Plug",
|
||||
"icon_hash": "",
|
||||
"relay_state": 1,
|
||||
"on_time": 451,
|
||||
"feature": "TIM",
|
||||
"updating": 0,
|
||||
"led_off": 0,
|
||||
"latitude": 0.0,
|
||||
"longitude": 0.0,
|
||||
"is_factory": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"sw_ver": "1.4.8 Build 180109 Rel.171240",
|
||||
"hw_ver": "1.0",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"model": "HS220(US)",
|
||||
"mac": "00:00:00:00:00:00",
|
||||
"dev_name": "Smart Wi-Fi Dimmer",
|
||||
"alias": "dimmer",
|
||||
"relay_state": 0,
|
||||
"brightness": 50,
|
||||
"on_time": 0,
|
||||
"active_mode": "none",
|
||||
"feature": "TIM",
|
||||
"updating": 0,
|
||||
"icon_hash": "",
|
||||
"rssi": -10,
|
||||
"led_off": 0,
|
||||
"longitude_i": 0,
|
||||
"latitude_i": 0,
|
||||
"hwId": "00000000000000000000000000000000",
|
||||
"fwId": "00000000000000000000000000000000",
|
||||
"deviceId": "00000000000000000000000000000000",
|
||||
"oemId": "00000000000000000000000000000000",
|
||||
"preferred_state": [
|
||||
{
|
||||
"index": 0,
|
||||
"brightness": 100
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"brightness": 75
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"brightness": 50
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"brightness": 25
|
||||
}
|
||||
],
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"err_code": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"sw_ver": "1.4.8 Build 180109 Rel.171240",
|
||||
"hw_ver": "1.0",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"model": "HS220(US)",
|
||||
"mac": "00:00:00:00:00:00",
|
||||
"dev_name": "Smart Wi-Fi Dimmer",
|
||||
"alias": "dimmer",
|
||||
"relay_state": 1,
|
||||
"brightness": 50,
|
||||
"on_time": 0,
|
||||
"active_mode": "none",
|
||||
"feature": "TIM",
|
||||
"updating": 0,
|
||||
"icon_hash": "",
|
||||
"rssi": -10,
|
||||
"led_off": 0,
|
||||
"longitude_i": 0,
|
||||
"latitude_i": 0,
|
||||
"hwId": "00000000000000000000000000000000",
|
||||
"fwId": "00000000000000000000000000000000",
|
||||
"deviceId": "00000000000000000000000000000000",
|
||||
"oemId": "00000000000000000000000000000000",
|
||||
"preferred_state": [
|
||||
{
|
||||
"index": 0,
|
||||
"brightness": 100
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"brightness": 75
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"brightness": 50
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"brightness": 25
|
||||
}
|
||||
],
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"err_code": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"context": {"child_ids": ["00000000000000000000000000000001"]}, "emeter": {"get_realtime": {}}}
|
||||
@@ -0,0 +1 @@
|
||||
{"context": {"child_ids": ["00000000000000000000000000000001"]}, "emeter": {"get_realtime": {}}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user