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.
Mains-powered contacts are easy. Battery contacts on ESP32 are easy to get wrong: the radio stays up, the reed sits on a pin that cannot wake the chip, and the cell is dead in two days. This pack is the sleepy pattern: wake on open or close, publish once, sleep again, and report battery voltage on a slow backup timer.
Wi-Fi credentials stay in secrets.yaml. Never paste SSIDs, PSKs, or API keys into a published YAML.
What problem it solves
You want a door or window contact in a shed, attic hatch, or interior door where pulling 5 V is annoying — without a Zigbee hub if you are already on ESPHome, and without a sensor that needs weekly charging.
How it works
- Reed on a wakeup GPIO — magnet present = closed (or the reverse; the pack inverts in YAML). The pin is an input with pull-up, and it is also the deep-sleep wakeup pin. The chip wakes on one pin level, so the YAML sets
wakeup_pin_mode: INVERT_WAKEUP: if the door is already open when the chip goes to sleep, ESPHome flips the wake level so the next close wakes it. Open and close both report. - Short run window — on boot, ESPHome connects, publishes the contact binary sensor and battery voltage, then
deep_sleep.enterafter a few seconds (long enough for HA to see the state). - GPIO wakeup — open or close the door, the pin wakes the ESP32, it reports the new state, and it sleeps again.
- Timed wakeup — a backup
sleep_duration(hours, not minutes) so a missed edge still refreshes battery voltage and an “I’m alive” timestamp. - Low battery — ADC on a divider (or the board’s VBAT pin if it has one) with a binary sensor at a cutoff you pick.
This is not a lock. It is a contact. Treat it that way.
Hardware notes
- Board. An ESP32-C3 Super Mini is small enough for a door jamb box. On the ESP32-C3, only GPIO0–GPIO5 can wake the chip from deep sleep. The pack uses GPIO4 and lists the pins to avoid: GPIO2, GPIO8, and GPIO9 (boot straps) and GPIO18/GPIO19 (USB).
- Reed. A glass reed + magnet is enough. Mount so the magnet is next to the reed when the door is shut; leave slack in the wires so a slam does not rip the header.
- Power. A small LiPo with a charge board is the usual path. Measure after the divider; a raw LiPo will exceed 3.3 V ADC range.
- Antenna. A metal door frame eats 2.4 GHz. Offset the board into the jamb cavity, not behind a strike plate.
Snippet
Trimmed from the pack YAML. Names and pins are substitutions, not a live house:
substitutions:
friendly_name: Shed door
reed_pin: GPIO4 # ESP32-C3: only GPIO0–GPIO5 can wake from deep sleep
battery_pin: GPIO1
divider_ratio: "2.0"
esp32:
board: esp32-c3-devkitm-1
framework:
type: esp-idf
binary_sensor:
- platform: gpio
pin:
number: ${reed_pin}
mode:
input: true
pullup: true
inverted: true
allow_other_uses: true
name: Contact
id: reed_contact
device_class: door
filters:
- delayed_on_off: 20ms
sensor:
- platform: adc
pin: ${battery_pin}
id: battery_voltage
name: Battery voltage
attenuation: 12db
filters:
- multiply: ${divider_ratio}
deep_sleep:
id: sleeper
run_duration: 15s
sleep_duration: 6h
wakeup_pin:
number: ${reed_pin}
allow_other_uses: true
inverted: true
mode:
input: true
pullup: true
# Wake on open AND close: if the pin is already at the wake level when the
# chip sleeps (door left open), flip the level so the next close wakes it.
wakeup_pin_mode: INVERT_WAKEUP
# Wi-Fi, API, on-connect report, and the stay-awake-for-OTA helper: full YAML in the pack
Setup outline
- Wire reed to the wakeup GPIO and GND (or 3V3, matching the pull). Confirm open/close in a USB-powered ESPHome log before enabling deep sleep.
- Add the ADC divider, flash the pack YAML, adopt in Home Assistant.
- Enable deep sleep, disconnect USB, run on battery. Open and close the door: HA should see a brief online blip and a stable contact state.
- Leave it overnight. Battery voltage should tick on the timed wakeup; contact changes should still report within a couple of seconds of the edge.
Troubleshooting
- Never wakes on the door. That GPIO is not a deep-sleep wakeup pin on this ESP32, or
inverted/wakeup_pin_modedoes not match the reed idle level. Test the pin with a jumper to ground before blaming the magnet. - Wakes once, then sleeps forever.
run_durationis shorter than Wi-Fi + API connect. Raise it, or enter sleep only fromon_connectafter the contact is published. - Never sleeps (dead overnight). A sensor or logger is holding the loop, or USB-CDC is keeping the chip awake. Disable verbose logger on battery builds; do not leave
power_save_modeoff. - Battery reads 0.0 or 3.3 forever. Wrong ADC pin, missing divider, or attenuation too low. Measure with a meter at the pad the YAML names.
Credits
Based on the ESPHome deep sleep component and the community thread Reed door switch with deep sleep. This write-up is an original Super Mini recipe, not a paste of those pages.