# TasmotaPlug Binding
-This binding connects Tasmota flashed smart plugs with 1, 2, 3 or 4 relay channels to openHAB.
-The plug must report the status of the relay via the url `http://$PLUG_IP/cm?cmnd=Power` in order for the binding to work.
+This binding connects Tasmota flashed smart plugs with 1, 2, 3 or 4 relay channels to openHAB.
+The plug must report the status of the relay via the url `http://$PLUG_IP/cm?cmnd=Power` in order for the binding to work.
+The energy monitoring channels can be used if the plug reports energy status via the url `http://$PLUG_IP/cm?cmnd=Status%2010`.
See the [Tasmota Supported Devices Repository](https://templates.blakadder.com/plug.html) for a list of supported plugs.
## Supported Things
Therefore `numChannels` cannot be changed upward after Thing creation.
If the number of channels must be increased, delete the Thing and re-create it with the correct number.
-| Channel ID | Item Type | Description |
-|------------|-----------|-----------------------------------------|
-| power | Switch | Turns the smart plug relay #1 ON or OFF |
-| power2 | Switch | Turns the smart plug relay #2 ON or OFF |
-| power3 | Switch | Turns the smart plug relay #3 ON or OFF |
-| power4 | Switch | Turns the smart plug relay #4 ON or OFF |
+| Channel ID | Item Type | Description |
+|----------------------|--------------------------|-------------------------------------------------|
+| power | Switch | Turns the smart plug relay #1 ON or OFF |
+| power2 | Switch | Turns the smart plug relay #2 ON or OFF |
+| power3 | Switch | Turns the smart plug relay #3 ON or OFF |
+| power4 | Switch | Turns the smart plug relay #4 ON or OFF |
+| voltage | Number:ElectricPotential | Channel for output voltage measurement |
+| current | Number:ElectricCurrent | Channel for output current measurement |
+| watts | Number:Power | Channel for output power measurement |
+| volt-ampere | Number:Power | Channel for output VA measurement |
+| volt-ampere-reactive | Number:Power | Channel for output VAr measurement |
+| power-factor | Number:Dimensionless | Channel for output power factor measurement |
+| energy-today | Number:Energy | Channel for output energy today measurement |
+| energy-yesterday | Number:Energy | Channel for output energy yesterday measurement |
+| energy-total | Number:Energy | Channel for output energy total measurement |
+| energy-total-start | DateTime | Channel for output energy total start date/time |
## Full Example
tasmotaplug.items:
```java
-Switch Plug1 "Plug 1 Power" { channel="tasmotaplug:plug:plug1:power" }
+Switch Plug1 "Plug 1 Power" { channel="tasmotaplug:plug:plug1:power" }
+Number:ElectricPotential Voltage { channel="tasmotaplug:plug:plug1:voltage" }
+Number:ElectricCurrent Current { channel="tasmotaplug:plug:plug1:current" }
+Number:Power Watts { channel="tasmotaplug:plug:plug1:watts" }
+Number:Power VoltAmpere { channel="tasmotaplug:plug:plug1:volt-ampere" }
+Number:Power VoltAmpereReactive { channel="tasmotaplug:plug:plug1:volt-ampere-reactive" }
+Number PowerFactor { channel="tasmotaplug:plug:plug1:power-factor" }
+Number:Energy EnergyToday { channel="tasmotaplug:plug:plug1:energy-today" }
+Number:Energy EnergyYesterday { channel="tasmotaplug:plug:plug1:energy-yesterday" }
+Number:Energy EnergyTotal { channel="tasmotaplug:plug:plug1:energy-total" }
+DateTime EnergyTotalStart "Total Start [%s]" { channel="tasmotaplug:plug:plug1:energy-total-start" }
Switch Plug2a "4ch Power 1" { channel="tasmotaplug:plug:plug2:power" }
Switch Plug2b "4ch Power 2" { channel="tasmotaplug:plug:plug2:power2" }
Frame label="Plugs" {
Switch item=Plug1
+ // Energy monitoring
+ Text item=Voltage
+ Text item=Current
+ Text item=Watts
+ Text item=VoltAmpere
+ Text item=VoltAmpereReactive
+ Text item=PowerFactor
+ Text item=EnergyToday
+ Text item=EnergyYesterday
+ Text item=EnergyTotal
+ Text item=EnergyTotalStart
+
Switch item=Plug2a
Switch item=Plug2b
Switch item=Plug2c
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.tasmotaplug.dto;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link TasmotaDTO} is responsible for storing
+ * all of the JSON data objects retrieved from the Tasmota plug
+ *
+ * @author Michael Lobstein - Initial contribution
+ */
+public class TasmotaDTO {
+
+ @SerializedName("StatusSNS")
+ private TasmotaStatus status = new TasmotaStatus();
+
+ public TasmotaDTO() {
+ }
+
+ public TasmotaStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(TasmotaStatus status) {
+ this.status = status;
+ }
+
+ public class TasmotaStatus {
+
+ @SerializedName("Time")
+ private String time = "";
+
+ @SerializedName("ENERGY")
+ private Energy energy = new Energy();
+
+ public TasmotaStatus() {
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+
+ public Energy getEnergy() {
+ return energy;
+ }
+
+ public void setEnergy(Energy energy) {
+ this.energy = energy;
+ }
+ }
+
+ public class Energy {
+
+ @SerializedName("Voltage")
+ private Integer voltage = 0;
+
+ @SerializedName("Current")
+ private Double current = 0d;
+
+ @SerializedName("Power")
+ private Integer activePower = 0;
+
+ @SerializedName("ApparentPower")
+ private Integer apparentPower = 0;
+
+ @SerializedName("ReactivePower")
+ private Integer reactivePower = 0;
+
+ @SerializedName("Factor")
+ private Double powerFactor = 0d;
+
+ @SerializedName("Today")
+ private Double energyToday = 0d;
+
+ @SerializedName("Yesterday")
+ private Double energyYesterday = 0d;
+
+ @SerializedName("Total")
+ private Double energyTotal = 0d;
+
+ @SerializedName("TotalStartTime")
+ private String energyTotalStart = "";
+
+ public Energy() {
+ }
+
+ public Integer getVoltage() {
+ return voltage;
+ }
+
+ public void setVoltage(Integer voltage) {
+ this.voltage = voltage;
+ }
+
+ public Double getCurrent() {
+ return current;
+ }
+
+ public void setCurrent(Double current) {
+ this.current = current;
+ }
+
+ public Integer getActivePower() {
+ return activePower;
+ }
+
+ public void setActivePower(Integer activePower) {
+ this.activePower = activePower;
+ }
+
+ public Integer getApparentPower() {
+ return apparentPower;
+ }
+
+ public void setApparentPower(Integer apparentPower) {
+ this.apparentPower = apparentPower;
+ }
+
+ public Integer getReactivePower() {
+ return reactivePower;
+ }
+
+ public void setReactivePower(Integer reactivePower) {
+ this.reactivePower = reactivePower;
+ }
+
+ public Double getPowerFactor() {
+ return powerFactor;
+ }
+
+ public void setPowerFactor(Double powerFactor) {
+ this.powerFactor = powerFactor;
+ }
+
+ public Double getEnergyToday() {
+ return energyToday;
+ }
+
+ public void setEnergyToday(Double energyToday) {
+ this.energyToday = energyToday;
+ }
+
+ public Double getEnergyYesterday() {
+ return energyYesterday;
+ }
+
+ public void setEnergyYesterday(Double energyYesterday) {
+ this.energyYesterday = energyYesterday;
+ }
+
+ public Double getEnergyTotal() {
+ return energyTotal;
+ }
+
+ public void setEnergyTotal(Double energyTotal) {
+ this.energyTotal = energyTotal;
+ }
+
+ public String getEnergyTotalStart() {
+ return energyTotalStart;
+ }
+
+ public void setEnergyTotalStart(String energyTotalStart) {
+ this.energyTotalStart = energyTotalStart;
+ }
+ }
+}
public static final String CMD_URI = "/cm?cmnd=%s";
public static final String CMD_URI_AUTH = "/cm?user=%s&password=%s&cmnd=%s";
+ public static final String STATUS = "Status";
+ public static final String STATUS_CMD = "10";
public static final String ON = "ON";
public static final String OFF = "OFF";
public static final String BLANK = "";
public static final String POWER2 = "power2";
public static final String POWER3 = "power3";
public static final String POWER4 = "power4";
+ public static final String VOLTAGE = "voltage";
+ public static final String CURRENT = "current";
+ public static final String WATTS = "watts";
+ public static final String VOLT_AMPERE = "volt-ampere";
+ public static final String VOLT_AMPERE_REACTIVE = "volt-ampere-reactive";
+ public static final String POWER_FACTOR = "power-factor";
+ public static final String ENERGY_TODAY = "energy-today";
+ public static final String ENERGY_YESTERDAY = "energy-yesterday";
+ public static final String ENERGY_TOTAL = "energy-total";
+ public static final String ENERGY_TOTAL_START = "energy-total-start";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG);
- public static final List<String> SUPPORTED_CHANNEL_IDS = List.of(POWER, POWER2, POWER3, POWER4);
+ public static final List<String> CONTROL_CHANNEL_IDS = List.of(POWER, POWER2, POWER3, POWER4);
+ public static final List<String> ENERGY_CHANNEL_IDS = List.of(VOLTAGE, CURRENT, WATTS, VOLT_AMPERE,
+ VOLT_AMPERE_REACTIVE, POWER_FACTOR, ENERGY_TODAY, ENERGY_YESTERDAY, ENERGY_TOTAL, ENERGY_TOTAL_START);
}
*/
package org.openhab.binding.tasmotaplug.internal;
-import static org.openhab.binding.tasmotaplug.internal.TasmotaPlugBindingConstants.THING_TYPE_PLUG;
-
-import java.util.Set;
+import static org.openhab.binding.tasmotaplug.internal.TasmotaPlugBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tasmotaplug")
public class TasmotaPlugHandlerFactory extends BaseThingHandlerFactory {
-
- private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG);
private final HttpClient httpClient;
@Activate
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
- if (THING_TYPE_PLUG.equals(thing.getThingTypeUID())) {
+ if (SUPPORTED_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
return new TasmotaPlugHandler(thing, httpClient);
}
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.openhab.binding.tasmotaplug.dto.TasmotaDTO;
+import org.openhab.binding.tasmotaplug.dto.TasmotaDTO.Energy;
import org.openhab.binding.tasmotaplug.internal.TasmotaPlugConfiguration;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonSyntaxException;
+
/**
* The {@link TasmotaPlugHandler} is responsible for handling commands, which are
* sent to one of the channels.
private final Logger logger = LoggerFactory.getLogger(TasmotaPlugHandler.class);
private final HttpClient httpClient;
+ private final Gson gson;
private @Nullable ScheduledFuture<?> refreshJob;
public TasmotaPlugHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.httpClient = httpClient;
+ gson = new GsonBuilder().serializeNulls().create();
}
@Override
plugHost = "http://" + hostName;
// remove the channels we are not using
- if (this.numChannels < SUPPORTED_CHANNEL_IDS.size()) {
+ if (this.numChannels < CONTROL_CHANNEL_IDS.size()) {
List<Channel> channels = new ArrayList<>(this.getThing().getChannels());
- List<Integer> channelsToRemove = IntStream.range(this.numChannels + 1, SUPPORTED_CHANNEL_IDS.size() + 1)
+ List<Integer> channelsToRemove = IntStream.range(this.numChannels + 1, CONTROL_CHANNEL_IDS.size() + 1)
.boxed().toList();
channelsToRemove.forEach(channel -> {
public void handleCommand(ChannelUID channelUID, Command command) {
if (channelUID.getId().contains(POWER)) {
if (command instanceof OnOffType) {
- getCommand(channelUID.getId(), command);
+ getCommand(channelUID.getId(), command.toString());
} else {
updateChannelState(channelUID.getId());
}
} else {
- logger.warn("Unsupported command: {}", command.toString());
+ logger.debug("Unsupported command: {}", command.toString());
}
}
if (refreshJob == null || refreshJob.isCancelled()) {
refreshJob = null;
this.refreshJob = scheduler.scheduleWithFixedDelay(() -> {
- SUPPORTED_CHANNEL_IDS.stream().limit(numChannels).forEach(channelId -> {
+ CONTROL_CHANNEL_IDS.stream().limit(numChannels).forEach(channelId -> {
updateChannelState(channelId);
});
+
+ if (ENERGY_CHANNEL_IDS.stream().anyMatch(energyCh -> isLinked(energyCh))) {
+ updateEnergyChannels();
+ }
}, 0, refreshPeriod, TimeUnit.SECONDS);
}
}
}
}
- private String getCommand(String channelId, @Nullable Command command) {
- final String plugChannel = channelId.substring(0, 1).toUpperCase() + channelId.substring(1);
- String url;
+ private void updateEnergyChannels() {
+ final Energy energyDto;
+ final String json = getCommand(STATUS, STATUS_CMD);
+ if (!json.isBlank()) {
+ try {
+ final TasmotaDTO dto = gson.fromJson(json, TasmotaDTO.class);
+ if (dto != null) {
+ energyDto = dto.getStatus().getEnergy();
+ } else {
+ logger.debug("TasmotaDTO was null for JSON: '{}'", json);
+ return;
+ }
+ } catch (JsonSyntaxException e) {
+ logger.debug("Error parsing Tasmota status JSON: '{}' Exception: {}", json, e.getMessage());
+ return;
+ }
+ } else {
+ return;
+ }
+ if (isLinked(VOLTAGE)) {
+ updateState(VOLTAGE, new QuantityType<>(energyDto.getVoltage(), Units.VOLT));
+ }
+ if (isLinked(CURRENT)) {
+ updateState(CURRENT, new QuantityType<>(energyDto.getCurrent(), Units.AMPERE));
+ }
+ if (isLinked(WATTS)) {
+ updateState(WATTS, new QuantityType<>(energyDto.getActivePower(), Units.WATT));
+ }
+ if (isLinked(VOLT_AMPERE)) {
+ updateState(VOLT_AMPERE, new QuantityType<>(energyDto.getApparentPower(), Units.VOLT_AMPERE));
+ }
+ if (isLinked(VOLT_AMPERE_REACTIVE)) {
+ updateState(VOLT_AMPERE_REACTIVE, new QuantityType<>(energyDto.getReactivePower(), Units.VAR));
+ }
+ if (isLinked(POWER_FACTOR)) {
+ updateState(POWER_FACTOR, new DecimalType(energyDto.getPowerFactor()));
+ }
+ if (isLinked(ENERGY_TODAY)) {
+ updateState(ENERGY_TODAY, new QuantityType<>(energyDto.getEnergyToday(), Units.KILOWATT_HOUR));
+ }
+ if (isLinked(ENERGY_YESTERDAY)) {
+ updateState(ENERGY_YESTERDAY, new QuantityType<>(energyDto.getEnergyYesterday(), Units.KILOWATT_HOUR));
+ }
+ if (isLinked(ENERGY_TOTAL)) {
+ updateState(ENERGY_TOTAL, new QuantityType<>(energyDto.getEnergyTotal(), Units.KILOWATT_HOUR));
+ }
+ if (isLinked(ENERGY_TOTAL_START) && !energyDto.getEnergyTotalStart().isBlank()) {
+ updateState(ENERGY_TOTAL_START, new DateTimeType(energyDto.getEnergyTotalStart()));
+ }
+ }
+
+ private String getCommand(String commmand, @Nullable String commandArg) {
+ final String tasmotaCommand;
+ if (STATUS.equals(commmand)) {
+ tasmotaCommand = commmand;
+ } else {
+ // uppercase the first character of the channel id
+ tasmotaCommand = commmand.substring(0, 1).toUpperCase() + commmand.substring(1);
+ }
+
+ String url;
if (isAuth) {
- url = String.format(CMD_URI_AUTH, user, pass, plugChannel);
+ url = String.format(CMD_URI_AUTH, user, pass, tasmotaCommand);
} else {
- url = String.format(CMD_URI, plugChannel);
+ url = String.format(CMD_URI, tasmotaCommand);
}
- if (command != null) {
- url += "%20" + command;
+ if (commandArg != null) {
+ url += "%20" + commandArg;
}
try {
thing-type.tasmotaplug.plug.label = Plug
thing-type.tasmotaplug.plug.description = Tasmota Smart Plug
+thing-type.tasmotaplug.plug.channel.energy-today.label = Energy Today
+thing-type.tasmotaplug.plug.channel.energy-today.description = Energy consumed today (kWh)
+thing-type.tasmotaplug.plug.channel.energy-total.label = Energy Total
+thing-type.tasmotaplug.plug.channel.energy-total.description = Total energy consumed (kWh)
+thing-type.tasmotaplug.plug.channel.energy-yesterday.label = Energy Yesterday
+thing-type.tasmotaplug.plug.channel.energy-yesterday.description = Energy consumed yesterday (kWh)
thing-type.tasmotaplug.plug.channel.power.label = Power
thing-type.tasmotaplug.plug.channel.power.description = Controls the smart plug relay for the 1st channel
thing-type.tasmotaplug.plug.channel.power2.label = Power 2
thing-type.tasmotaplug.plug.channel.power3.description = Controls the smart plug relay for the 3rd channel
thing-type.tasmotaplug.plug.channel.power4.label = Power 4
thing-type.tasmotaplug.plug.channel.power4.description = Controls the smart plug relay for the 4th channel
+thing-type.tasmotaplug.plug.channel.watts.label = Active Power
+thing-type.tasmotaplug.plug.channel.watts.description = Active Power (W)
# thing types config
thing-type.config.tasmotaplug.plug.username.label = Username
thing-type.config.tasmotaplug.plug.username.description = Tasmota username
+# channel types
+
+channel-type.tasmotaplug.energy-total-start.label = Energy Total Start
+channel-type.tasmotaplug.energy-total-start.description = The date/time when the energy total measurement started
+channel-type.tasmotaplug.power-factor.label = Power Factor
+channel-type.tasmotaplug.power-factor.description = Power Factor (PF)
+channel-type.tasmotaplug.volt-ampere-reactive.label = Reactive Power
+channel-type.tasmotaplug.volt-ampere-reactive.description = Reactive Power (VAr)
+channel-type.tasmotaplug.volt-ampere.label = Apparent Power
+channel-type.tasmotaplug.volt-ampere.description = Apparent Power (VA)
+
# thing status descriptions
offline.communication-error.http-failure = Tasmota http response code was: {0}
<label>Power 4</label>
<description>Controls the smart plug relay for the 4th channel</description>
</channel>
+
+ <!-- Energy Monitor Channels -->
+ <channel id="voltage" typeId="system.electric-voltage"/>
+ <channel id="current" typeId="system.electric-current"/>
+ <channel id="watts" typeId="system.electric-power">
+ <label>Active Power</label>
+ <description>Active Power (W)</description>
+ </channel>
+
+ <channel id="volt-ampere" typeId="volt-ampere"/>
+ <channel id="volt-ampere-reactive" typeId="volt-ampere-reactive"/>
+ <channel id="power-factor" typeId="power-factor"/>
+
+ <channel id="energy-today" typeId="system.electric-energy">
+ <label>Energy Today</label>
+ <description>Energy consumed today (kWh)</description>
+ </channel>
+ <channel id="energy-yesterday" typeId="system.electric-energy">
+ <label>Energy Yesterday</label>
+ <description>Energy consumed yesterday (kWh)</description>
+ </channel>
+ <channel id="energy-total" typeId="system.electric-energy">
+ <label>Energy Total</label>
+ <description>Total energy consumed (kWh)</description>
+ </channel>
+
+ <channel id="energy-total-start" typeId="energy-total-start"/>
</channels>
+ <properties>
+ <property name="thingTypeVersion">1</property>
+ </properties>
+
<config-description>
<parameter name="hostName" type="text" required="true">
<context>network-address</context>
</thing-type>
+ <channel-type id="volt-ampere">
+ <item-type>Number:Power</item-type>
+ <label>Apparent Power</label>
+ <description>Apparent Power (VA)</description>
+ <state readOnly="true" pattern="%d %unit%"/>
+ </channel-type>
+
+ <channel-type id="volt-ampere-reactive">
+ <item-type>Number:Power</item-type>
+ <label>Reactive Power</label>
+ <description>Reactive Power (VAr)</description>
+ <state readOnly="true" pattern="%d %unit%"/>
+ </channel-type>
+
+ <channel-type id="power-factor">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Power Factor</label>
+ <description>Power Factor (PF)</description>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
+
+ <channel-type id="energy-total-start">
+ <item-type>DateTime</item-type>
+ <label>Energy Total Start</label>
+ <description>The date/time when the energy total measurement started</description>
+ <category>Time</category>
+ <tags>
+ <tag>Timestamp</tag>
+ </tags>
+ <state readOnly="true"/>
+ </channel-type>
+
</thing:thing-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
+ xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
+
+ <thing-type uid="tasmotaplug:plug">
+ <instruction-set targetVersion="1">
+ <add-channel id="voltage">
+ <type>system:electric-voltage</type>
+ </add-channel>
+ <add-channel id="current">
+ <type>system:electric-current</type>
+ </add-channel>
+ <add-channel id="watts">
+ <type>system:electric-power</type>
+ <label>Active Power</label>
+ <description>Active Power (W)</description>
+ </add-channel>
+ <add-channel id="volt-ampere">
+ <type>tasmotaplug:volt-ampere</type>
+ </add-channel>
+ <add-channel id="volt-ampere-reactive">
+ <type>tasmotaplug:volt-ampere-reactive</type>
+ </add-channel>
+ <add-channel id="power-factor">
+ <type>tasmotaplug:power-factor</type>
+ </add-channel>
+ <add-channel id="energy-today">
+ <type>system:electric-energy</type>
+ <label>Energy Today</label>
+ <description>Energy consumed today (kWh)</description>
+ </add-channel>
+ <add-channel id="energy-yesterday">
+ <type>system:electric-energy</type>
+ <label>Energy Yesterday</label>
+ <description>Energy consumed yesterday (kWh)</description>
+ </add-channel>
+ <add-channel id="energy-total">
+ <type>system:electric-energy</type>
+ <label>Energy Total</label>
+ <description>Total energy consumed (kWh)</description>
+ </add-channel>
+ <add-channel id="energy-total-start">
+ <type>tasmotaplug:energy-total-start</type>
+ </add-channel>
+ </instruction-set>
+ </thing-type>
+
+</update:update-descriptions>