Category: ESPHome

  • Building a Snake Deterrent with ESPHome

    Snakes are highly sensitive to ground vibrations, interpreting them as signs of nearby predators or large animals. This natural behavior can be leveraged to create a humane deterrent system: instead of relying on chemicals or barriers alone, we can generate irregular seismic signals that encourage snakes to move away.

    This project explores how to build a low‑cost, programmable vibration driver using an ESP8266 microcontroller and ESPHome firmware. By switching a 12 V hammer actuator in randomized bursts, the system produces unpredictable vibration patterns that mimic footsteps or animal movement. The result is a practical demonstration of how embedded systems, simple electronics, and open‑source firmware can be combined into a real‑world solution.

    Why Random Bursts?

    A steady metronome‑like vibration quickly becomes background noise. Random clusters of strikes, separated by unpredictable pauses, feel more “alive” and unsettling. This project uses ESPHome on an ESP‑01S relay board to generate those bursts automatically.

    Why 12 V Matters

    One important design choice was to keep the system at 12 V DC. Many garden devices unfortunately operate directly from 230 V mains, which introduces unnecessary electrical hazards in outdoor environments. By standardizing on 12 V, the system remains low‑voltage and touch‑safe, significantly reducing the risk of shock during installation, maintenance, or accidental contact.

    Hardware Setup

    • ESP‑01S WiFi relay board with external voltage regulator 12V -> 5V.
    • 12 V Selenoid Lock, used as hammer actuator mounted to a metal stick pushed into the ground
    • Shared 12 V supply: powers both the hammer and the relay board

    The relay switches the hammer coil, while ESPHome firmware handles the random timing.

    ESPHome Configuration

    Here’s the YAML configuration that runs the random burst script at boot, with a manual switch to enable/disable it:

    yaml
    esphome:
      name: esphome-relay2
      friendly_name: esphome relay2 snake hammer
      on_boot:
        priority: -10
        then:
          - if:
              condition:
                switch.is_on: random_enabled
              then:
                - script.execute: random_burst
    
    esp8266:
      board: esp01_1m
    
    switch:
      - platform: gpio
        pin: GPIO0
        name: "Relay2"
        inverted: true
        id: relay2
    
      - platform: template
        name: "Random Burst Enabled"
        id: random_enabled
        optimistic: true
        restore_state: true
        turn_on_action:
          - script.execute: random_burst
        turn_off_action:
          - script.stop: random_burst
    
    script:
      - id: random_burst
        mode: restart
        then:
          - while:
              condition:
                switch.is_on: random_enabled
              then:
                - lambda: |-
                    int burst = random(2, 5); // 2–4 strikes
                    for (int i = 0; i < burst; i++) {
                      id(relay2).turn_on();
                      delay(200); // hammer ON
                      id(relay2).turn_off();
                      delay(random(300, 1000)); // random pause
                    }
                - delay: !lambda "return random(5000, 15000);" // random gap before next burst
    

    How It Works

    • Burst clusters: 2–4 relay activations per cycle
    • Random intra‑burst delay: 300–1000 ms between strikes
    • Random inter‑burst gap: 5–15 s before the next cluster
    • Control switch: Exposed in Home Assistant and the ESPHome web UI, so the system can be disabled remotely

    Results

    The hammer delivers irregular seismic signals through the ground near entry points. Combined with perimeter lighting and physical barriers, this creates a layered deterrent system. It’s not a silver bullet, but it reduces surprise encounters and adds peace of mind.

    Final Thoughts

    This vibration deterrent system is no longer just a concept on paper — it is currently undergoing real‑world testing. The ESPHome‑driven relay board and hammer actuator are deployed and running continuous randomized bursts, allowing me to observe how the design performs outside of the lab. Early results are promising, but the ongoing field trials will provide the most valuable insights: durability of the hardware, consistency of the randomization, and, most importantly, the behavioral response of snakes to irregular seismic signals.

    By documenting this project as it evolves, I aim to demonstrate not only the technical implementation but also the practical effectiveness of combining embedded systems with behavioral cues in a real environment. This piece highlights the journey from idea to deployment — and the testing phase is where theory meets reality.

  • Reading a Huawei Battery BMS with an ESP32 and ESPHome

    A deep dive into reverse-engineering RS485 Modbus communication to bring industrial battery telemetry into Home Assistant.


    Background

    The Huawei ESM-48100 is a 48V 100Ah LiFePO4 energy storage module originally designed for telecom sites. It’s a well-built, high-density battery — but like most industrial hardware, it was never meant to talk to a home automation system. It exposes data over a 4-wire RS485 interface using Modbus RTU, and Huawei’s official protocol documentation sits behind an enterprise support portal.

    This project was about bridging that gap: taking a piece of industrial-grade battery hardware and making its internal data — state of charge, cell voltages, temperature, alarms — visible in Home Assistant through a $5 ESP32 and a $1 MAX485 transceiver.


    The Hardware Stack

    The physical layer is straightforward but required careful attention to the details.

    Components used:

    • ESP32-WROOM development board
    • MAX485 RS485 transceiver module
    • RJ45 cable terminated to the ESM-48100’s COM port

    The ESM-48100’s COM port is a standard RJ45 connector carrying 4-wire RS485 on pins 1, 2, 4, and 5, alongside CAN bus signals on pins 7 and 8. Only the RS485 lines were used for this project.

    Wiring the MAX485 Module

    The MAX485 chip has two sides — one facing the microcontroller, one facing the RS485 bus. A naming confusion that trips up many people: the module’s pins are labeled DI (Driver Input) and RO (Receiver Output), which reflect the chip’s own perspective, not the ESP32’s. DI connects to the ESP32’s TX line, and RO connects to the ESP32’s RX line.

    Some MAX485 modules expose separate DE and RE pins for flow control — these need to be tied together and driven by a GPIO on the ESP32. Others tie them internally, handling flow switching automatically. Both variants work at 9600 baud with Modbus RTU, though the manual DE/RE approach is more deterministic at higher speeds.

    A 120Ω termination resistor was placed across the A and B lines at the far end of the RS485 bus, as required by the Modbus standard to prevent signal reflections.

    Wiring Summary

    ESP32 GPIO16 (TX) → MAX485 DI
    ESP32 GPIO17 (RX) ← MAX485 RO
    ESP32 GPIO4       → MAX485 DE + RE (if exposed)
    3.3V              → MAX485 VCC
    GND               → MAX485 GND
    MAX485 A+  →  ESM-48100 RJ45 Pin 1 (RS485 T+)
    MAX485 B-  →  ESM-48100 RJ45 Pin 2 (RS485 T-)
    

    The Software: ESPHome and Modbus RTU

    ESPHome is a firmware framework for ESP32/ESP8266 that lets you define hardware integrations entirely in YAML. It natively supports Modbus RTU via its modbus_controller component, which handles framing, CRC, request queuing, and register parsing — so there’s no need to implement the protocol manually.

    The configuration defines:

    • UART component on GPIO16/GPIO17 at 9600 baud, 8N1
    • Modbus component that references the UART
    • Modbus Controller targeting slave address 0x01 with a 10-second poll interval
    • Individual sensors mapped to each holding register

    Register Map

    Sensor Register Scale
    Battery Voltage 0x0000 0.01 V/bit
    Battery Current 0x0001 0.01 A/bit (signed)
    State of Charge 0x0002 0.1 %/bit
    State of Health 0x0003 0.1 %/bit
    Remaining Capacity 0x0004 0.1 Ah/bit
    Max Cell Voltage 0x0005 1 mV/bit
    Min Cell Voltage 0x0006 1 mV/bit
    Max Cell Temp 0x0007 0.1 °C/bit
    Min Cell Temp 0x0008 0.1 °C/bit
    Average Cell Temp 0x0009 0.1 °C/bit
    Status Flags 0x000A bitmask
    Alarm Flags 0x000B bitmask
    Cycle Count 0x000C 1 cycle/bit

    ESPHome Configuration (excerpt)

    uart:
      id: uart_modbus
      tx_pin: GPIO16
      rx_pin: GPIO17
      baud_rate: 9600
      stop_bits: 1
      data_bits: 8
      parity: NONE
      flow_control_pin: GPIO4
    
    modbus:
      id: modbus_esm
      uart_id: uart_modbus
      send_wait_time: 250ms
    
    modbus_controller:
      - id: esm_bms
        address: 0x01
        modbus_id: modbus_esm
        update_interval: 10s
    
    sensor:
      - platform: modbus_controller
        modbus_controller_id: esm_bms
        name: "Battery SOC"
        register_type: holding
        address: 0x0002
        unit_of_measurement: "%"
        device_class: battery
        value_type: U_WORD
        filters:
          - multiply: 0.1
    

    Derived Sensors

    Beyond the raw registers, template sensors were added to derive useful secondary values:

    • Battery Power — calculated as voltage × current (W)
    • Cell Voltage Delta — max minus min cell voltage (mV), a key indicator of cell imbalance
    • Battery State — text sensor decoding the status bitmask into Charging / Discharging / Idle
    • BMS Alarm Active — binary sensor that fires whenever any alarm bit is non-zero

    The Hard Part: Finding the Register Map

    This was the most significant challenge of the project. Huawei’s Modbus protocol document for the ESM-48100 series is not publicly accessible without an enterprise support account. Community documentation is sparse, and what exists is scattered across energy storage forums.

    The ESM-48100 is documented as complying with the YDN1363 protocol over RS485. The register layout used in this project was sourced from community reverse-engineering efforts, not from the official Huawei document — which means it carries some uncertainty. A key caveat discovered during research: some firmware revisions use a 0x1000 base offset for all registers. If sensors return zeros or errors, shifting every address up by 0x1000 is the first thing to try.

    This kind of ambiguity is common when working with industrial hardware in hobby contexts. The approach taken here was to be explicit about what is verified and what is inferred, rather than presenting unverified information as confirmed fact — a discipline that matters when the output is a real electrical system.


    What This Enables in Home Assistant

    Once running, the ESP32 joins the home network and appears in Home Assistant as a device with 15+ entities. From there, the data feeds into:

    • Energy dashboards tracking charge and discharge cycles over time
    • Automations that respond to low SOC, high cell temperature, or active alarms
    • Long-term statistics on SOH degradation and cycle count growth
    • Notifications when the BMS alarm register goes non-zero

    The cell voltage delta sensor is particularly useful — a widening gap between max and min cell voltages over time is an early indicator that cells are drifting apart, which typically precedes a significant SOH drop.


    Reflections

    This project sits at the intersection of embedded systems, industrial protocols, and home automation. The hardware side — RS485 wiring, termination, flow control — required understanding the physical layer of the Modbus standard. The software side required navigating ESPHome’s component model, register types, and value scaling. And the research side required distinguishing between what Huawei officially documents and what the community has inferred.

    The result is a reliable, OTA-updatable, WiFi-connected BMS monitor that costs under $10 in hardware and runs indefinitely without any cloud dependency.


    Built with ESPHome and Home Assistant on an ESP32 with a MAX485 RS485 transceiver.
    Hardware: Huawei ESM-48100B1 LiFePO4 48V 100Ah energy storage module.