TapHome

Shelly Plus i4

Packet Parser → MQTT
Submitted by
Last updated: 03. 2026
Shelly Plus i4

The Shelly Plus i4 is a compact Wi-Fi 4-channel digital input module. It has no relays or outputs — it functions purely as an input device that detects button presses and switch states on four independent terminals (SW1–SW4). It fits behind a standard wall switch (37 x 42 x 16 mm) and is powered by 110–240 VAC. TapHome communicates with the device over MQTT using Gen2+ JSON-RPC 2.0 notifications on the local network — no cloud connection is required.

Each of the four inputs can be independently configured as either button mode (detects single push, double push, long push) or switch mode (detects open/closed state). The TapHome template creates both a push-button device and a reed-contact device for each input — you use the one that matches how the input is configured in the Shelly web UI.

Configuration

MQTT broker setup

The Shelly Plus i4 communicates via MQTT. You need an MQTT broker running on your network (e.g., Mosquitto). In the Shelly web UI (http://{device-ip}), go to Settings → MQTT and enable MQTT, entering the broker IP address and port.

Template import parameters

During TapHome template import, enter three parameters:

ParameterDescriptionExample
MQTT Broker IPIP address of the MQTT broker192.168.1.10
MQTT Broker PortBroker port (default 1883)1883
Shelly IDMQTT client ID from the Shelly web UI → Settings → MQTTshellyplusi4-xxxxxxxxxxxx
Input mode configuration

After importing the template, configure each input in the Shelly web UI (http://{device-ip}) → Inputs:

  • Button mode — for momentary push buttons. Use the corresponding Button 1–4 device in TapHome.
  • Switch mode — for toggle switches or reed contacts. Use the corresponding Switch 1–4 device in TapHome.

Each physical input can only be one type at a time. If an input is set to switch mode but TapHome receives a button event (or vice versa), the listener script raises an error indicating the mismatch.

Device capabilities

Push-button detection (Button 1–4)

Four push-button devices listen for MQTT NotifyEvent messages on the {device_id}/events/rpc topic. Each button detects three press types and maps them to numeric values:

Press typeValue
Single push1
Long push2
Double push3

The button devices are read-only — they report the last detected event. Each button listens for events from its corresponding input component (input:0 through input:3).

Switch/reed-contact detection (Switch 1–4)

Four reed-contact devices listen for MQTT NotifyStatus messages. Each switch reads the binary state of its corresponding input:

StateValue
Closed (active)1
Open (inactive)0

The switch devices are read-only with a 2.5-second poll interval. They are suitable for toggle switches, magnetic reed contacts, or any binary on/off sensor connected to the input terminals.

Additional capabilities

The Shelly Plus i4 API also supports triple-push detection, raw button-down/button-up events, and a programmatic Input.Trigger method (unique to i4 devices) that can emit events without physical input. System diagnostics (uptime, MAC, WiFi RSSI) are available via HTTP RPC but not exposed in this MQTT-only template. These capabilities can be added in a future template update.

Troubleshooting

Button presses not detected
  1. Verify the input is configured as button mode in the Shelly web UI → Inputs
  2. Check that TapHome is connected to the MQTT broker and the Shelly ID matches the device’s MQTT client ID
  3. If TapHome shows “Device is set as switch” error, the input is in switch mode — change it to button mode in the Shelly web UI or use the Switch 1–4 device instead
Switch state not updating
  1. Verify the input is configured as switch mode in the Shelly web UI → Inputs
  2. If TapHome shows “Device is set as button” error, the input is in button mode — change it to switch mode or use the Button 1–4 device instead
  3. Toggle the physical switch and check the MQTT broker for NotifyStatus messages on the shellyplusi4-{id}/events/rpc topic
Device not reachable
  1. Verify the Shelly is connected to Wi-Fi — the blue LED should be constantly on
  2. Confirm MQTT is enabled in the Shelly web UI → Settings → MQTT and the broker address is correct
  3. Try using the mDNS hostname (shellyplusi4-AABBCCDDEE.local) to access the Shelly web UI
  4. Check that the MQTT broker is running and accessible from both TapHome Core and the Shelly device

The Shelly Plus i4 has an MQTT rate limit of 80 notifications per 60-second window. Rapid repeated button presses may exceed this limit and cause some events to be dropped. This is a firmware-level limitation.

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 Plus i4 Module
Custom Variables
ID (string)
Button 1 Push Button Read-only

Push button on input:0 — detects single push (1), long push (2), double push (3)

numeric JSON-RPC event
Variable: Button

Button 1

Listener
Bp := 0;
#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0
    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF method = "NotifyEvent"
        VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
        VAR component := PARSEJSON(zero, "component");
        VAR event := PARSEJSON(zero, "event");
    
        if component = "input:0"
            Bp := SWITCH(event, "single_push", Bp := 1, "double_push", Bp :=3,  "long_push", Bp := 2, Bp := 0 );
            #RETURN(Bp);
        END
    elseif method = "NotifyStatus"
        IF( INDEXOF(params, "input:0") > -1, ADDERROR("Device is set as switch"));
    END
END
Button 2 Push Button Read-only

Push button on input:1 — detects single push (1), long push (2), double push (3)

numeric JSON-RPC event

Button 2

Listener
Bp := 0;

#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF method = "NotifyEvent"
        VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
        VAR component := PARSEJSON(zero, "component");
        VAR event := PARSEJSON(zero, "event");
    
        if component = "input:1"
            Bp := SWITCH(event, "single_push", Bp := 1, "double_push", Bp :=3,  "long_push", Bp := 2, Bp := 0 );
            #RETURN(Bp);
        END
    elseif method = "NotifyStatus"
        IF( INDEXOF(params, "input:0") > -1, ADDERROR("Device is set as switch"));
    END
END
Button 3 Push Button Read-only

Push button on input:2 — detects single push (1), long push (2), double push (3)

numeric JSON-RPC event

Button 3

Listener
Bp := 0;

#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF method = "NotifyEvent"
        VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
        VAR component := PARSEJSON(zero, "component");
        VAR event := PARSEJSON(zero, "event");
    
        if component = "input:2"
            Bp := SWITCH(event, "single_push", Bp := 1, "double_push", Bp :=3,  "long_push", Bp := 2, Bp := 0 );
            #RETURN(Bp);
        END
    elseif method = "NotifyStatus"
        IF( INDEXOF(params, "input:0") > -1, ADDERROR("Device is set as switch"));
    END
END
Button 4 Push Button Read-only

Push button on input:3 — detects single push (1), long push (2), double push (3)

numeric JSON-RPC event

Button 4

Listener
Bp := 0;

#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF method = "NotifyEvent"
        VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
        VAR component := PARSEJSON(zero, "component");
        VAR event := PARSEJSON(zero, "event");
    
        if component = "input:3"
            Bp := SWITCH(event, "single_push", Bp := 1, "double_push", Bp :=3,  "long_push", Bp := 2, Bp := 0 );
            #RETURN(Bp);
        END
    elseif method = "NotifyStatus"
        IF( INDEXOF(params, "input:0") > -1, ADDERROR("Device is set as switch"));
    END
END
Switch 1 Reed Contact Read-only

Reed contact on input:0 — closed (1), open (0)

boolean JSON-RPC status

Switch 1

Listener
#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF(method ="NotifyEvent")
    VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
    VAR component := PARSEJSON(zero, "component");
    
    if component = "input:0"
    ADDERROR("Device is set as button");
    END
    
    IF(method = "NotifyStatus")
    IF( INDEXOF(params, "input:0") > -1)
        VAR input := PARSEJSON(params, "input:0");
        SWITCH(PARSEJSON(input, "state"), true, Rc := 1, Rc := 0);
    END  
    END
END
END
Switch 2 Reed Contact Read-only

Reed contact on input:1 — closed (1), open (0)

boolean JSON-RPC status

Switch 2

Listener
#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF(method ="NotifyEvent")
    VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
    VAR component := PARSEJSON(zero, "component");
    
    if component = "input:1"
    ADDERROR("Device is set as button");
    END
    
    IF(method = "NotifyStatus")
    IF( INDEXOF(params, "input:1") > -1)
    VAR input := PARSEJSON(params, "input:1");
        SWITCH(PARSEJSON(input, "state"), true, Rc := 1, Rc := 0);
    END  
    END
END
END
Switch 3 Reed Contact Read-only

Reed contact on input:2 — closed (1), open (0)

boolean JSON-RPC status

Switch 3

Listener
#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF(method ="NotifyEvent")
    VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
    VAR component := PARSEJSON(zero, "component");
    
    if component = "input:2"
    ADDERROR("Device is set as button");
    END
    
    IF(method = "NotifyStatus")
    IF( INDEXOF(params, "input:2") > -1)
    VAR input := PARSEJSON(params, "input:2");
        SWITCH(PARSEJSON(input, "state"), true, Rc := 1, Rc := 0);
    END  
    END
END
END
Switch 4 Reed Contact Read-only

Reed contact on input:3 — closed (1), open (0)

boolean JSON-RPC status

Switch 4

Listener
#index of shelly
if INDEXOF(RECEIVEDMSG.TOPIC, ID) = 0

    VAR method := PARSEJSON(RECEIVEDMSG.PAYLOAD, "method", true);
    VAR params := PARSEJSON(RECEIVEDMSG.PAYLOAD, "params", true);

    IF(method ="NotifyEvent")
    VAR zero := PARSEJSON(PARSEJSON(params, "events"),"[0]");
    VAR component := PARSEJSON(zero, "component");
    
    if component = "input:3"
    ADDERROR("Device is set as button");
    END
    
    IF(method = "NotifyStatus")
    IF( INDEXOF(params, "input:3") > -1)
    VAR input := PARSEJSON(params, "input:3");
        SWITCH(PARSEJSON(input, "state"), true, Rc := 1, Rc := 0);
    END  
    END
END
END
Connection: Packet Parser → MQTT
Possible improvements (7)
  • Triple Push Detection — Input component supports triple_push events but template only maps single_push, double_push, long_push
  • Button Press/Release Events — Raw button-down and button-up events available via MQTT but not captured by template
  • Programmatic Input Trigger — Input.Trigger method allows emitting events without physical input — unique to i4/i4 Gen3 devices
  • System Status (uptime, RAM, MAC, time) — Available via HTTP /rpc/Sys.GetStatus but template uses MQTT only — no HTTP polling configured
  • WiFi Status (SSID, IP, RSSI) — Available via HTTP /rpc/WiFi.GetStatus but template uses MQTT only
  • Analog Input Mode — Input component supports analog mode (0-100%) but template does not implement it — Plus i4 hardware supports digital inputs only
  • Counter/Pulse Input Mode — Input component supports pulse counting mode but template does not implement it

Sources