---
title: "Shelly DUO"
description: "Shelly DUO E27 bulb in TapHome over local HTTP or MQTT: brightness, color temperature 2700–6500 K and power metering. MQTT template handles up to 5 bulbs."
url: "https://taphome.com/en/compatibility/shelly-duo/"
language: en
lastmod: 2026-10-08
generator: hugo
ai:
  topics: ["http","mqtt","lighting","wifi","cct","power-metering","led-bulb"]
  questions: ["How to integrate Shelly DUO with TapHome?","How to control Shelly DUO brightness and color temperature from TapHome?","How to connect Shelly DUO via HTTP to TapHome?","How to connect multiple Shelly DUO bulbs via MQTT to TapHome?","Why does Shelly DUO show zero power readings?","What is the debounce mechanism in the Shelly DUO template?"]
---

# Shelly DUO

Communication: Packet Parser → HTTP

- [Shelly DUO Product Page](https://www.shelly.com/en/products/shop/shelly-bulb-duo)
- [Shelly DUO API Documentation](https://shelly-api-docs.shelly.cloud/gen1/#shelly-duo)

> Network address
> 
> TapHome reaches this device at the address entered on import. Give the device a fixed address — an IP reservation in the router, or its mDNS name if it supports one — otherwise the integration stops working when the router changes the address.
> 
> [Network Preparation](https://taphome.com/en/docs/setup/network-preparation/)

## Integration guide

The Shelly DUO is a Wi-Fi LED bulb with an E27 base that supports brightness dimming and tunable white color temperature (CCT) in the range of 2700 K (warm white) to 6500 K (daylight). TapHome integrates with the bulb locally over Wi-Fi using either the HTTP REST API or MQTT. No cloud connection is required.

Two TapHome templates are available: an **HTTP template** for a single bulb, and an **MQTT template** that can control up to 5 DUO bulbs through a single MQTT broker connection. Both templates expose the same device types per bulb — a light device with brightness and CCT control, and an electric meter for power monitoring.

## Configuration

### HTTP template

The HTTP template requires the bulb's IP address (or mDNS hostname `ShellyBulbDuo-{MAC}.local`). TapHome polls the `/status` endpoint every 2.5 seconds and caches the JSON response into the `jsonStatus` custom variable. Individual device scripts parse the cached response without making redundant HTTP calls.

The template accepts two import parameters:

- **IP Address** — the bulb's local IP (default `192.168.0.1`)
- **Transition time** — light transition duration in milliseconds (default 300 ms)

### MQTT template

The MQTT template requires the broker IP, port, and the **Device ID** for each bulb (format: `ShellyBulbDuo-DEVICEID`). The Device ID can be found in the Shelly web UI under **Settings** > **Device Info**, or via `GET http://{bulb-ip}/settings` in the `mqtt.id` field.

The template supports up to **5 DUO bulbs** through a single module. Each bulb is identified by its own topic variable (`bulb1topic` through `bulb5topic`). Unused bulb slots can be left at their default placeholder value.

The template accepts three import parameters:

- **MQTT Broker IP** — the broker address (default `192.168.0.1`)
- **MQTT Broker port** — the broker port (default `1883`)
- **Transition time** — light transition duration in milliseconds (default 300 ms)

> [!WARNING]
> On Gen1 Shelly devices, enabling MQTT **disables Shelly Cloud**. Both cannot run simultaneously.

## Device capabilities

### Light control

The template exposes the DUO as a white light device with two controllable parameters:

- **Brightness** — read from `lights[0].brightness` (0-100, converted to 0.0-1.0 internally) and `lights[0].ison`; controlled via `/light/0?turn=on|off&brightness=N` (HTTP) or by publishing JSON to the `light/0/set` topic (MQTT)
- **Color temperature** — read from `lights[0].temp` (2700-6500 K); controlled via `/light/0?temp=K` (HTTP) or the `temp` field in the JSON payload (MQTT)

Both parameters are sent together in a single write command. The transition time parameter controls the fade duration for all changes.

When the light is turned off (brightness set to 0), the template sends `turn=off` (HTTP) or publishes `off` to the `light/0/command` topic (MQTT).

### Debounce mechanism

The HTTP template includes a debounce guard to prevent stale readings during light transitions. After every write command, the template ignores `/status` reads for the duration of the transition time plus 500 ms. During this period, the read scripts return the last known values instead of polling the device. This prevents the UI from briefly showing intermediate states while the bulb is transitioning.

The MQTT template does not need debounce — it receives state updates directly from the bulb as they occur.

### Power metering

The built-in energy meter reads two values:

- **Real-time power** — `meters[0].power` in watts, converted to kW (divided by 1000)
- **Total consumption** — `meters[0].total` in watt-minutes, converted to kWh (divided by 60 000)

The meter is read-only and updates automatically with every poll cycle (HTTP) or on each MQTT message.

> [!NOTE]
> To enable power monitoring, the device model must be configured in the Shelly app or web browser under Settings > Device Model. If the bulb is on but power reads zero, the template displays a warning about this configuration step.

### Service diagnostics (HTTP template)

The HTTP template exposes 10 service attributes:

- **Network info** — IP address, MAC address (formatted with colon separators), WiFi signal strength (dBm)
- **Connectivity** — cloud enabled/connected, MQTT connected
- **Device info** — device time, uptime (formatted as days/hours/minutes), RAM usage
- **Firmware** — firmware update available

### Service actions (HTTP template)

Two service actions are available:

- **Enable cloud** — enables or disables Shelly Cloud connectivity
- **Reboot** — triggers a device reboot

### Additional capabilities

The Shelly DUO also exposes a light timer (active flag and remaining seconds), an auto-off timer on the light endpoint, internal device temperature, WiFi signal strength as a standalone sensor device, and an MQTT online/offline LWT topic for connection status detection. These capabilities can be added in a future template update.

## Troubleshooting

### Bulb not responding (HTTP)

1. Verify the DUO is connected to Wi-Fi and has a valid IP address
2. Try using the mDNS hostname (`ShellyBulbDuo-AABBCC.local`) instead of the IP address — the IP may have changed after a DHCP renewal
3. Open `http://{bulb-ip}/shelly` in a browser — if it responds with a JSON containing `"type":"SHBDUO-1"`, the bulb is reachable
4. Check that TapHome CCU and the DUO are on the same network / VLAN

### Power readings show zero

1. Confirm the device model is configured in the Shelly app (Settings > Device Model)
2. Check that the bulb is turned on — the meter only reads when current flows
3. Poll `/status` manually and verify `meters[0].power` returns a non-zero value

### MQTT bulb not responding

1. Verify MQTT is enabled in the Shelly web UI (Internet & Security > Advanced — MQTT)
2. Confirm the broker address and port are correct in both the Shelly device and TapHome module settings
3. Check that the `bulbNtopic` custom variable matches the bulb's Device ID exactly (e.g., `ShellyBulbDuo-B929CC`)
4. Use an MQTT client (e.g., MQTT Explorer) to subscribe to `shellies/#` and verify the bulb publishes messages

### Light transitions appear jerky

1. Increase the transition time parameter — the default 300 ms may be too short for large brightness changes
2. If using HTTP, ensure no other system is polling the bulb simultaneously — Gen1 devices support only 2 concurrent connections

> [!WARNING]
> Gen1 Shelly devices support only **2 concurrent HTTP connections**. If TapHome and another system (e.g., Home Assistant) poll the same device simultaneously, communication may become unreliable. Consider switching to the MQTT template for multi-system environments.

## How to install in TapHome

### Prerequisites

- Shelly device installed and powered on
- Local Wi-Fi network (2.4 GHz)
- TapHome CCU on the same network

### Step 1 — Connect Shelly to Wi-Fi

**Option A — Shelly app (recommended):**

1. Download the [Shelly app](https://www.shelly.com/en/support/shelly-app) (iOS / Android)
2. Tap **+** → **Add Device** and follow the Bluetooth pairing wizard
3. Enter your Wi-Fi credentials when prompted

**Option B — AP mode (no app):**

1. On first power-up the device creates a hotspot: `ShellyXXX-AABBCCDDEE`
2. Connect your phone/PC to that hotspot
3. Open `http://192.168.33.1` → **Internet & Security** → **Wi-Fi Mode - Client**
4. Enter SSID and password → **Save**

> [!NOTE]
> Shelly only supports **2.4 GHz** networks. 5 GHz networks will not appear in the scan.

### Step 2 — Find the device address

Shelly Gen1 devices support **mDNS** (Zeroconf). You can reach the device using a hostname instead of an IP address:

```
shelly<model>-<MAC>.local
```

For example: `shelly1pm-AABBCCDDEE.local` (MAC address in uppercase hex, no colons).

> [!TIP]
> **Recommended: use the TapHome IP Scanner.** Open the TapHome app and use the **IP Scanner** (Settings → Network → Scan). The scanner will discover devices on your network and show both the IP address and the mDNS hostname. Use the **hostname** instead of the IP address for a more reliable connection — it stays the same even if the device's IP changes after a router reboot.

**Alternative methods** to find the IP address:

- **Shelly app:** Device detail → **Device info** → IP address
- **Shelly web UI:** Connect to the device AP before Wi-Fi setup — the IP is shown after saving
- **Router DHCP table:** Look for a hostname like `shelly1pm-AABBCCDDEE`

### Step 3 — Configure in TapHome

1. In TapHome, add a new **Packet Parser (HTTP)** module
2. **Address:** enter the mDNS hostname (e.g., `shelly1pm-AABBCCDDEE.local`) or IP address from Step 2
3. **Port:** `80` (default, no change needed)
4. Import the template — TapHome will poll `/status` to read device state

> [!NOTE]
> HTTP authentication is disabled by default on Shelly devices. If you have enabled login protection, TapHome does not support HTTP Basic Auth at this time — keep auth disabled for TapHome integration.

## Available devices 2

These devices appear in TapHome after import.

Shelly DUO Module

Service Attributes

|                     |
|---------------------|
| IP Address          |
| MAC Address         |
| WIFI signal         |
| Cloud enabled       |
| Cloud connected     |
| MQTT connected      |
| Device time         |
| FW update available |
| Uptime              |
| RAM                 |

Service Actions

|              |
|--------------|
| Enable cloud |
| Reboot       |

Custom Variables

|                                             |                                                                              |
|---------------------------------------------|------------------------------------------------------------------------------|
| `transitionTime` (numeric) = TransitionTime | Light transition duration in milliseconds (import parameter, default 300 ms) |

Read (module)

```taphome
VAR now := NOW();

IF now.Ticks < debounceTimestamp
    RETURN(0);
END

VAR response := SENDHTTPREQUEST("/status");

IF response.IsSuccess
    jsonStatus := response.Content;
ELSE
    jsonStatus := NULL;
END
```

Service Attributes

IP Address

```taphome
VAR response := SENDHTTPREQUEST("/status");

IF response.IsSuccess
    jsonStatus := response.Content;
ELSE
    jsonStatus := NULL;
END

VAR address := PARSEJSON(jsonStatus, "$.wifi_sta.ip", 1);
IF (ISNULL(address), "-", address)
```

MAC Address

```taphome
VAR value := PARSEJSON(jsonStatus, "$.mac", 1);
IF ISNULL(value)
    RETURN("-");
END;

STRING mac;
INT i := 0;
INT len := LENGTH(value);

WHILE i < len
    mac += GETAT(value, i);
    i += 1;
    
    IF MOD(i, 2) = 0 AND i < len
        mac += ":";
    END
LOOP

mac
```

WIFI signal

```taphome
VAR signal := PARSEJSON(jsonStatus, "$.wifi_sta.rssi", 1);
IF (ISNULL(signal), "-", signal + "db");
```

Cloud enabled

```taphome
VAR value := PARSEJSON(jsonStatus, "$.cloud.enabled", 1);
IF (ISNULL(value), "-", value)
```

Cloud connected

```taphome
VAR value := PARSEJSON(jsonStatus, "$.cloud.connected", 1);
IF (ISNULL(value), "-", value)
```

MQTT connected

```taphome
VAR value := PARSEJSON(jsonStatus, "$.mqtt.connected", 1);
IF (ISNULL(value), "-", value)
```

Device time

```taphome
VAR value := PARSEJSON(jsonStatus, "$.time", 1);
IF (ISNULL(value), "-", value)
```

FW update available

```taphome
VAR value := PARSEJSON(jsonStatus, "$.has_update");
IF (ISNULL(value), "-", value)
```

Uptime

```taphome
VAR value := PARSEJSON(jsonStatus, "$.uptime", 1);
IF ISNULL(value)
    RETURN("-");
END

VAR days := FLOOR(value/86400, 1);
value := MOD(value, 86400);
VAR hours := FLOOR(value/3600, 1);
value := MOD(value, 3600);
VAR minutes := FLOOR(value/60, 1);

days + "day(s) " + hours + "h " + minutes + "m"
```

RAM

```taphome
VAR ramFree := PARSEJSON(jsonStatus, "$.ram_free", 1);
VAR ramTotal := PARSEJSON(jsonStatus, "$.ram_total", 1);

IF ISNULL(ramFree) OR ISNULL(ramTotal)
    RETURN("-");
END

ramFree + " bytes free of " + ramTotal
```

Service Actions

Enable cloud

Parameters: Enable (Enable / Disable)

```taphome
VAR response := SENDHTTPREQUEST("/settings/cloud?enabled=" + enable);
VAR contentJson := response.Content;
VAR wasEnabled := PARSEJSON(contentJson, "enabled");

IF(wasEnabled, "Cloud enabled", "Cloud disabled");
```

Reboot

```taphome
VAR response := SENDHTTPREQUEST("/reboot");
VAR contentJson := response.Content;
VAR wasRebooted := PARSEJSON(contentJson, "ok");

IF(wasRebooted, "Reboot successful", "Error");
```

Light White Light Read and write

CCT white light (2700-6500 K) — brightness dimming and color temperature control

numeric Unit: %, K json\_path

Read brightness

```taphome
VAR now := NOW();

IF now.Ticks < debounceTimestamp
    RETURN(Hb);
END

VAR value := PARSEJSON(jsonStatus, "$.lights[0].brightness", 1);

IF ISNULL(value)
    RETURN(NaN);
END

BOOL isOn := PARSEJSON(jsonStatus, "$.lights[0].ison", 1);

IF ISNULL(isOn)
    RETURN(NaN);
END

IF(isOn, value/100.0, 0);
```

Write brightness

```taphome
IF St > 0.5
    SENDHTTPREQUEST("light/0?turn=on&transition=" + transitionTime + "&brightness=" + ROUND(Hb*100.0));
ELSE
    SENDHTTPREQUEST("light/0?turn=off&transition=" + transitionTime);
END

VAR now := NOW();
debounceTimestamp := now.Ticks + transitionTime + 500;
```

Read color temperature

```taphome
VAR now := NOW();

IF now.Ticks < debounceTimestamp
    RETURN(Ct);
END

VAR value := PARSEJSON(jsonStatus, "$.lights[0].temp", 1);

IF ISNULL(value)
    RETURN(NaN);
END
 
value
```

Write color temperature

```taphome
SENDHTTPREQUEST("light/0?transition=" + transitionTime + "&brightness=" + ROUND(Hb*100) + "&temp=" + Ct);

VAR now := NOW();
debounceTimestamp := now.Ticks + transitionTime + 500;
```

Electric Meter Electricity Meter Read-only

Power consumption and energy metering — instantaneous power (kW) and cumulative energy (kWh)

numeric Unit: W / kWh json\_path

Read total consumption

```taphome
IF LENGTH(jsonStatus) = 0
    RETURN(NaN);
END

VAR power := PARSEJSON(jsonStatus, "$.meters[0].power");
VAR total := PARSEJSON(jsonStatus, "$.meters[0].total");
BOOL isOn := PARSEJSON(jsonStatus, "$.lights[0].ison");

IF ISNULL(power) OR ISNULL(total) OR (ison AND power=0)
	ADDWARNING("To enable power monitoring, open device settings in Shelly app or web browser and configure device model in Settings->Device Model");
	
    RETURN(NaN);
END

total / 60000.0
```

Read demand

```taphome
IF LENGTH(jsonStatus) = 0
    RETURN(NaN);
END

VAR power := PARSEJSON(jsonStatus, "$.meters[0].power", 1);

IF ISNULL(power)
    RETURN(NaN);
END

power / 1000.0
```

**Connection:** Packet Parser → HTTP • Hostname: `ShellyBulbDuo-{MAC}.local`

Possible improvements (7)

- Light Timer Active — Boolean — whether a countdown timer is currently active on the light output.
- Timer Remaining — Seconds remaining on active timer. Available in /status response.
- Auto-off Timer — Auto-off timer in seconds, could be added as service action or light parameter.
- WiFi Signal Strength (as device) — WiFi RSSI in dBm. HTTP template exposes it as service attribute but not as a standalone sensor device.
- Internal Device Temperature — Internal temperature in celsius. Available in /status for Gen1 devices. Not exposed in DUO template.
- MQTT Real-time Power (as device attribute) — MQTT template reads power in electric meter device but does not expose it as a service attribute on the light device.
- Connection Status — LWT topic — true on connect, false on disconnect. Could detect offline bulbs.

## Import parameters

Enter these values when you import the XML.

| Asked in the app     | Default       |
|----------------------|---------------|
| IP address           | `192.168.0.1` |
| Transition time (ms) | `300`         |

## Sources

- Shelly Gen1 API Reference
  
  [shelly-api-docs.shelly.cloud](https://shelly-api-docs.shelly.cloud/gen1/) 2026-03-12
- Home Assistant Shelly Integration
  
  [www.home-assistant.io](https://www.home-assistant.io/integrations/shelly/) 2026-03-12
- Shelly DUO — Device-Specific API
  
  [shelly-api-docs.shelly.cloud](https://shelly-api-docs.shelly.cloud/gen1/#shelly-duo) 2026-03-30
- Shelly DUO — Product Datasheet
  
  [shellystore.co.uk](https://shellystore.co.uk/wp-content/uploads/2021/05/Duo-specs.pdf) 2026-03-30
  
  [PDF](https://taphome.com/compatibility/devices/shelly-duo/manufacturer/duo-specs.pdf)

Manufacturer documents are © their respective owners. They are provided as published by the manufacturer, for reference only.

## Related Documentation

- [Packet Parser Integration](https://taphome.com/en/compatibility/packet-parser-guide/)
- [Packet Parser (HTTP, TCP, UDP, FTP, MQTT)](https://taphome.com/en/docs/integration/packet-parser/)
- [Packet parser functions](https://taphome.com/en/docs/script/packet-parser/)
- [Parsing functions](https://taphome.com/en/docs/script/parsing-functions/)

