---
title: "Yeelight Color"
description: "Yeelight color bulbs and strips over local JSON-RPC on TCP port 55443: hue, saturation, brightness and color temperature in TapHome. Enable LAN Control."
url: "https://taphome.com/en/compatibility/yeelight-color/"
language: en
lastmod: 2026-04-21
generator: hugo
ai:
  topics: ["data-pp","lighting","wifi","json-rpc","lan-control","color-light","hsb","color-temperature"]
  questions: ["How to control Yeelight color and color temperature from TapHome?","What is the difference between the Yeelight dimmer and Yeelight Color templates?","How does TapHome switch between HSV color mode and white mode on a Yeelight bulb?","What color temperature range does Yeelight support via TapHome?","Why does set_hsv fail when the Yeelight is in white mode?","How to enable LAN Control on a Yeelight bulb for TapHome?"]
---

# Yeelight Color

Communication: Packet Parser → TCP

- [Yeelight Developer Portal](https://www.yeelight.com/en_US/developer)
- [Yeelight LAN Control FAQ](https://www.yeelight.com/faqs/lan_control)

> 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 Yeelight Color template extends the dimmer-only [Yeelight](https://taphome.com/en/compatibility/yeelight/) template with full HSB color control and tunable white (color temperature). It targets the same family of Wi-Fi smart LEDs — color bulbs, strips and ceiling lights — using the identical Yeelight **Inter-Operation Protocol** on TCP port **55443**. The key difference is the device model: instead of a simple dimmer the template exposes a **PacketParserHSBLight**, which gives TapHome native hue, saturation, brightness and color temperature properties in one device.

TapHome communicates with the bulb directly on the local network over JSON-RPC — no cloud connection is required once LAN Control is enabled on the bulb. The template polls all six color properties at once and reacts to `props` notifications pushed by the bulb, so changes made from the Yeelight app or another controller appear in TapHome almost immediately.

## Hardware connection

Yeelight bulbs are powered from the standard mains (typically E27, E14, GU10 or 24 V strip power supply depending on product). No wiring is needed between TapHome and the bulb — all communication goes over Wi-Fi. The bulb must be on the **same LAN / VLAN** as the TapHome CCU, because the JSON-RPC protocol has no authentication and no encryption, and the traffic is never routed through the Yeelight cloud.

> [!WARNING]
> The Yeelight LAN protocol is unencrypted. Do not expose TCP port 55443 to the public internet, and place the bulbs on a trusted network segment — anyone with access to the LAN can issue commands to the bulb.

## Configuration

### Enabling LAN Control

LAN Control (also called **Developer Mode** in some regions) is disabled on the bulb by default. Without it, TCP connections on port 55443 are refused.

1. Open the **Yeelight** mobile app and pair the bulb to the local Wi-Fi network with the SmartConfig / QuickConnect procedure if it has not been paired yet.
2. Select the target bulb in the app.
3. Tap the settings icon (top-right) and open **LAN Control** (in some firmware versions labelled **Developer Mode**).
4. Toggle **LAN Control** to ON.
5. Note the bulb's IP address — it is shown in the Yeelight app device info or can be read from the router's DHCP lease table.

Once LAN Control is enabled, the bulb listens on TCP port `55443` and periodically advertises itself over UDP multicast `239.255.255.250:1982`.

### Network configuration

- **IP address** — the TapHome template does not auto-discover bulbs. Assign a **static IP** or a **DHCP reservation** in the router so the bulb's address does not change after a lease renewal.
- **Same LAN segment** — the TapHome CCU and the bulb must be in the same broadcast domain. If Wi-Fi and wired clients are on separate VLANs, add a firewall rule that allows TCP 55443 between them.

### Import parameters

During template import in TapHome the user enters three values:

| Parameter | Description | Default |
|-----------|-------------|---------|
| `ipAddress` | IP address of the Yeelight bulb on the LAN | `192.168.0.1` (placeholder — replace with real IP) |
| `Port` | TCP control port on the bulb | `55443` |
| `Internal poll interval` | How often the template sends `get_prop` (in milliseconds) | `10000` (10 s) |

The default port `55443` is the standard Yeelight LAN Control port and should not be changed unless the bulb has been configured for a non-standard port.

> [!TIP]
> Between polls, the template also reacts to `props` notifications that the bulb pushes whenever its state changes. In practice this means color, brightness and on/off changes made from the Yeelight app, a wall switch adapter, or another controller appear in TapHome almost immediately, without waiting for the next poll.

## Device capabilities

### HSB color light (hue, saturation, brightness and on/off)

The template exposes a single HSB light device. On every poll cycle it sends a `get_prop` request for all six properties at once:

```json
{"id":951,"method":"get_prop","params":["hue","sat","bright","power","ct","color_mode"]}
```

The listener script parses the response and maps it to native TapHome properties:

- **Hue** (`Hd`) — `result[0]`, integer 0–359 degrees
- **Saturation** (`Sa`) — `result[1]`, percent 0–100, divided by 100 to the TapHome 0.0–1.0 range
- **Brightness** (`Hb`) — `result[2]`, percent 1–100, divided by 100 to the TapHome 0.0–1.0 range
- **Power** (`St`) — `result[3]`, `"on"` mapped to 1, `"off"` mapped to 0 (brightness is also set to 0 when off)
- **Color temperature** (`Ct`) — `result[4]`, Kelvin value set only when `color_mode = 2` (white mode); set to `NaN` otherwise
- **Color mode** — `result[5]`, determines whether `Ct` is written (`1` = RGB, `2` = Temperature, `3` = HSV)

### Color mode switching

The template uses the `Ct` property to determine the active color mode:

- **`Ct = NaN`** — the bulb is in HSV color mode. Writes use `set_hsv` for hue and saturation.
- **`Ct = number`** — the bulb is in white (color temperature) mode. Writes use `set_ct_abx`.

TapHome does not send an explicit mode-switch command. Instead, the user sets color temperature to a numeric value to enter white mode, or sets it to NaN (by choosing a color in the HSB picker) to enter HSV mode. The write scripts check `Ct` before sending and skip the irrelevant command — `writesaturation` returns immediately if `Ct` is not NaN, and `writecct` returns immediately if `Ct` is NaN.

### Write commands

Three write scripts handle different aspects of the light:

- **Brightness / power** (`writebrightness`) — if brightness > 0, sends `set_power ["on","smooth",300]` followed by `set_bright [level,"smooth",300]`. If brightness = 0, sends `set_power ["off","smooth",300]`.
- **Hue and saturation** (`writesaturation`) — sends `set_power ["on","smooth",300]` followed by `set_hsv [hue, saturation,"smooth",300]`. Only runs when `Ct = NaN` (HSV mode).
- **Color temperature** (`writecct`) — sends `set_power ["on","smooth",300]` followed by `set_ct_abx [ct,"smooth",300]`. Only runs when `Ct` is a number (white mode). Valid range: **1700–6500 K** (exact limits depend on the bulb model).

All writes use a 300 ms smooth transition for a soft fade instead of a hard step. A debounce variable is set to 1 after every write, causing the next poll cycle to be skipped — this avoids reading stale state while the bulb is transitioning.

### Service diagnostics

Two module-level service attributes are read via a separate `get_prop` request (`id=981`):

- **Color mode** — `RGB`, `Temperature`, or `HSV`, decoded from the numeric `color_mode` property (1 / 2 / 3) using a `SWITCH` expression in the module listener script.
- **Color temperature** — Kelvin value reported as `"{ct}K"` (for example `"4000K"`). Only meaningful when the bulb is in Temperature mode.

These attributes are read-only diagnostics — the actual color temperature control happens through the device-level `Ct` property and the `writecct` script described above.

## Troubleshooting

### Bulb does not respond to commands

1. Verify **LAN Control** is enabled on the bulb (Yeelight app → bulb settings → LAN Control). Without it, the bulb refuses all TCP connections on port 55443.
2. Confirm the bulb IP in the Yeelight app or in the router's DHCP lease table, and make sure it matches the `ipAddress` import parameter. Yeelight bulbs do not keep a fixed IP by default — the lease may have expired and the IP changed.
3. Assign a static IP or DHCP reservation to the bulb to prevent the address from drifting.
4. Check that the TapHome CCU and the bulb are on the same LAN / VLAN and that TCP `55443` is not blocked by a firewall between them.
5. Test connectivity manually: `telnet {bulb-ip} 55443` and send a raw request followed by `\r\n`:

   ```json
   {"id":1,"method":"get_prop","params":["hue","sat","bright","power","ct","color_mode"]}
   ```

   A valid bulb replies with `{"id":1,"result":["<hue>","<sat>","<bright>","<power>","<ct>","<color_mode>"]}`.

### Color commands are ignored (hue/saturation not changing)

The `writesaturation` script checks `Ct` before sending `set_hsv`. If `Ct` is set to a numeric value (white mode), the script returns without sending any command. To control HSV color, set the color temperature to NaN first by selecting a color in the TapHome HSB picker.

Similarly, `writecct` returns without sending if `Ct = NaN` (HSV mode). To write a color temperature, the bulb must already be in white mode.

### Read error: client quota exceeded

Each TCP connection to a Yeelight bulb is limited to **60 commands per minute**, and the bulb accepts at most **4 concurrent connections** in total. If another system polls the bulb at the same time — Home Assistant, a Yeelight cloud session, a custom script — the combined traffic can trigger rate-limit errors.

1. Disable or slow down other integrations that share the bulb.
2. Keep the TapHome poll interval at the default `10000` ms or higher. The color template sends one `get_prop` per poll plus up to three `set_*` writes per change, which stays well under the 60 cmd/min quota.
3. Close unused `telnet` debug sessions — they count against the 4-connection limit.

### HueSat or Color temperature write error

The listener script tracks write errors separately for each command type — `writeErrorBrightness` for power/brightness writes, `writeErrorHueSat` for `set_hsv` writes, and `writeErrorCt` for `set_ct_abx` writes. If an error appears:

1. Confirm the bulb is powered on — all `set_*` commands except `set_power` are only accepted when the bulb is in the `on` state.
2. Verify the color temperature value is within the model-specific range (typically 1700–6500 K for color bulbs, 2700–6500 K for ceiling lights, 2700–6000 K for ceiling3).
3. Check the raw error message in the TapHome service diagnostics for the specific error code returned by the bulb.

### Changes made in the Yeelight app are not reflected

The template reacts to `props` notifications pushed by the bulb, so external changes normally appear within a second. If they do not:

1. The notification may have arrived while the TCP socket was being re-established — the next poll (default 10 s) will resynchronize.
2. Some older firmware versions only push notifications when a command is actively sent. Upgrade the bulb firmware from the Yeelight app.
3. The bulb may have hit the 4-connection limit — reduce the number of concurrent clients on the LAN.

> [!WARNING]
> Yeelight devices support only **4 concurrent TCP connections** and **60 commands per minute** per connection. If TapHome and another system (e.g., Home Assistant) poll the same bulb simultaneously, communication may become unreliable. Use a poll interval of 10 seconds or higher.

## Available devices 1

These devices appear in TapHome after import.

Yeelight color module Module

Service Attributes

|                   |                                                                                                  |
|-------------------|--------------------------------------------------------------------------------------------------|
| Color mode        | Current color mode of the bulb — RGB, Temperature or HSV — decoded from the color\_mode property |
| Color temperature | Color temperature in Kelvin, reported only when the bulb is in Temperature mode (color\_mode=2)  |

Listener

```taphome
VAR jsonResponse := TOSTRING(RECEIVEDBYTES);
VAR id := PARSEJSON(jsonResponse, "id", 1);

IF(id = 981)
   VAR error := PARSEJSON(jsonResponse, "error.message", 1);
   
   IF(!ISNULL(error))
      COMPLETESERVICEATTRIBUTE("Color mode", "", "error");
      COMPLETESERVICEATTRIBUTE("Color temperature", "", "error");
   ELSE
      VAR colorMode := PARSEJSON(jsonResponse, "result[0]", 1);
      VAR colorTemp := PARSEJSON(jsonResponse, "result[1]", 1);
      
      IF(!ISNULL(colorMode))
         VAR colorModeValue := SWITCH(TODOUBLE(colorMode), 1, "RGB", 2, "Temperature", 3, "HSV", "Unknown");
         COMPLETESERVICEATTRIBUTE("Color mode", colorModeValue, "");
      ELSE
         COMPLETESERVICEATTRIBUTE("Color mode", "", "error");
      END
      
      IF(!ISNULL(colorTemp))
         COMPLETESERVICEATTRIBUTE("Color temperature", colorTemp + "K", "");
      ELSE
         COMPLETESERVICEATTRIBUTE("Color temperature", "", "error");
      END
   END
END
```

Service Attributes

Color mode

```taphome
VAR json := "{\"id\":981, \"method\":\"get_prop\", \"params\":[\"color_mode\", \"ct\"]}";
SENDDATA(json);

RETURN(NULL);
```

Color temperature

```

```

HSB Light HSB Light Read and write

Full HSB color light with color temperature support — controls hue, saturation, brightness and on/off via set\_hsv, set\_ct\_abx and set\_bright with smooth transitions

numeric Unit: hue 0-359, sat/bright 0-100 %, CCT 2700-6500 K

Read (module)

```taphome
IF(debounce > 0)
    debounce := 0;
ELSE
    VAR json := "{\"id\":951, \"method\":\"get_prop\", \"params\":[\"hue\", \"sat\", \"bright\", \"power\", \"ct\", \"color_mode\"]}";
    SENDDATA(json);
END
```

Listener

```taphome
VAR jsonResponse := TOSTRING(RECEIVEDBYTES);
VAR method := PARSEJSON(jsonResponse, "method", 1);
VAR id := PARSEJSON(jsonResponse, "id", 1);
VAR error := PARSEJSON(jsonResponse, "error.message", 1);

#response to ReadScript
IF(id = 951)
   receiveError1 := error;
   
   IF(LENGTH(receiveError1) = 0)
      VAR hueStr := PARSEJSON(jsonResponse, "result[0]", 1);
      VAR satStr := PARSEJSON(jsonResponse, "result[1]", 1);
      VAR brightnessStr := PARSEJSON(jsonResponse, "result[2]", 1);
      VAR onOffStr := PARSEJSON(jsonResponse, "result[3]", 1);
      VAR ctStr := PARSEJSON(jsonResponse, "result[4]", 1);
      VAR colorModeStr := PARSEJSON(jsonResponse, "result[5]", 1);
      
      IF(!ISNULL(hueStr))
         Hd := TODOUBLE(hueStr);
      END

      IF(!ISNULL(satStr))
        Sa := TODOUBLE(satStr) / 100.0;
      END
      
      IF(!ISNULL(brightnessStr))
        Hb := TODOUBLE(brightnessStr) / 100.0;
      END
   
      VAR cm := TODOUBLE(colorModeStr);
      IF(!ISNULL(ctStr) AND cm = 2)
        Ct := TODOUBLE(ctStr);
      ELSE
        Ct := NaN;
      END
      
      IF(onOffStr = "on")
         St := 1;
      ELSEIF(onOffStr = "off")
         Hb := 0;
         St := 0;
      END
   END
ELSEIF(id = 952)
   receiveError2 := error;
   
   IF(LENGTH(receiveError2) = 0)
      brightnessStr := PARSEJSON(jsonResponse, "result[0]", 1);
      
      IF(!ISNULL(brightnessStr))
        Hb := TODOUBLE(brightnessStr) / 100.0;
      END
   END
END

IF(id >= 941 AND id <= 942)
   writeErrorBrightness := error;
ELSEIF(id = 943)
   writeErrorHueSat := error;
ELSEIF(id = 944)
   writeErrorCt := error;
END

#general notification
IF(method = "props")
   notificationError := error;
   
   IF(LENGTH(notificationError) = 0)
      VAR brightJson := PARSEJSON(jsonResponse, "params.bright", 1);
      VAR onOffJson := PARSEJSON(jsonResponse, "params.power", 1);
      VAR hue := PARSEJSON(jsonResponse, "params.hue", 1);
      VAR sat := PARSEJSON(jsonResponse, "params.sat", 1);
      VAR colorMode := PARSEJSON(jsonResponse, "params.color_mode", 1);
      VAR ctJson := PARSEJSON(jsonResponse, "params.ct", 1);
      
      IF(!ISNULL(brightJson))
         Hb := brightJson / 100.0;
      END
      
      IF(!ISNULL(hue))
         Hd := hue;
         Ct := NaN;
      END      

      IF(!ISNULL(sat))
        Sa := sat / 100;
        Ct := NaN;
      END 
      
      IF(!ISNULL(ctJson))
        Ct := ctJson;
      END 
      
      IF(onOffJson = "on")
         St := 1;
         IF(ISNULL(brightJson))
            SENDDATA("{\"id\":952, \"method\":\"get_prop\", \"params\":[\"bright\"]}");
         END
      ELSEIF(onOffJson = "off")
         Hb := 0;
         St := 0;
      END
   END
END

IF(LENGTH(receiveError1) > 0)
   ADDERROR(951, "Read error: " + receiveError1);
END

IF(LENGTH(receiveError2) > 0)
   ADDERROR(952, "Read error: " + receiveError2);
END

IF(LENGTH(writeErrorBrightness) > 0)
   ADDERROR(941, "Brightness write error: " + writeErrorBrightness);
END

IF(LENGTH(writeErrorHueSat) > 0)
   ADDERROR(943, "HueSat write error: " + writeErrorHueSat);
END

IF(LENGTH(writeErrorCt) > 0)
   ADDERROR(944, "Color temperature write error: " + writeErrorCt);
END

IF(LENGTH(notificationError) > 0)
   ADDERROR(1, notificationError);
END
```

Write brightness

```taphome
IF(Hb > 0)
    VAR jsonBrightness := "{\"id\":941,\"method\":\"set_power\",\"params\":[\"on\", \"smooth\", 300]}\r\n{\"id\":942,\"method\":\"set_bright\",\"params\":[" + ROUND(Hb*100) + ",\"smooth\", 300]}";
    SENDDATA(jsonBrightness);
ELSE
    VAR jsonPowerOff := "{\"id\":942,\"method\":\"set_power\",\"params\":[\"off\", \"smooth\", 300]}";
    SENDDATA(jsonPowerOff);
END

debounce := 1;
```

Write saturation

```taphome
#do not send HUESAT when COLOR mode is active
IF !ISNAN(Ct)
    RETURN(0);
END

VAR hueSatJson := "{\"id\":941,\"method\":\"set_power\",\"params\":[\"on\", \"smooth\", 300]}\r\n{\"id\":943,\"method\":\"set_hsv\",\"params\":[" + ROUND(MOD(Hd, 360)) + ", " + ROUND(Sa*100) + ", \"smooth\", 300]}";

SENDDATA(hueSatJson);
debounce := 1;
```

Write color temperature

```taphome
#do not set CT in COLOR mode
IF ISNAN(Ct)
    RETURN(0);
END

VAR ctJson := "{\"id\":941,\"method\":\"set_power\",\"params\":[\"on\", \"smooth\", 300]}\r\n{\"id\":944,\"method\":\"set_ct_abx\",\"params\":[" + Ct + ", \"smooth\", 300]}";
SENDDATA(ctJson);

debounce := 1;
```

**Connection:** Packet Parser → TCP

Possible improvements (12)

- Set RGB color — Write full RGB color (0-16777215). Template uses set\_hsv instead, which maps naturally to the HSBLight device model.
- Color flow — Scripted sequences of brightness / color / CT changes (sunrise effect, strobe, ambient cycles). Not exposed by this template.
- Set scene — Jump directly to a predefined state (color, hsv, ct, cf, auto\_delay\_off). Not exposed by this template.
- Toggle power — Single-parameter power toggle. Not exposed — TapHome writes explicit on/off via set\_power instead.
- Sleep timer (cron) — On-device auto-off timer in minutes. Not exposed — TapHome uses its own Smart Rules for scheduling instead.
- Music mode — Reverse-TCP channel bypassing the 60 cmd/min rate limit. Not used by TapHome.
- Relative adjustments — Relative +/- changes without knowing the current value. Not exposed — TapHome always writes absolute values.
- Save current state as power-on default — Persist current brightness/color to flash so it survives a hard power cut. Not exposed by this template.
- Set device name — Set device name (max 64 bytes). Not exposed by this template.
- Background light control — Secondary light channel on dual-light fixtures (e.g., some ceiling lights). Not exposed by this template.
- Extended notification properties — Additional properties pushed via props notifications. Template consumes hue, sat, bright, power, color\_mode and ct — remaining properties (rgb, flowing, delayoff, music\_on, name) are ignored.
- LAN auto-discovery — User must enter the bulb IP manually during import — template does not perform SSDP discovery. A static DHCP lease is strongly recommended.

## Import parameters

Enter these values when you import the XML.

| Asked in the app       | Default       |
|------------------------|---------------|
| IP address             | `192.168.0.1` |
| Port                   | `55443`       |
| Internal poll interval | `10000`       |

## Sources

- Yeelight WiFi Light Inter-Operation Specification
  
  [www.yeelight.com](https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf) 2026-04-15
- Yeelight Developer — Third-party Control Protocol
  
  [www.yeelight.com](https://www.yeelight.com/en_US/developer) 2026-04-15
- python-yeelight library documentation
  
  [yeelight.readthedocs.io](https://yeelight.readthedocs.io/en/latest/) 2026-04-15

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/)

