[tapocontrol] now supports energy monitoring of P110 device (#12017)

* [tapocontrol] added energy monitoring for P110
* [tapocontrol] corrected textual thing configuration in readme

Signed-off-by: Christian Wild <christian@wild-bw.de>
This commit is contained in:
Christian Wild 2022-01-27 08:46:30 +01:00 committed by GitHub
parent 07e02cf459
commit 3d9717caf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 336 additions and 19 deletions

View File

@ -6,12 +6,21 @@ This binding adds support to control Tapo (Copyright © TP-Link Corporation Limi
The following Tapo-Devices are supported
### P100/P105/P110 SmartPlug (WiFi)
### P100/P105 SmartPlug (WiFi)
* Power On/Off
* Wi-Fi signal (SignalStrength)
* On-Time (Time in seconds device is switched on)
### P110 EnergyMonitoring SmartPlug (WiFi)
* Power On/Off
* Wi-Fi signal (SignalStrength)
* On-Time (Time in seconds device is switched on)
* actual PowerUsage (Watt)
* today EnergyUsage (Wh)
* today Runtime (Time in seconds device was on today)
### L510(Series) dimmable SmartBulb (WiFi)
* Light On/Off
@ -87,6 +96,9 @@ All devices support some of the following channels:
| | color | Color | Color | L530, L900 |
| device | wifiSignal | system.signal-strength | WiFi-quality-level | P100, P105, P110, L510, L530, L900, L920 |
| | onTime | Number:Time | seconds output is on | P100, P105, P110, L510, L530, L900, L920 |
| energy | actualPower | Number:Power | actual Power (Watt) | P110 |
| | todayEnergyUsage | Number:Energy | used energy today (Wh) | P110 |
| | todayRuntime | Number:Time | seconds output was on today | P110 |
## Channel Refresh
@ -100,12 +112,16 @@ To minimize network traffic the default refresh-rate is set to 30 seconds. This
### tapocontrol.things:
```
tapocontrol:bridge:myTapoBridge "Cloud-Login" [ username="you@yourpovider.com", password="verysecret" ]
tapocontrol:P100:myTapoBridge:mySocket "My-Socket" [ ipAddress="192.168.178.150", pollingInterval=30 ]
tapocontrol:L510:myTapoBridge:whiteBulb "white-light" [ ipAddress="192.168.178.151", pollingInterval=30 ]
tapocontrol:L530:myTapoBridge:colorBulb "color-light" [ ipAddress="192.168.178.152", pollingInterval=30 ]
tapocontrol:L900:myTapoBridge:myLightStrip "light-strip" [ ipAddress="192.168.178.153", pollingInterval=30 ]
```
tapocontrol:bridge:myTapoBridge "Cloud-Login" [ username="you@yourpovider.com", password="verysecret" ]
tapocontrol:P100:myTapoBridge:mySocket "My-Socket" (tapocontrol:bridge:myTapoBridge) [ ipAddress="192.168.178.150", pollingInterval=30 ]
tapocontrol:L510:myTapoBridge:whiteBulb "white-light" (tapocontrol:bridge:myTapoBridge) [ ipAddress="192.168.178.151", pollingInterval=30 ]
tapocontrol:L530:myTapoBridge:colorBulb "color-light" (tapocontrol:bridge:myTapoBridge) [ ipAddress="192.168.178.152", pollingInterval=30 ]
tapocontrol:L900:myTapoBridge:myLightStrip "light-strip" (tapocontrol:bridge:myTapoBridge) [ ipAddress="192.168.178.153", pollingInterval=30 ]
Bridge tapocontrol:bridge:secondBridgeExample "Cloud-Login" [ username="youtoo@anyprovider.com", password="verysecret" ] {
Thing tapocontrol:P110:secondBridgeExample:mySocket "My-Socket" [ ipAddress="192.168.101.51", pollingInterval=30 ]
}
```
### tapocontrol.items:

View File

@ -14,6 +14,7 @@ package org.openhab.binding.tapocontrol.internal.api;
import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*;
import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants.*;
import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*;
import java.net.InetAddress;
@ -25,6 +26,7 @@ import org.openhab.binding.tapocontrol.internal.device.TapoDevice;
import org.openhab.binding.tapocontrol.internal.helpers.PayloadBuilder;
import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler;
import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo;
import org.openhab.binding.tapocontrol.internal.structures.TapoEnergyData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -43,6 +45,7 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
private final String uid;
private final TapoDevice device;
private TapoDeviceInfo deviceInfo;
private TapoEnergyData energyData;
private Gson gson;
private long lastQuery = 0L;
private long lastSent = 0L;
@ -58,6 +61,7 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
this.device = device;
this.gson = new Gson();
this.deviceInfo = new TapoDeviceInfo();
this.energyData = new TapoEnergyData();
this.uid = device.getThingUID().getAsString();
}
@ -208,6 +212,20 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
}
}
/**
* Get energy usage from device
*/
public void getEnergyUsage() {
logger.trace("({}) DeviceConnetor_getEnergyUsage from '{}'", uid, deviceURL);
/* create payload */
PayloadBuilder plBuilder = new PayloadBuilder();
plBuilder.method = DEVICE_CMD_GETENERGY;
String payload = plBuilder.getPayload();
sendSecurePasstrhroug(payload, DEVICE_CMD_GETENERGY);
}
/**
* SEND SECUREPASSTHROUGH
* encprypt payload and send to device
@ -251,6 +269,7 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
}
/**
*
* handle JsonResponse (getDeviceInfo)
*
* @param responseBody String with responseBody from device
@ -258,7 +277,7 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
@Override
protected void handleDeviceResult(String responseBody) {
JsonObject jsnResult = getJsonFromResponse(responseBody);
if (jsnResult.has("device_id")) {
if (jsnResult.has(DEVICE_PROPERTY_ID)) {
this.deviceInfo = new TapoDeviceInfo(jsnResult);
this.device.setDeviceInfo(deviceInfo);
} else {
@ -268,6 +287,23 @@ public class TapoDeviceConnector extends TapoDeviceHttpApi {
this.device.responsePasstrough(responseBody);
}
/**
* handle JsonResponse (getEnergyData)
*
* @param responseBody String with responseBody from device
*/
@Override
protected void handleEnergyResult(String responseBody) {
JsonObject jsnResult = getJsonFromResponse(responseBody);
if (jsnResult.has(ENERGY_PROPERTY_POWER)) {
this.energyData = new TapoEnergyData(jsnResult);
this.device.setEnergyData(energyData);
} else {
this.energyData = new TapoEnergyData();
}
this.device.responsePasstrough(responseBody);
}
/**
* handle custom response
*

View File

@ -93,6 +93,14 @@ public class TapoDeviceHttpApi {
protected void handleDeviceResult(String responseBody) {
}
/**
* handle JsonResponse (getEnergyData)
*
* @param responseBody String with responseBody from device
*/
protected void handleEnergyResult(String responseBody) {
}
/**
* handle custom response
*
@ -346,6 +354,9 @@ public class TapoDeviceHttpApi {
case DEVICE_CMD_GETINFO:
handleDeviceResult(rBody);
break;
case DEVICE_CMD_GETENERGY:
handleEnergyResult(rBody);
break;
case DEVICE_CMD_CUSTOM:
handleCustomResponse(rBody);
break;

View File

@ -52,5 +52,6 @@ public class TapoBindingSettings {
// LIST OF DEVICE-COMMANDS
public static final String DEVICE_CMD_GETINFO = "get_device_info";
public static final String DEVICE_CMD_SETINFO = "set_device_info";
public static final String DEVICE_CMD_GETENERGY = "get_energy_usage";
public static final String DEVICE_CMD_CUSTOM = "custom_command";
}

View File

@ -142,7 +142,7 @@ public class TapoErrorConstants {
// List of Config-Error-Messages
public static final String ERR_CONF_IP_MSG = "IP-Address not valid"; // 10001;
public static final String ERR_CONF_CREDENTIALS_MSG = "credentials not set (bridge)"; // 10002;
public static final String ERR_NO_BRIDGE_MSG = "no brigde configured"; // 10003;
public static final String ERR_NO_BRIDGE_MSG = "no bridge configured"; // 10003;
/****************************************
* ErrorTypes

View File

@ -73,6 +73,8 @@ public class TapoThingConstants {
.of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_SMART_PLUG_UIDS, SUPPORTED_WHITE_BULB_UIDS,
SUPPORTED_COLOR_BULB_UIDS, SUPPORTED_LIGHT_STRIP_UIDS)
.flatMap(Set::stream).collect(Collectors.toSet()));
/*** THINGS WITH ENERGY DATA ***/
public static final Set<ThingTypeUID> SUPPORTED_ENERGY_DATA_UIDS = Set.of(P110_THING_TYPE);
/*** THINGS WITH CHANNEL GROUPS ***/
public static final Set<ThingTypeUID> CHANNEL_GROUP_THING_SET = Collections
@ -125,6 +127,16 @@ public class TapoThingConstants {
public static final String PROPERTY_LIGHTNING_EFFECT_ENABLE = "enable";
public static final String PROPERTY_LIGHTNING_EFFECT_ID = "id";
public static final String PROPERTY_LIGHTNING_EFFECT_NAME = "name";
// energy monitoring
public static final String ENERGY_PROPERTY_POWER = "current_power";
public static final String ENERGY_PROPERTY_RUNTIME_TODAY = "today_runtime";
public static final String ENERGY_PROPERTY_RUNTIME_MONTH = "month_runtime";
public static final String ENERGY_PROPERTY_ENERGY_TODAY = "today_energy";
public static final String ENERGY_PROPERTY_ENERGY_MONTH = "month_energy";
public static final String ENERGY_PROPERTY_PAST24H = "past24h";
public static final String ENERGY_PROPERTY_PAST7D = "past7d";
public static final String ENERGY_PROPERTY_PAST30D = "past30d";
public static final String ENERGY_PROPERTY_PAST1Y = "past1y";
/*** DEVICE SETTINGS ***/
public static final Integer BULB_MIN_COLORTEMP = 2500;
@ -143,6 +155,11 @@ public class TapoThingConstants {
public static final String CHANNEL_ONTIME = "onTime";
public static final String CHANNEL_OVERHEAT = "overheated";
public static final String CHANNEL_WIFI_STRENGTH = "wifiSignal";
// channel group energy monitor
public static final String CHANNEL_GROUP_ENERGY = "energy";
public static final String CHANNEL_NRG_POWER = "actualPower";
public static final String CHANNEL_NRG_USAGE_TODAY = "todayEnergyUsage";
public static final String CHANNEL_NRG_RUNTIME_TODAY = "todayRuntime";
// channel group effect
public static final String CHANNEL_GROUP_EFFECTS = "effect";
public static final String CHANNEL_FX_BRIGHTNESS = "brightness";

View File

@ -28,6 +28,8 @@ import org.openhab.binding.tapocontrol.internal.api.TapoDeviceConnector;
import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler;
import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceConfiguration;
import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo;
import org.openhab.binding.tapocontrol.internal.structures.TapoEnergyData;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@ -319,6 +321,10 @@ public abstract class TapoDevice extends BaseThingHandler {
deviceError.reset();
if (connector.loggedIn()) {
connector.queryInfo(ignoreGap);
// query energy usage
if (SUPPORTED_ENERGY_DATA_UIDS.contains(getThing().getThingTypeUID())) {
connector.getEnergyUsage();
}
} else {
logger.debug("({}) tried to query DeviceInfo but not loggedIn", uid);
connect();
@ -342,6 +348,20 @@ public abstract class TapoDevice extends BaseThingHandler {
}
}
/**
* Set Device EnergyData to device
*
* @param energyData
*/
public void setEnergyData(TapoEnergyData energyData) {
publishState(getChannelID(CHANNEL_GROUP_ENERGY, CHANNEL_NRG_POWER),
getPowerType(energyData.getCurrentPower(), Units.WATT));
publishState(getChannelID(CHANNEL_GROUP_ENERGY, CHANNEL_NRG_USAGE_TODAY),
getEnergyType(energyData.getTodayEnergy(), Units.WATT_HOUR));
publishState(getChannelID(CHANNEL_GROUP_ENERGY, CHANNEL_NRG_RUNTIME_TODAY),
getTimeType(energyData.getTodayRuntime(), Units.MINUTE));
}
/**
* Handle full responsebody received from connector
*
@ -474,6 +494,7 @@ public abstract class TapoDevice extends BaseThingHandler {
channel = channel.replace(CHANNEL_GROUP_ACTUATOR + "#", "");
channel = channel.replace(CHANNEL_GROUP_DEVICE + "#", "");
channel = channel.replace(CHANNEL_GROUP_EFFECTS + "#", "");
channel = channel.replace(CHANNEL_GROUP_ENERGY + "#", "");
return channel;
}
}

View File

@ -218,7 +218,7 @@ public class TapoLightStrip extends TapoDevice {
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH),
getDecimalType(deviceInfo.getSignalLevel()));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME),
getQuantityType(deviceInfo.getOnTime(), Units.SECOND));
getTimeType(deviceInfo.getOnTime(), Units.SECOND));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated()));
// light effect
publishState(getChannelID(CHANNEL_GROUP_EFFECTS, CHANNEL_FX_BRIGHTNESS),

View File

@ -163,7 +163,7 @@ public class TapoSmartBulb extends TapoDevice {
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH),
getDecimalType(deviceInfo.getSignalLevel()));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME),
getQuantityType(deviceInfo.getOnTime(), Units.SECOND));
getTimeType(deviceInfo.getOnTime(), Units.SECOND));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated()));
}
}

View File

@ -86,7 +86,7 @@ public class TapoSmartPlug extends TapoDevice {
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH),
getDecimalType(deviceInfo.getSignalLevel()));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME),
getQuantityType(deviceInfo.getOnTime(), Units.SECOND));
getTimeType(deviceInfo.getOnTime(), Units.SECOND));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated()));
}
}

View File

@ -196,7 +196,7 @@ public class TapoUniversalDevice extends TapoDevice {
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH),
getDecimalType(deviceInfo.getSignalLevel()));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME),
getQuantityType(deviceInfo.getOnTime(), Units.SECOND));
getTimeType(deviceInfo.getOnTime(), Units.SECOND));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT),
getDecimalType(deviceInfo.isOverheated() ? 1 : 0));
}

View File

@ -13,6 +13,8 @@
package org.openhab.binding.tapocontrol.internal.helpers;
import javax.measure.Unit;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import javax.measure.quantity.Time;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -340,9 +342,31 @@ public class TapoUtils {
*
* @param numVal Number with value
* @param unit TimeUnit (Unit<Time>)
* @return QuantityTime<Time>
* @return QuantityType<Time>
*/
public static QuantityType<Time> getQuantityType(@Nullable Number numVal, Unit<Time> unit) {
public static QuantityType<Time> getTimeType(@Nullable Number numVal, Unit<Time> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
/**
* Return QuantityType with Power
*
* @param numVal Number with value
* @param unit PowerUnit (Unit<Power>)
* @return QuantityType<Power>
*/
public static QuantityType<Power> getPowerType(@Nullable Number numVal, Unit<Power> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
/**
* Return QuantityType with Energy
*
* @param numVal Number with value
* @param unit PowerUnit (Unit<Power>)
* @return QuantityType<Energy>
*/
public static QuantityType<Energy> getEnergyType(@Nullable Number numVal, Unit<Energy> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
}

View File

@ -92,7 +92,6 @@ public class TapoDeviceInfo {
this.hue = jsonObjectToInt(jsonObject, DEVICE_PROPERTY_HUE);
this.hwVer = jsonObjectToString(jsonObject, DEVICE_PROPERTY_HW);
this.ip = jsonObjectToString(jsonObject, DEVICE_PROPERTY_IP);
this.lightEffect = lightEffect.setData(jsonObject);
this.mac = jsonObjectToString(jsonObject, DEVICE_PROPERTY_MAC);
this.model = jsonObjectToString(jsonObject, DEVICE_PROPERTY_MODEL);
this.nickname = jsonObjectToString(jsonObject, DEVICE_PROPERTY_NICKNAME);
@ -106,6 +105,19 @@ public class TapoDeviceInfo {
this.timeUsagePast30 = jsonObjectToInt(jsonObject, DEVICE_PROPERTY_USAGE_30);
this.timeUsageToday = jsonObjectToInt(jsonObject, DEVICE_PROPERTY_USAGE_TODAY);
this.type = jsonObjectToString(jsonObject, DEVICE_PROPERTY_TYPE);
if (this.hasLightEffect()) {
this.lightEffect = lightEffect.setData(jsonObject);
}
}
/***********************************
*
* CHECK FOR CHILD TYPES
*
************************************/
public Boolean hasLightEffect() {
return this.jsonObject.has(DEVICE_PROPERTY_EFFECT);
}
/***********************************

View File

@ -0,0 +1,129 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tapocontrol.internal.structures;
import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*;
import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonObject;
/**
* Tapo-Energy-Monitor Structure Class
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class TapoEnergyData {
private Number currentPower = 0;
private Number todayEnergy = 0;
private Number monthEnergy = 0;
private Number todayRuntime = 0;
private Number monthRuntime = 0;
private Number[] past24h = new Number[24];
private Number[] past30d = new Number[30];
private Number[] past1y = new Number[12];
private JsonObject jsonObject = new JsonObject();
/**
* INIT
*/
public TapoEnergyData() {
setData();
}
/**
* Init DeviceInfo with new Data;
*
* @param jso JsonObject new Data
*/
public TapoEnergyData(JsonObject jso) {
setData(jso);
}
/**
* Set Data (new JsonObject)
*
* @param jso JsonObject new Data
*/
public TapoEnergyData setData(JsonObject jso) {
/* create empty jsonObject to set efault values if has no energydata */
if (jso.has(ENERGY_PROPERTY_POWER)) {
this.jsonObject = jso;
} else {
jsonObject = new JsonObject();
}
setData();
return this;
}
private void setData() {
this.currentPower = (float) jsonObjectToInt(jsonObject, ENERGY_PROPERTY_POWER) / 1000;
this.todayEnergy = jsonObjectToInt(jsonObject, ENERGY_PROPERTY_ENERGY_TODAY);
this.monthEnergy = jsonObjectToInt(jsonObject, ENERGY_PROPERTY_ENERGY_MONTH);
this.todayRuntime = jsonObjectToInt(jsonObject, ENERGY_PROPERTY_RUNTIME_TODAY);
this.monthRuntime = jsonObjectToInt(jsonObject, ENERGY_PROPERTY_RUNTIME_MONTH);
this.past24h = new Number[24];
this.past30d = new Number[30];
this.past1y = new Number[12];
}
/***********************************
*
* GET VALUES
*
************************************/
public Number getCurrentPower() {
return this.currentPower;
}
public Number getTodayEnergy() {
return this.todayEnergy;
}
public Number getMonthEnergy() {
return this.monthEnergy;
}
public Number getYearEnergy() {
int sum = 0;
for (int i = 0; i < this.past1y.length; i++) {
sum += this.past1y[i].intValue();
}
return sum;
}
public Number getTodayRuntime() {
return this.todayRuntime;
}
public Number getMonthRuntime() {
return this.monthRuntime;
}
public Number[] getPast24hUsage() {
return this.past24h;
}
public Number[] getPast30dUsage() {
return this.past30d;
}
public Number[] getPast1yUsage() {
return this.past1y;
}
}

View File

@ -61,7 +61,7 @@ public class TapoLightEffect {
*/
public TapoLightEffect setData(JsonObject jso) {
/* create empty jsonObject to set efault values if has no lighning effect */
if (jsonObject.has(DEVICE_PROPERTY_EFFECT)) {
if (jso.has(DEVICE_PROPERTY_EFFECT)) {
this.jsonObject = jso;
} else {
jsonObject = new JsonObject();

View File

@ -42,6 +42,8 @@ channel-group-type.tapocontrol.colorBulb.label = Color Light Bulb
channel-group-type.tapocontrol.colorBulb.description = Tapo Multicolor Smart Light Bulb
channel-group-type.tapocontrol.deviceState.label = Device State
channel-group-type.tapocontrol.deviceState.description = Information about the device
channel-group-type.tapocontrol.energyMonitor.label = Energy Usage
channel-group-type.tapocontrol.energyMonitor.description = Energy and Power usage
channel-group-type.tapocontrol.lightBulb.label = Light Bulb
channel-group-type.tapocontrol.lightBulb.description = Tapo Smart Light Bulb
channel-group-type.tapocontrol.lightEffect.label = Lightning Effect
@ -53,6 +55,8 @@ channel-group-type.tapocontrol.smartPlug.description = Tapo Smart Plug Power Out
# channel types
channel-type.tapocontrol.actualPowerChannel.label = Power
channel-type.tapocontrol.actualPowerChannel.description = Actual power usage
channel-type.tapocontrol.colorChannel.label = Color
channel-type.tapocontrol.colorChannel.description = Color
channel-type.tapocontrol.colorTemperature.label = Color Temperature
@ -77,3 +81,9 @@ channel-type.tapocontrol.outputChannel.label = Output Switch
channel-type.tapocontrol.outputChannel.description = Switches the power state on/off
channel-type.tapocontrol.overheated.label = Device Overheated
channel-type.tapocontrol.overheated.description = ON if device is overheated
channel-type.tapocontrol.todayEnergyUsageChannel.label = Today Usage
channel-type.tapocontrol.todayEnergyUsageChannel.description = Today energy usage
channel-type.tapocontrol.todayRuntimeChannel.label = Today Runtime
channel-type.tapocontrol.todayRuntimeChannel.description = Today runtime (On-Time)

View File

@ -15,6 +15,7 @@
<channel-groups>
<channel-group id="actuator" typeId="smartPlug"/>
<channel-group id="device" typeId="deviceState"/>
<channel-group id="energy" typeId="energyMonitor"/>
</channel-groups>
<representation-property>macAddress</representation-property>

View File

@ -62,6 +62,17 @@
</channels>
</channel-group-type>
<!-- Energy Monitor -->
<channel-group-type id="energyMonitor">
<label>Energy Usage</label>
<description>Energy and Power usage</description>
<channels>
<channel id="actualPower" typeId="actualPowerChannel"></channel>
<channel id="todayEnergyUsage" typeId="todayEnergyUsageChannel"></channel>
<channel id="todayRuntime" typeId="todayRuntimeChannel"></channel>
</channels>
</channel-group-type>
<!-- Lightning Effect -->
<channel-group-type id="lightEffect">
<label>Lightning Effect</label>
@ -148,8 +159,36 @@
</channel-type>
<!-- DEVICE-STATE CHANNEL TYPES -->
<!-- actual power usage -->
<channel-type id="actualPowerChannel">
<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>
<!-- LightningEffect Channel Type -->
<!-- today energy usage -->
<channel-type id="todayEnergyUsageChannel">
<item-type>Number:Energy</item-type>
<label>Today Usage</label>
<description>Today energy usage</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"></state>
</channel-type>
<!-- today runtime -->
<channel-type id="todayRuntimeChannel">
<item-type>Number:Time</item-type>
<label>Today Runtime</label>
<description>Today runtime (On-Time)</description>
<category>Time</category>
<state readOnly="true" pattern="%.0f %unit%"></state>
</channel-type>
<!-- LIGHTNING EFFECT CHANNEL TYPES -->
<!-- effect on -->
<channel-type id="effectOn">
<item-type>Switch</item-type>

View File

@ -196,7 +196,7 @@ public class TapoUniversalDevice extends TapoDevice {
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH),
getDecimalType(deviceInfo.getSignalLevel()));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME),
getQuantityType(deviceInfo.getOnTime(), Units.SECOND));
getTimeType(deviceInfo.getOnTime(), Units.SECOND));
publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT),
getDecimalType(deviceInfo.isOverheated() ? 1 : 0));
}