Esp32

Five ESP32 Devices I Built for My Smart Home (And Which I'd Build Differently)

Independent technologist · 200+ HA devices · GriswoldLabs
10 min read

I have five ESP32 devices running in production around the house. Two are open-source projects I flashed and installed mostly as-is; three are my own builds for problems that didn’t have a good off-the-shelf answer. They’ve collectively been running for over a year now, which is enough time to have opinions on what was worth the effort and what wasn’t.

This post is what each one does, what I’d change, and the YAML / build details that matter.

1. RATGDO — chain-drive garage door controller

What it is: A small ESP32 board that wires into the existing wires of a chain-drive garage opener and exposes the door as a Home Assistant cover entity over ESPHome native API.

Why I built it: The garage opener is a 15-year-old chain-drive with no smart features. I didn’t want to replace the opener (it works fine, why throw it away), and I didn’t want a separate “smart garage” hub that would phone home to a vendor cloud. RATGDO sits between the existing wall button and the opener, gives me lift / lower / status, and reports state changes to HA in under 200ms.

What I’d build differently: Nothing. RATGDO is the cleanest ESPHome project I’ve installed. The board is about $50, install is 10 minutes (three wires), the firmware is well-maintained, and it just works. If you have a chain-drive opener, this is the answer.

The config is the stock RATGDO ESPHome YAML — I haven’t customized it beyond the WiFi credentials and entity names. The only HA-side automation worth mentioning is the auto-close I covered in the home security post: if the door has been open for five minutes and home mode is Away, close it.

2. Gate alarm

What it is: A battery-powered ESP32 with a magnetic reed switch wired across the side gate, a battery monitor, and deep-sleep firmware that wakes only on state change. Reports gate-open events over ESPHome native API back to HA.

Why I built it: The side gate is too far from any outlet for a wired sensor, and I wanted to know when it opened. Off-the-shelf battery-powered Zigbee contact sensors exist, but they all assume a small door — I needed something that could survive a year of outdoor weather without water ingress.

The build is an ESP32 dev board, a 3.7V Li-Ion 18650 cell, a TP4056 charging board with battery protection, a small voltage divider for monitoring battery percentage, and a reed switch glued to the gate frame. Total parts cost under $20. The enclosure is a 3D-printed IP65-ish box with a silicone gasket on the lid.

The ESPHome config uses deep sleep aggressively. The board sleeps until either (a) a wake-on-pin trigger fires (reed switch state change) or (b) a 6-hour timer expires for a heartbeat report. The wake-on-change pattern looks like:

esp32:
  board: esp32dev

deep_sleep:
  id: deep_sleep_1
  wakeup_pin:
    number: GPIO27
    inverted: true
  run_duration: 30s
  sleep_duration: 6h

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO27
      mode:
        input: true
        pullup: true
      inverted: true
    name: "Side Gate"
    id: gate_state
    on_state:
      - delay: 200ms
      - component.update: gate_state

run_duration: 30s means the board stays awake for 30 seconds after waking — long enough to publish the state change to HA over the API, then it goes back to sleep. Sleep current draw is around 10 µA, which gets me about a year on the 18650.

What I’d build differently: I’d use a slightly bigger battery. The 18650 lasts a year, but barely — by month 11 I’m dropping below 30% and getting low-battery notifications, and the swap is fiddly enough that I’d rather not do it annually. Going to a 21700 (20% more capacity) or two 18650s in parallel would push me to 18-24 months. Worth the slightly bigger enclosure.

I’d also skip the battery monitor’s voltage-divider approach and use an INA219 current/voltage sensor instead. The voltage divider draws a constant ~50 µA, which is significant when you’re trying to hit single-digit microamps in deep sleep. INA219 has a software-shutdown mode that drops to <1 µA.

The HA side is the gate alarm automation from the security post — gate opens, notify family, with a calendar-based mute for the lawn service.

3. Electric-fence monitor

What it is: An ESP32 hooked to a current sensor on the electric fence’s power input. If the fence loses power, HA gets notified.

Why I built it: I have an electric fence around a paddock at the edge of the property. The fence energizer runs on 120V from a GFCI outlet that’s prone to tripping during storms. If the fence is unpowered for any length of time, the animals figure it out. By the time I notice, the perimeter is no longer a perimeter.

The build is just an ESP32 with a non-contact current sensor (SCT-013-005, a clamp-on CT) on the energizer’s hot wire. The CT outputs a small AC voltage proportional to current; I rectify and integrate it in software.

sensor:
  - platform: ct_clamp
    sensor: adc_input
    name: "Electric Fence Current"
    update_interval: 10s
    sample_duration: 200ms
    on_value:
      then:
        - if:
            condition:
              lambda: 'return x < 0.05;'
            then:
              - binary_sensor.template.publish:
                  id: fence_powered
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: fence_powered
                  state: ON

binary_sensor:
  - platform: template
    name: "Electric Fence Powered"
    id: fence_powered
    device_class: power

The threshold (x < 0.05) is empirical — the energizer pulls about 0.4A in steady state, and zero when off. Anything below 0.05A I’m calling “off” with margin to spare for noise.

The HA automation notifies me on power loss with a 30-second debounce (which catches normal momentary GFCI nuisance trips that auto-reset). If the fence is dead for 30+ seconds, I get a phone notification.

What I’d build differently: I’d use a properly burdened CT board (already includes the burden resistor, ADC, and an ATMega-style serial output) instead of doing the math in ESPHome. Saves the integration code, more accurate, less drift over time.

4. Vacuum water relay

What it is: An ESP32 controlling a 12V solenoid valve on the makeup-water line for the central vacuum’s wet-vac canister. Triggered by HA when the canister is full, opens the valve to let water drain, closes when empty.

Why I built it: The Beam central vac has a big wet-vac collection bucket that needs to drain to a floor sink. The bucket has a sensor for “full” but no way to actually drain itself. I wanted to plumb a drain line from the bucket to the floor sink with a valve that opens automatically.

The build is a small ESP32 in a project box, wired to a 12V relay board, a 12V solenoid valve, and a 12V wall-wart power supply. The relay drives the valve. The ESP32 publishes a switch entity to HA. HA controls the switch based on the bucket-full sensor.

The ESPHome config is genuinely just a single switch.gpio block:

switch:
  - platform: gpio
    pin: GPIO23
    name: "Vacuum Drain Valve"
    id: drain_valve
    icon: mdi:water-pump

That’s basically it. All the smarts live in HA: when the canister-full sensor goes on, open the valve. After 30 seconds, close it. If it re-triggers within 5 minutes, escalate (probably a clog or a sensor stuck-on).

What I’d build differently: The single biggest mistake on this build was using a normally-closed valve. When power fails, the valve closes. That sounds safe, but in practice it means the canister doesn’t drain on power outages — if a power outage happens during a drain cycle, you can get a small amount of water trapped above the valve until power comes back. A normally-open valve would have been better, with the relay holding it closed during normal operation.

I’d also add a leak sensor next to the floor sink. If the sink ever clogs and the drain backs up, I want to know.

5. Dashcam BMS — battery management for a 12V hardwire kit

What it is: An ESP32 with a BQ76920 battery management chip, monitoring a 4S Li-Ion pack that powers the BlackVue dashcam in one of the cars for parking-mode recording. Reports cell voltages, pack current, and temperature back to HA.

Why I built it: Parking-mode recording on a dashcam draws about 250 mA continuously. The car battery can supply that for maybe 24-36 hours before you start risking a no-start. A separate Li-Ion auxiliary battery decoupled from the car’s electrical system lets the dashcam record indefinitely on its own pack, with the pack recharging from the car when the engine runs.

The off-the-shelf solutions exist (Cellink, BlackBox PowerCell) but cost $300+ and don’t expose any monitoring. I built mine for under $100 in parts and got real-time pack health data into HA as a side benefit.

The board is a custom KiCad design with the BQ76920 (Texas Instruments, 4S BMS chip, I2C interface), an ESP32, and a TP4056-style charge circuit. Currently on revision 2; rev 1 had a charging-current limit that was too low for cold-weather scenarios. JLCPCB does the fab for $5 in qty 5.

The ESPHome config is the most complex of the five — the BQ76920 isn’t a stock ESPHome component, so I wrote a small external component that wraps the I2C calls. Cell voltages and pack current update every 10 seconds; pack temperature every minute.

What I’d build differently: Two things.

First, the BQ76920 is at the bottom of TI’s BMS lineup — it does cell balancing and over-current protection but not coulomb counting. The BQ40Z80 is a higher-end chip with proper SOC estimation. The downside is it’s about 4× the price and harder to get in single quantities. For a personal project, the BQ76920’s “voltage-based SOC estimation” is fine; for anything safety-critical, get the better chip.

Second, I should have used a sealed enclosure with a Gore vent (small membrane that lets air through but blocks water and dust). The current enclosure is a standard project box that’s not rated for the engine bay. I have it mounted inside the trunk well, which is fine, but it limits where I can put the next iteration.

The HA side is mostly observability — a Lovelace card showing cell voltages, pack temp, pack current, SOC. Plus one automation: if any cell drops below 2.8V, send an urgent notification (means the BMS is about to disconnect the load to protect the cells, and the dashcam is about to lose power).

What I learned across all five

A few patterns worth pulling out:

ESPHome native API beats MQTT for these sizes of project. I started with MQTT for two of these and migrated everything to native API. The API is faster, more reliable, has built-in encryption, and integrates more cleanly with HA. The only reason to use MQTT is if you have non-ESPHome devices that need to share the broker — and even then, you can run both side by side.

Deep sleep is harder than it looks. The gate alarm took three iterations to get right. Sleep current matters more than wake-up current; a 10 µA deep-sleep current draw is fine for a year on an 18650, but a 100 µA difference (one wrong pull-up resistor) cuts that to a month. Measure it with a real microammeter, not by eyeballing the LED on a USB power monitor.

External components are cheap to write and worth it. The BQ76920 wrapper is about 200 lines of C++ and took an evening to write. ESPHome’s external-component infrastructure makes it easy. If you have a sensor or chip that isn’t supported, writing the wrapper yourself is usually faster than waiting for someone else to.

The boring builds last. The RATGDO and the vacuum water relay are the simplest of the five — both effectively a single GPIO controlling a relay — and they’ve never given me a problem in 12+ months of operation. The complex ones (gate alarm, BMS) are the ones that needed multiple revisions. Build simple where you can.

If you’re starting from one of these: RATGDO is the lowest-effort, highest-payoff. Then a contact sensor or two on the doors that don’t already have one. Then go from there.

Tags: #esp32 #esphome #home-assistant #diy #iot
Share: X / Twitter Facebook

Related Articles