TapHome

Shelly EM MQTT

Packet Parser → MQTT
Submitted by
Last updated: 06. 2026
Shelly EM MQTT

The Shelly EM is a single-phase energy meter with two independent metering channels and a 2A relay output for contactor control. Each channel connects to an external CT (current transformer) clamp – available in 50A and 120A variants – allowing non-invasive monitoring of two separate circuits simultaneously. This template connects to the device via an MQTT broker on the local network. No cloud connection is required.

The template exposes three devices: two electric meters (one per CT channel) tracking cumulative energy consumption, and a switch for the contactor relay.

Configuration

Device ID

The Shelly EM uses a Device ID in the format shellyem-XXXXXX, where XXXXXX is the last 6 characters of the MAC address in uppercase hex (e.g., shellyem-B929CC). During template import, enter only the hex part (e.g., B929CC) into the Device ID parameter.

The Device ID can be found:

  • In the Shelly web UI: Settings > Device Info
  • Via API: GET http://<device-ip>/settings – the mqtt.id field

This device supports mDNS discovery. You can use the hostname shellyem-{MAC}.local instead of an IP address when configuring the MQTT broker. Replace {MAC} with the full MAC address in lowercase hex (e.g., shellyem-b929cc.local). Using a hostname prevents connectivity issues when the device’s IP address changes.

MQTT setup

Before importing the template, enable MQTT on the Shelly EM:

  1. Open the Shelly web UI at http://<device-ip>
  2. Go to Internet & Security > Advanced — Developer Settings
  3. Tick Enable action execution via MQTT
  4. In the Server field, enter the MQTT broker address in the format broker-ip:1883
  5. Press SAVE

On Gen1 Shelly devices, enabling MQTT disables Shelly Cloud. Both cannot run simultaneously.

Template setup

After importing the template in TapHome:

  1. Set the MQTT Broker IP to the address of your MQTT broker
  2. Set the MQTT Broker Port (default 1883)
  3. Set the Device ID to the Shelly EM’s Device ID hex part (e.g., B929CC)

The module subscribes to shellies/# and the listener scripts on each device filter messages by the configured Device ID.

Device capabilities

Energy metering (per channel)

Each channel is exposed as an independent Electric Meter device in TapHome. The listener script subscribes to two MQTT topics per channel:

TopicUnitDescription
emeter/{i}/energywatt-minutesCumulative energy since last reboot – divided by 60 000 to convert to kWh
emeter/{i}/totalWhPersistent total energy consumed – survives reboots

The template stores both values: Ed (energy from the watt-minutes topic, converted to kWh) and To (total in Wh from the persistent topic).

The energy topic resets to zero on device reboot. For persistent energy tracking, the template also reads the total topic which survives reboots.

Each channel also exposes a Voltage service attribute, which reads the RMS line voltage from the emeter/{i}/voltage MQTT topic.

The readtotalconsumption and readdemand scripts are commented-out boilerplate – all energy data comes through the MQTT listener. This means the template does not provide instantaneous power readings (W). Only cumulative energy (kWh) and total consumed (Wh) are tracked. Instantaneous active power is available via the emeter/{i}/power MQTT topic but is not subscribed to by this template.

Contactor relay

The relay output is exposed as a switch device in TapHome. The relay is rated 2A / 230 VAC – it is designed for contactor control only, not for direct load switching.

  • Read: subscribes to shellies/shellyem-{id}/relay/0 – payload on maps to ON, off maps to OFF
  • Write: publishes on or off to shellies/shellyem-{id}/relay/0/command

The relay is rated only 2A. Always use an external contactor for loads exceeding this rating. Direct connection of high-power loads will damage the relay.

Troubleshooting

No energy data
  1. Verify MQTT is enabled in the Shelly web UI (Internet & Security > Advanced – MQTT)
  2. Confirm the MQTT broker address and port are correct in both the Shelly device and TapHome module settings
  3. Check that the Device ID custom variable matches the Shelly’s Device ID exactly (e.g., B929CC)
  4. Use an MQTT client (e.g., MQTT Explorer) to subscribe to shellies/# and verify the device publishes emeter/0/energy and emeter/1/energy topics
Only one channel reporting data
  1. Verify the CT clamp is connected to the correct 3.5mm jack (channel 0 or channel 1)
  2. Check that current is flowing through the monitored conductor – the CT clamp must encircle a single conductor, not the entire cable
  3. Subscribe to shellies/shellyem-{id}/emeter/0/# and shellies/shellyem-{id}/emeter/1/# separately to confirm both channels publish data
Relay not responding
  1. Check that the Shelly EM is powered and connected to the MQTT broker
  2. Publish on or off manually to shellies/shellyem-{id}/relay/0/command via an MQTT client to test relay operation independently from TapHome
  3. Verify the relay output is wired correctly (check terminal labels on the device)

Gen1 Shelly devices do not support MQTT over TLS. Communication between the device and the MQTT broker is unencrypted (plain MQTT, port 1883). Ensure the MQTT broker is on a trusted local network.

How to install in TapHome

Prerequisites

  • Shelly device connected to Wi-Fi (see HTTP connection guide if not done yet)
  • MQTT broker running on your local network (e.g., Mosquitto, Home Assistant, or TapHome built-in broker)
  • TapHome CCU on the same network as the broker

On Gen1 devices, enabling MQTT disables Shelly Cloud. Both cannot run simultaneously. On Gen2/Plus devices this limitation does not apply.

Step 1 — Enable MQTT on the Shelly device

Gen1 devices (Shelly 1, 1PM, 2.5, EM, 3EM, Plug S, RGBW2, Dimmer, TRV…)

  1. Open the Shelly web UI: http://<device-ip>/
  2. Navigate to Internet & SecurityAdvanced — MQTT
  3. Enable MQTT
  4. Set MQTT Server: <broker-ip>:<port> (e.g., 192.168.1.10:1883)
  5. Optionally set MQTT User and MQTT Password if your broker requires authentication
  6. Click Save — the device will reboot and connect to the broker

Gen2 / Plus devices (Shelly Plus 1, Plus 1PM, Plus 2PM, Plus Plug S, Plus H&T, Pro 3EM…)

  1. Open the Shelly web UI: http://<device-ip>/
  2. Navigate to SettingsMQTT
  3. Enable MQTT
  4. Set Server: <broker-ip>:<port> (e.g., 192.168.1.10:1883)
  5. The Client ID is pre-filled with the device ID (e.g., shellyplus1pm-AABBCCDDEE) — leave as-is unless you have a specific reason to change it
  6. Click Save and reboot the device

To verify MQTT is working, use an MQTT client (e.g., MQTT Explorer) and subscribe to shellies/# (Gen1) or <device-id>/# (Gen2). You should see status messages from the device.

Step 2 — Find the Device ID / MQTT Client ID

Some templates require a Device ID or MQTT Client ID parameter. This is the unique identifier used in MQTT topics.

  • Gen1: found on the label as MAC address (e.g., AABBCCDDEE). Device ID = shelly<model>-<mac>, e.g., shelly1pm-AABBCCDDEE
  • Gen2/Plus: found in the Shelly web UI under SettingsDevice InfoDevice ID, or on the device label

Step 3 — Configure in TapHome

  1. In TapHome, add a new Packet Parser (MQTT) module
  2. IP Address: enter the MQTT broker IP (e.g., 192.168.1.10)
  3. Port: 1883 (default; use 8883 for TLS)
  4. Device ID / MQTT Client ID: enter the value from Step 2 (if required by the template)
  5. Import the template — TapHome will subscribe to the device topics automatically

Available devices

Shelly EM MQTT Module
Custom Variables
deviceID (string)MQTT Device ID of the Shelly EM — format is 'shellyem-DEVICEID' where DEVICEID is the last 6 hex chars of the MAC address (e.g., B929CC)
Open http://shellyIpAddress → Settings → Device Info → copy Device ID
Electric Meter - Channel 1 Electricity Meter Read-only

Energy consumption on CT clamp channel 1 -- cumulative energy (kWh) and total consumed (Wh)

numeric Unit: kWh
Service Attributes
VoltageRMS voltage on channel 1 read from the emeter/0/voltage MQTT topic

Electric Meter - Channel 1

Read total consumption
# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/getValue");
# IF response.IsSuccess
#  VAR content := response.Content;
#  VAR responseHeaders := response.Headers;
#  RETURN(PARSEXML(content, "//element1/value1"));
# ELSE
#  ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
#  RETURN(NaN);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/getValue", "GET", "some data", "header1:value1", "header2:value2", ...);
# OR
# VAR request := HTTPREQUEST("/example/getValue", "POST", "some data");
# request.headers := { "header1:value1", "header2:value2", ...};
# request.method := "GET";
# request.data := null;
# VAR response := SENDHTTPREQUEST(request);
#
#
# Send TCP, UDP data:
# VAR data1 := BYTECOLLECTION("0a bb ea df 01");
# SENDDATA(data1);
# VAR data2 := "{\"name\":\"John\", \"age\":32}";
# SENDDATA(data2);
# VAR data3 := TOBYTES("{\"name\":\"John\", \"age\":32}", "iso-8859-1");
# SENDDATA(data3);
# Process received TCP or UDP data and set device values in the Listener script
#
#
# Download data from FTP:
# FTPDOWNLOAD("filePath");
Read demand
# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/getValue");
# IF response.IsSuccess
#  VAR content := response.Content;
#  VAR responseHeaders := response.Headers;
#  RETURN(PARSEXML(content, "//element1/value1"));
# ELSE
#  ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
#  RETURN(NaN);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/getValue", "GET", "some data", "header1:value1", "header2:value2", ...);
# OR
# VAR request := HTTPREQUEST("/example/getValue", "POST", "some data");
# request.headers := { "header1:value1", "header2:value2", ...};
# request.method := "GET";
# request.data := null;
# VAR response := SENDHTTPREQUEST(request);
#
#
# Send TCP, UDP data:
# VAR data1 := BYTECOLLECTION("0a bb ea df 01");
# SENDDATA(data1);
# VAR data2 := "{\"name\":\"John\", \"age\":32}";
# SENDDATA(data2);
# VAR data3 := TOBYTES("{\"name\":\"John\", \"age\":32}", "iso-8859-1");
# SENDDATA(data3);
# Process received TCP or UDP data and set device values in the Listener script
#
#
# Download data from FTP:
# FTPDOWNLOAD("filePath");
Listener
VAR whatEd := "shellies/shellyem-"+deviceID+"/emeter/0/energy";
VAR whatTo := "shellies/shellyem-"+deviceID+"/emeter/0/total";

IF (whatEd = RECEIVEDMSG.TOPIC)
 Ed := todouble(TOSTRING(RECEIVEDMSG.PAYLOAD))/60000;
END
IF (whatTo = RECEIVEDMSG.TOPIC)
 To := todouble(TOSTRING(RECEIVEDMSG.PAYLOAD));
END
Service Attributes
Voltage [V]
if parsejson(response, "Topic") = "shellies/shellyem-"+deviceID+"/emeter/0/voltage"
 return(todouble(parsejson(response, "Payload")));
end
Electric Meter - Channel 2 Electricity Meter Read-only

Energy consumption on CT clamp channel 2 -- cumulative energy (kWh) and total consumed (Wh)

numeric Unit: kWh
Service Attributes
VoltageRMS voltage on channel 2 read from the emeter/1/voltage MQTT topic

Electric Meter - Channel 2

Read total consumption
# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/getValue");
# IF response.IsSuccess
#  VAR content := response.Content;
#  VAR responseHeaders := response.Headers;
#  RETURN(PARSEXML(content, "//element1/value1"));
# ELSE
#  ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
#  RETURN(NaN);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/getValue", "GET", "some data", "header1:value1", "header2:value2", ...);
# OR
# VAR request := HTTPREQUEST("/example/getValue", "POST", "some data");
# request.headers := { "header1:value1", "header2:value2", ...};
# request.method := "GET";
# request.data := null;
# VAR response := SENDHTTPREQUEST(request);
#
#
# Send TCP, UDP data:
# VAR data1 := BYTECOLLECTION("0a bb ea df 01");
# SENDDATA(data1);
# VAR data2 := "{\"name\":\"John\", \"age\":32}";
# SENDDATA(data2);
# VAR data3 := TOBYTES("{\"name\":\"John\", \"age\":32}", "iso-8859-1");
# SENDDATA(data3);
# Process received TCP or UDP data and set device values in the Listener script
#
#
# Download data from FTP:
# FTPDOWNLOAD("filePath");
Read demand
# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/getValue");
# IF response.IsSuccess
#  VAR content := response.Content;
#  VAR responseHeaders := response.Headers;
#  RETURN(PARSEXML(content, "//element1/value1"));
# ELSE
#  ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
#  RETURN(NaN);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/getValue", "GET", "some data", "header1:value1", "header2:value2", ...);
# OR
# VAR request := HTTPREQUEST("/example/getValue", "POST", "some data");
# request.headers := { "header1:value1", "header2:value2", ...};
# request.method := "GET";
# request.data := null;
# VAR response := SENDHTTPREQUEST(request);
#
#
# Send TCP, UDP data:
# VAR data1 := BYTECOLLECTION("0a bb ea df 01");
# SENDDATA(data1);
# VAR data2 := "{\"name\":\"John\", \"age\":32}";
# SENDDATA(data2);
# VAR data3 := TOBYTES("{\"name\":\"John\", \"age\":32}", "iso-8859-1");
# SENDDATA(data3);
# Process received TCP or UDP data and set device values in the Listener script
#
#
# Download data from FTP:
# FTPDOWNLOAD("filePath");
Listener
VAR whatEd := "shellies/shellyem-"+deviceID+"/emeter/1/energy";
VAR whatTo := "shellies/shellyem-"+deviceID+"/emeter/1/total";

IF (whatEd = RECEIVEDMSG.TOPIC)
 Ed := todouble(TOSTRING(RECEIVEDMSG.PAYLOAD))/60000;
END
IF (whatTo = RECEIVEDMSG.TOPIC)
 To := todouble(TOSTRING(RECEIVEDMSG.PAYLOAD));
END
Service Attributes
voltage [V]
if parsejson(response, "Topic") = "shellies/shellyem-"+deviceID+"/emeter/1/voltage"
 return(parsejson(response, "Payload"));
end
Contactor Relay Switch

2A relay output for contactor control -- reads relay/0 state and publishes on/off commands

boolean
Values / States: ON · OFF

Contactor Relay

Read switch state
# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/getValue");
# IF response.IsSuccess
#  VAR content := response.Content;
#  VAR responseHeaders := response.Headers;
#  RETURN(PARSEXML(content, "//element1/value1"));
# ELSE
#  ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
#  RETURN(NaN);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/getValue", "GET", "some data", "header1:value1", "header2:value2", ...);
# OR
# VAR request := HTTPREQUEST("/example/getValue", "POST", "some data");
# request.headers := { "header1:value1", "header2:value2", ...};
# request.method := "GET";
# request.data := null;
# VAR response := SENDHTTPREQUEST(request);
#
#
# Send TCP, UDP data:
# VAR data1 := BYTECOLLECTION("0a bb ea df 01");
# SENDDATA(data1);
# VAR data2 := "{\"name\":\"John\", \"age\":32}";
# SENDDATA(data2);
# VAR data3 := TOBYTES("{\"name\":\"John\", \"age\":32}", "iso-8859-1");
# SENDDATA(data3);
# Process received TCP or UDP data and set device values in the Listener script
#
#
# Download data from FTP:
# FTPDOWNLOAD("filePath");
Write switch state
MQTTPUBLISH("shellies/shellyem-" + deviceID + "/relay/0/command",if(St = 1, "on","off"));

# Simple HTTP Request:
# VAR response := SENDHTTPREQUEST("/example/set/value=" + St);
# IF response.IsSuccess = false
#  ADDERROR(response.StatusCode);
# END
#
# Set Http request method, body and headers
# VAR response := SENDHTTPREQUEST("/example/setValue", "GET", "value=" + St, "header1:value1", "header2:value2", ...);\r
# Or VAR request := HTTPREQUEST("/example/setValue");
# request.Method := "PUT";
# VAR response := SENDHTTPREQUEST(request);
#r
#
# Send TCP, UDP data:
# VAR data1 := "{\"name\":\"John\", \"age\":" + St + "}";
# SENDDATA(data1);
# VAR data2 := TOBYTES("{\"name\":\"John\", \"age\":" + St + "}", "iso-8859-1");
# SENDDATA(data2);
# You can process received TCP or UDP data in the Listener script
#
#
# Upload data to FTP:
# FTPUPLOAD("filePath", "somedata=" + St, "write"); # use "append" mode to append data to existing file
Listener
VAR whatSt := "shellies/shellyem-"+deviceID+"/relay/0";
IF (whatSt = RECEIVEDMSG.TOPIC)
 IF (TOSTRING(RECEIVEDMSG.PAYLOAD) = "on")
  St := 1;
 ELSE
  St := 0;
 END
END
Connection: Packet Parser → MQTT
Possible improvements (5)
  • Active Power — Instantaneous active power in W per channel. Available via MQTT but template listener scripts do not subscribe to it — readdemand is commented-out boilerplate.
  • Reactive Power — Instantaneous reactive power in VAR per channel. Available via MQTT topic.
  • Total Energy Returned — Total energy returned to grid in Wh per channel. Useful for solar/bidirectional setups.
  • Connection Status — LWT topic — true on connect, false on disconnect. Could detect device offline state.
  • Reset Energy Data — Payload 'reset_data' resets all accumulated energy counters on both channels.

Sources

Found a problem with this device template?

Tell us what's wrong, what's missing, or how the template should behave. We rely on your feedback to keep the catalog accurate.

Verified by TapHome

Want to use this in your TapHome Core?

Open this template in the Customer Portal to apply it to one of your homes, or to draft a refinement and submit it back to the catalog.

Open in portal