A tiny, coin-cell Zigbee climate sensor that hibernates like its namesake β years on a CR2032, and joins Home Assistant with zero cloud.
Dormouse is a from-scratch, open-hardware temperature + humidity sensor on the Silicon Labs MGM210LA22JNF2 module (EFR32MG21, Cortex-M33, 2.4 GHz). It's a Zigbee sleepy end device: it wakes every 5 minutes, reads an external Sensirion SHT40 over IΒ²C, reports temperature, relative humidity and battery level over Zigbee, then drops back to EM2 sleep. On a single CR2032 that budgets out to multi-year battery life. No hub beyond your existing Zigbee coordinator, no cloud, no vendor lock-in.
Why "Dormouse"? A dormouse hibernates and briefly stirs to feed β which is exactly what a Zigbee sleepy end device does: sleep deep in EM2, wake for a few milliseconds every five minutes, report, and doze off again.
Everything is here: firmware, a custom KiCad schematic + routed 2-layer PCB, a datasheet-exact module footprint, the manufacturing files, and the Home Assistant integration.
- π Coin-cell native β sleepy end device, EM2 sleep, TX power capped so a CR2032 never browns out. ~1β3 Β΅A average.
- π‘οΈ Real ambient temp + humidity β external SHT40 (Β±0.2 Β°C / Β±1.8 %RH), CRC-checked, one-shot read per wake.
- π Zero-config Home Assistant β temperature, humidity and battery auto-expose over ZHA; a ready-made Zigbee2MQTT converter is included.
- π Runtime debug mode β flip a switch in HA to drop to 10 s sampling and stream a live log line, over a manufacturer-specific Zigbee cluster. Auto-off on boot so it never drains the cell.
- π‘οΈ Self-healing β software watchdog (spans the multi-minute sleep), IΒ²C bus recovery, and a button-less factory reset (power-cycle 5Γ quickly β re-commission).
- π οΈ Fully open & reproducible β headless
slc generateβ build β flash; schematic + footprint generated by scripts; DRC-clean routed board; Gerbers included.
| Top | Bottom (CR2032 holder) |
|---|---|
![]() |
![]() |
βββββββββββββββββββββββββββββ every 5 min (10 s in debug) βββββββββββββββββββββββββββββ
β β
wake ββ€ SHT40 read (IΒ²C, CRC) β IADC battery read β write ZCL attrs β reporting β EM2 sleep
β temp + RH VDD via AVDD/4 temp/RH/batt pushes to
β coordinator
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ZCL model (endpoint 1, HA Temperature Sensor 0x0302):
Basic Β· Power Config Β· Identify Β· Temperature (0x0402) Β· Humidity (0x0405) Β· MGM Debug (0xFC10)
The .slcp manifest is the source of truth for components, the target part,
sleepy-device timing and TX power. The ZCL data model lives in a ZAP file; the
#defines in src/app.h mirror it. See CLAUDE.md for the full
architecture write-up.
Tiny 2-layer, ~36 Γ 25 mm board. The MGM210L sits at the top edge with its integrated antenna pointing off-board and a copper keepout around it; the CR2032 holder is on the back; the SHT40 is at the bottom edge for airflow.
| Ref | Part | Purpose |
|---|---|---|
| U1 | MGM210LA22JNF2 | MCU + Zigbee radio (integrated antenna) |
| U2 | Sensirion SHT40 (SHT40-AD1B) | Temp + humidity, IΒ²C 0x44 |
| BT1 | CR2032 SMD holder | Power (~220 mAh) |
| R1, R2 | 4.7 kΞ© (0402) | IΒ²C pull-ups |
| C1 | 10 Β΅F (0805) | Bulk decoupling β sources the TX pulse |
| C2, C3 | 100 nF (0402) | HF decoupling (module + sensor) |
| J1 | 1Γ5 1.27 mm header | SWD / RTT debug |
Full wiring, pinout and CR2032 power design: docs/hardware.md.
KiCad sources, custom libraries and PCB notes: hardware/README.md.
Manufacturing files (Gerbers, drill, BOM, pick-and-place): hardware/fab/.
There is no host/unit-test suite β this is on-target firmware. "Testing" means flashing and watching the join + reports over RTT and in ZHA/Z2M. The toolchain is installed via SLT (Silicon Labs Tool).
# one-time: install SDK 2026.6.0 + slc/gcc/zap/commander
slt install -f tools/pkg.slt
source tools/env.sh # puts slc, arm-none-eabi-gcc, commander, zap on PATH
tools/build.sh # slc generate (runs ZAP) + make -> build/β¦/*.s37
tools/flash.sh # commander flash over J-Link
commander rtt --device MGM210LA22JNF # live device logsThen put your Zigbee network in join mode (ZHA: Add device; Z2M: permit_join)
and power the sensor. Verified working with SDK 2026.6.0, slc-cli 6.0.22, GCC 14.2.
- ZHA β temperature, humidity and battery are zero-config (standard clusters). The custom debug cluster needs a small ZHA quirk to expose.
- Zigbee2MQTT β drop
integration/zigbee2mqtt/dormouse.jsin as an external converter. It exposes temperature, humidity, battery, and the debug entities (debug_modeswitch,debug_log,debug_status,sample_interval).
| Path | What |
|---|---|
mgm210l_zigbee_temp.slcp |
Project manifest β components, target, config. Source of truth. |
src/ |
Firmware: measurement loop, SHT40 driver, battery, debug mode, watchdog, factory reset. |
config/zcl/ |
ZCL data model (ZAP) + custom debug-cluster XML. |
hardware/ |
KiCad schematic + routed PCB, custom symbol/footprint libraries, generators. |
hardware/fab/ |
Gerbers, drill, BOM, pick-and-place β ready to send to a fab. |
integration/zigbee2mqtt/ |
Z2M external converter. |
docs/ |
Hardware guide + rendered images. |
tools/ |
Headless build / flash / env scripts. |
CLAUDE.md |
Deep-dive architecture & rationale (great first read for contributors). |
- Firmware builds end-to-end (
slc generateβ compile β link β flashable.s37) - ZCL model: temperature, humidity, power config, + manufacturer debug cluster (
0xFC10) - SHT40 IΒ²C driver β CRC-8 verified, with automatic IΒ²C bus recovery + one retry
- Battery sensing via internal IADC (no divider), with a bounded busy-wait guard
- Sleepy-end-device power model (EM2 sleep, 300 s poll, 8 dBm TX cap)
- Runtime debug mode (HA-controlled 10 s cadence + live log), auto-off on boot
- Software watchdog (sleeptimer-based, spans multi-minute sleep)
- Button-less power-cycle factory reset (5Γ quick cycles β re-commission)
- Custom, datasheet-exact MGM210LA22JNF land pattern + symbol library
- 2-layer PCB fully routed, GND pours with antenna keepout, 0 copper DRC errors
- Manufacturing package generated (Gerbers / drill / BOM / pick-and-place)
- PCBs ordered π
- Zigbee2MQTT converter + ZHA zero-config path
- GitHub Actions CI β repo + device-identity checks on every push (
ci.yml); firmware.s37build & release via a self-hosted runner (firmware.yml)
- Assemble the boards (reflow / hand-solder), first power-on
- Flash and confirm join + temperature/humidity/battery reports in ZHA & Z2M
- Verify TX power reads 8 dBm on RTT after a warm-reboot join
- Confirm
FACTORY_RESET_NVM3_KEYhas no stack-key collision; test the 5Γ power-cycle reset - Double-check
config/sl_i2cspm_sensor_config.hpins match the built board (PC00/PC01) - Measure real sleep current & validate multi-year battery estimate
- ZHA quirk (zha-device-handlers) so the debug cluster shows up as HA entities
- 3D model for the custom MGM210L footprint (nicer renders + mechanical check)
- 3D-printed enclosure / vented case for the SHT40
- Production build profile (drop
segger_rtt/iostream_rttto shave idle current) - Si7021 sensor variant (swap command byte + conversion only)
- Zigbee OTA firmware update support
- Nudge the one SDA trace to clear the cosmetic 0.05 mm edge-clearance DRC note
Issues and PRs welcome β especially hardware bring-up reports, battery-life data,
and the "help wanted" items above. Please read CLAUDE.md first; it
explains the two-stage build, the .slcp-is-truth rule, and the ZCL/app.h/converter
sync requirement that's easy to trip over.
MIT β see LICENSE. Firmware builds against the Silicon Labs Simplicity
SDK, which carries its own (permissive) license; it is not vendored here β the
build fetches it via SLT.
- Silicon Labs β EFR32MG21 / MGM210L, Simplicity SDK, Zigbee stack.
- Sensirion β SHT4x sensor family.
- The KiCad, Freerouting, and Zigbee2MQTT projects.


