{"id":27125722,"url":"https://github.com/david-eipi/esp32-zigbee-light","last_synced_at":"2026-05-01T12:31:21.393Z","repository":{"id":278095278,"uuid":"903961232","full_name":"David-EIPI/esp32-zigbee-light","owner":"David-EIPI","description":"Zigbee remote light control using ESP32-H2 and Home Assistant integration","archived":false,"fork":false,"pushed_at":"2025-07-29T22:08:26.000Z","size":995,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-20T12:03:01.600Z","etag":null,"topics":["esp32","esp32-h2","home-assistant","zigbee"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/David-EIPI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-16T01:27:24.000Z","updated_at":"2025-07-29T22:08:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"aa5c1e0b-6c5b-4f03-844c-f1196c1b3d52","html_url":"https://github.com/David-EIPI/esp32-zigbee-light","commit_stats":null,"previous_names":["david-eipi/esp32-zigbee-light"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/David-EIPI/esp32-zigbee-light","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-EIPI%2Fesp32-zigbee-light","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-EIPI%2Fesp32-zigbee-light/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-EIPI%2Fesp32-zigbee-light/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-EIPI%2Fesp32-zigbee-light/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/David-EIPI","download_url":"https://codeload.github.com/David-EIPI/esp32-zigbee-light/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-EIPI%2Fesp32-zigbee-light/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32497809,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","esp32-h2","home-assistant","zigbee"],"created_at":"2025-04-07T15:35:55.459Z","updated_at":"2026-05-01T12:31:21.367Z","avatar_url":"https://github.com/David-EIPI.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# esp32-zigbee-light\nRemotely controlled indoor light powered by ESP32-H2, integrated with Zigbee and Home Assistant.\n\n## Overview\nBuilding the [stm32-zigbee-light project](https://github.com/David-EIPI/stm32-zigbee-light) left me with several spare PCBs. I decided to repurpose them to experiment with Espressif's Zigbee SDK (zSDK). Overall, zSDK is similar to STM's Z-Stack. Programming with zSDK seems to require slightly fewer API calls, though Z-Stack is somewhat better documented.\n\n## Firmware\nThe project is written in C and built using `idf.py`. It implements a zero-crossing detector for TRIAC-based dimming and supports the **HLK-LD2420S** mmWave motion sensor with adjustable sensing distance. The firmware exposes 6 endpoints and 11 clusters:\n\n- **6 Analog Output clusters** (configuration)\n- **1 Analog Input cluster** (detected presence distance)\n- **2 Binary Input clusters** (motion state, light state)\n- **1 Multistate Value cluster** (operation mode)\n- **1 OnOff cluster** (dimming enable control)\n\nFor building instructions with `idf.py` on Linux see [BUILD.md](BUILD.md \"Build\").\n\n### Motion Sensor\nThe **HiLink LD2420S** is an **mmWave motion sensor** (not a presence sensor). It is more sensitive than traditional PIR sensors and can estimate the approximate distance to a moving object, in addition to detecting motion.\n\nCommunication with the sensor is achieved through a standard text-based UART interface. The sensor can be configured with various parameters such as sensitivity, distance range, scanning frequency, etc. This configuration must be done individually for each sensor using the manufacturer's proprietary software. The serial communication protocol is available on the manufacturer's website, but the documentation is brief and somewhat difficult to interpret.\n\nRather than configuring the sensor internally, I opted to parse its output. The output contains information about both motion detection and the estimated distance to the detected object. In the firmware, this distance is compared against a configurable threshold to trigger a motion detection event. The threshold is adjustable via Zigbee, providing a practical way to control the sensor's sensitivity.\n\nThe sensor is powered through a transistor switch, allowing the firmware to power-cycle it when necessary. I used a **PNP** transistor, which proved to be a suboptimal choice. The sensor draws relatively high current (~50-60mA) and is sensitive to supply voltage. Below **3.2V**, it becomes unstable, and its distance measurements become unreliable. Therefore, the transistor base current needs to be sufficiently high to minimize the voltage drop across it to less than **0.1V**. \nA MOSFET would certainly be a more suitable as a switch here.\n\n## Hardware\nI re-used the PCB from the [stm32-zigbee-light](https://github.com/David-EIPI/stm32-zigbee-light) project as the power supply and as the base for the TRIAC dimming circuit. Only a few minor modifications were necessary to integrate the **LD2420S** motion sensor.\n\n![The assembled board.](images/assembled.jpg)  \nAssembled board.\n\nThe control board is based on the **ESP32-H2**. I used a small module called the **ESP32-H2 Super Mini**, designed by **Tenstar Robot**. Despite its compact size, the board provides plenty of accessible GPIOs and works well, with **one exception** that I will describe below. This power-on issue is likely to happen in other circuits with a similar power source.\n\nWhen powered via **USB**, the **ESP32-H2** boots normally. However, when powered from AC mains via the HiLink AC-DC converter, it fails to start. \n\nI suspect that the HiLink adapter's output capacitor has a high capacitance, leading to a slow output voltage rise **(low slew rate)**, which interferes with the ESP32-H2 startup sequence.\n\n#### Solution:\nI added a **4.7µF capacitor** to the **Enable (EN)** pin to delay the startup, which resolved the issue. The module now boots reliably every time. \n\nOther capacitor values might work as well, but I did not experiment further.\n\nThe board is densely packed, leaving little room for additional components. Furthermore, the **EN pin** is not routed to any easily accessible pad. I managed to solder a **0603** capacitor next to the reset button, but to me this was a fairly tricky soldering task.\n\n![Capacitor placement](images/esp32h2_cap_place.jpg)  \nCapacitor placement is indicated by red lines.\n\n![Capacitor photo](images/esp32h2_added_cap.jpg)  \nPhoto of the actual board with the added **4.7µF** capacitor.\n\n## ZHA Quirk\nAs of now, **ZHA (Zigbee Home Automation)** does not fully support several standard Zigbee clusters required for this project, including:\n\n- **Analog Input cluster**\n- **Binary Input cluster**\n- **Multistate Value cluster**\n\nAdditionally, **present_value** atribute of **Multistate Value** cluster is incorrectly defined as **Float32** instead of **uint16** in the underlying **zigpy** library.\n\nUntil these clusters are officially supported in the main **ZHA** integration, a custom **quirk** script is required. This quirk file provides proper cluster handling and also extends supported units for the **Analog Input** cluster, adding **microseconds** as a unit. This is useful for the **Phase Correction** setting in the dimming control.\n\nThe quirk file should be placed in Home Assistant configuration directory under custom_zha_quirks.\nYou may need to restart ZHA integration or Home Assistant for the changes to take effect.\n\nThe screenshot below shows the device page with custom entity names:\n\n![Device page](images/Screenshot.png)  \nZHA device page in Home Assistant.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-eipi%2Fesp32-zigbee-light","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavid-eipi%2Fesp32-zigbee-light","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-eipi%2Fesp32-zigbee-light/lists"}