ESPHomeESP32DIY

ESP32-C6 Zigbee dimmable light

An ESP32-C6 uses its 802.15.4 radio as a Zigbee router and exposes one dimmable-light endpoint. On and level commands drive a MOSFET-dimmed LED strip. Pairs with ZHA or Zigbee2MQTT.

Difficulty · IntermediateSetup · 1–2 hoursHA · current stable (ZHA or Zigbee2MQTT)ESPHome · 2026.6 or newer (external Zigbee component, ESP-IDF)
Get the pack · from $19Have us set it up

Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.

The ESP32-C6 already has an 802.15.4 radio. This pack turns one board into a Zigbee router that joins the coordinator you already run and shows up as a single dimmable light. On/off and level from ZHA or Zigbee2MQTT drive a monochromatic LED output. A logic-level MOSFET switches the 12 V strip. The node stays on USB power and speaks Zigbee only, so the router role is not sharing the radio with a Wi-Fi station.

The reference example this is drawn from logs brightness on a template output. The pack swaps that template for PWM on a real strip. API keys are not part of this node: there is no Wi-Fi API.

This radio is Zigbee here. The ESP32-C6 Thread router is the same silicon on a Thread network. One board runs one of those roles.

What problem it solves

You want a dimmable strip on the Zigbee mesh you already have — ZHA or Zigbee2MQTT — built from an ESP32-C6 and a MOSFET, without a Wi-Fi bulb and without a second hub.

How it works

  1. Radio — ESP-IDF on an ESP32-C6. The external Zigbee component (the one the reference example imports) owns the 802.15.4 stack. ESPHome’s built-in Zigbee support exposes sensors and switches; a dimmable lamp uses this external component.
  2. Router — router: true. The node stays awake and may relay other Zigbee traffic. USB power stays plugged in. A battery would be the wrong supply for a router.
  3. One endpoint — device type DIMMABLE_LIGHT. The on/off cluster’s attribute 0 is a bool. The level cluster’s attribute 0 is an integer, 0–254 in the reference example, scaled into ESPHome brightness 0.0–1.0.
  4. PWM — light.control on a monochromatic light whose output is LEDC at about 1 kHz. Gamma is 1.0 and the default transition is 0 s, so the coordinator’s fade is the only fade.
  5. Join — with permit-join open on the coordinator, the board looks for a network. After you change the endpoint, remove the device and pair again. On Zigbee2MQTT, re-interview it as well.
  6. Leave — a zigbee.reset action drops the network so the next boot can join again.

ESPHome 2026.6 or newer, and a current ESP-IDF, match what that component asks for. One dimmable endpoint is the shape this pack supports.

Hardware notes

  • Board. ESP32-C6 Super Mini. Leave the strap pins alone (GPIO8, GPIO9, GPIO12, GPIO13, GPIO15). PWM uses GPIO4 in the pack. Some C6 boards only join reliably when they are near the coordinator; pair on the bench beside it, then move the lamp.
  • MOSFET. An IRLZ44N is logic-level, so a 3.3 V GPIO can dim a short strip. Put about 220 Ω between GPIO4 and the gate, and about 10 kΩ from gate to source so the strip stays off while the chip boots.
  • Strip and supply. A 12 V single-color (non-addressable) strip. A 5 m 5050 reel at 60 LEDs/m is on the order of 36 W. The linked supply listing has a 2 A / 24 W size and a 5 A / 60 W size: use 5 A for a full reel, or cut the tape and stay under about 20 W on the 2 A adapter. Addressable strips (a data pin, WS2812-class) are a different project.
  • Two supplies, one ground. USB powers the ESP32. The 12 V adapter powers the strip only. Tie the adapter ground to the ESP32 ground. The 12 V positive goes to the strip positive and nowhere on the ESP32.
  • Coordinator. ZHA or Zigbee2MQTT, already paired with the rest of the house. Open permit-join only while you are pairing this node.

Wiring

MOSFET / strip Connect to
Gate GPIO4 through ~220 Ω; 10 kΩ from gate to source
Source ESP32 GND and the 12 V adapter GND
Drain LED strip negative
Strip positive 12 V adapter positive

Snippet

Trimmed from the pack YAML. The device name is a substitution:

substitutions:
  device_name: zigbee-lamp
  friendly_name: Zigbee lamp
  pwm_pin: GPIO4

esp32:
  variant: esp32c6
  framework:
    type: esp-idf

external_components:
  - source: github://luar123/zigbee_esphome
    components: [zigbee]

output:
  - platform: ledc
    id: lamp_pwm
    pin: ${pwm_pin}
    frequency: 1000Hz

light:
  - platform: monochromatic
    id: lamp
    output: lamp_pwm
    gamma_correct: 1.0
    default_transition_length: 0s

zigbee:
  id: zb
  router: true
  endpoints:
    - num: 1
      device_type: DIMMABLE_LIGHT
      clusters:
        - id: ON_OFF
          attributes:
            - attribute_id: 0
              type: bool
              on_value:
                then:
                  - light.control:
                      id: lamp
                      state: !lambda "return (bool) x;"
        - id: LEVEL
          attributes:
            - attribute_id: 0
              type: UINT8
              on_value:
                then:
                  - light.control:
                      id: lamp
                      brightness: !lambda "return ((float) x) / 254.0;"
# USB power, logger, and zigbee.reset button: full YAML in the pack

Setup outline

  1. Wire the MOSFET and a short piece of strip on the bench. Grounds tied, 12 V kept off the board.
  2. Flash the pack YAML over USB. The log should show the Zigbee stack starting and the light at 0%.
  3. Permit-join on ZHA or Zigbee2MQTT for a minute. The node should appear as a dimmable light. Toggle and dim from Home Assistant.
  4. Change YAML only when you mean to. Any endpoint change means delete the device, pair again, and re-interview on Zigbee2MQTT.
  5. Mount the strip. Keep the C6 out of a closed metal box; the onboard antenna needs a clear path back toward the mesh.

Troubleshooting

  • Compile error on zigbee:. ESPHome is older than 2026.6, the framework is Arduino instead of ESP-IDF, or the external component failed to download. Update ESPHome and clean the build.
  • It never joins. Permit-join was closed, or the board is too far for a first join. Pair beside the coordinator. If it joined a network you did not intend, run zigbee.reset and try again with only your coordinator open.
  • On/off works, dimming does nothing. Level attribute id is not 0, or brightness is not scaled from the 0–254 range. The snippet uses attribute 0 and divides by 254.
  • The strip stays on at boot. The gate is floating. Add the gate-to-source resistor.
  • The strip is dim or the MOSFET gets hot. The piece of tape draws more than the adapter can hold, or the gate is not being driven hard enough for that current. Shorten the strip or step up to the 5 A supply size.
  • Zigbee2MQTT shows a device with no light. The interview happened before the endpoint existed. Remove, re-pair, re-interview.
  • The mesh gets weird after you also enable Wi-Fi. This pack leaves Wi-Fi out. A router plus a Wi-Fi station on the same C6 is a poor combination; keep updates on USB.

Credits

Based on jindacek/zigbee_light, whose example is a virtual dimmable light on the external component luar123/zigbee_esphome. This write-up is an original PWM-strip build for ZHA and Zigbee2MQTT, not a paste of that example.

Changelog

v1.0 · Oct 23, 2026: First publish.