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
- 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.
- 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. - 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. - PWM —
light.controlon 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. - 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.
- Leave — a
zigbee.resetaction 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
- Wire the MOSFET and a short piece of strip on the bench. Grounds tied, 12 V kept off the board.
- Flash the pack YAML over USB. The log should show the Zigbee stack starting and the light at 0%.
- Permit-join on ZHA or Zigbee2MQTT for a minute. The node should appear as a dimmable light. Toggle and dim from Home Assistant.
- Change YAML only when you mean to. Any endpoint change means delete the device, pair again, and re-interview on Zigbee2MQTT.
- 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.resetand 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.