/ #ESP32 #weather station 

ESP32 Weather Station Alert: DIY Touchless Alarm System with Infrared Obstacle Avoidance

Last winter, right after I had finally fine‑tuned my home‑brewed ESP32 weather station, our cat discovered the temperature sensor dangled from the windowsill and treated it as a feline punching bag. Within a week the outdoor humidity reading was permanently stuck at 99%—not because of a monsoon, but because the sensor had been batted onto the muddy ground one time too many.

I needed a way to know when something (or someone) got within paw‑swiping range of my weather kit, without turning the project into a tripwire‑laden fortress. The answer turned out to be stupidly simple: an infrared obstacle avoidance module, a buzzer, and a little ESPHome logic that shrieks whenever anything breaks the invisible beam around the station. It’s touchless, costs less than a coffee, and has already saved the outside sensor from my cat’s “field research” three times this month.

Here’s exactly how you can build the same touchless alarm for your own ESP32 weather station—no soldering iron required if you use a breadboard.

What You’ll Need

All the parts are easy to find and together they total about the price of a decent pizza. I’ve linked the main board with an affiliate shortcode, because that’s how I afford the next batch of fried‑when‑I‑wired‑them‑backwards components.

  • {{ <affiliate_link name=“esp32-devkitc”> }} (any ESP32 development board module with USB will work; I used a WROOM‑32D)
  • Infrared Obstacle Avoidance Module (the little red‑board sensor with an LM393 comparator and a preset potentiometer)
  • Active Buzzer (3.3–5 V, self‑oscillating; the kind that beeps when you just feed it DC, not a passive piezo that needs PWM)
  • Breadboard + jumper wires (male‑to‑female make life easier)
  • USB cable for programming

Optionally, grab a 100 µF electrolytic capacitor to smooth the 3.3 V rail if your USB power is noisy—more on that in the troubleshooting section.

Wiring – Keep It as Short as the Cat’s Attention Span

The IR obstacle avoidance module has three pins: VCC, GND, and OUT. The active buzzer usually has three pins too (VCC, GND, I/O), or sometimes two. If yours has two pins, the longer leg is positive and you’ll drive it from a GPIO through a small transistor—but the three‑pin variant is simpler, so I’ll assume that.

ESP32 PinConnects to…Notes
3.3 VIR module VCC
Buzzer VCC
Both modules run at 3.3 V
GNDIR module GND
Buzzer GND
Common ground
GPIO 13IR module OUTDigital output; LOW = obstacle
GPIO 12Buzzer I/OHIGH = buzzer screams

I deliberately chose GPIO 13 and GPIO 12 because they don’t interfere with boot strapping pins or the built‑in LED on many dev boards, so debugging stays predictable. If you’re using a board with a tiny OLED already attached (like I did on the indoor display unit of my weather station), just remap to any available pin and update the ESPHome config accordingly.

Tip: The IR module comes with an onboard potentiometer. Turn it fully clockwise during wiring, then adjust sensitivity after you’ve got the logic working. Clockwise typically increases detection distance, but every clone seems to reverse the direction, so trust the test, not the silkscreen.

Software Setup – ESPHome Because I’m Lazy and Value My Sanity

In a previous guide I walked through using ESPHome to monitor temperature with Xiaomi Mijia sensors, and that whole toolchain has spoiled me. Instead of wrangling C++ and the Arduino IDE all over again, I’m staying within ESPHome. It gives me a clean YAML definition, OTA updates, and dead‑simple integration with Home Assistant—where I can later log every time the alarm fires.

If you don’t have ESPHome yet, head over to esphome.io and follow the installation for your OS (Home Assistant add‑on, Docker, or pip). Once the dashboard is running, create a new node called something like weather-station-alarm.

Here’s the full YAML I’m using:

esphome:
  name: weather-station-alarm
  friendly_name: Weather Station Alarm

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "your-unique-key"

ota:
  - platform: esphome
    password: "your-ota-password"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Fallback hotspot in case WiFi disappears
  ap:
    ssid: "Weather-Station-Alarm"
    password: "fallback123"

captive_portal:

# --- Our sensor and alarm ---
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO13
      mode: INPUT_PULLUP   # The IR module pulls OUT low when an obstacle is present
    name: "IR Obstacle Detected"
    id: ir_obstacle
    filters:
      - delayed_on: 50ms   # tiny debounce
      - delayed_off: 50ms
    on_press:
      then:
        - output.turn_on: buzzer
        - delay: 500ms
        - output.turn_off: buzzer

output:
  - platform: gpio
    pin: GPIO12
    id: buzzer

What’s happening in this YAML:

  • The binary_sensor reads GPIO 13 with an internal pull‑up. The IR module’s OUT pin goes low when something approaches – that’s our PRESS event.
  • Two delayed_* filters act as a simple hardware‑denoiser. I’ve learned the hard way that those tiny LM393 boards love to chatter for a millisecond when you accidentally breathe near them. 50 ms has been the sweet spot that doesn’t miss real intrusions but ignores most jitter.
  • When the sensor trips, the on_press automation turns the buzzer on for half a second, then off. That gives a clear, short beep rather than an endless scream. (If you prefer a constant alarm until the obstacle clears, swap the logic to on_press: output.turn_on: buzzer and on_release: output.turn_off: buzzer.)
  • I’ve named it Weather Station Alarm so that in Home Assistant I instantly know which entity suddenly disturbed my coffee break.

If you already have an secrets.yaml file set up for your Wi‑Fi, great. If not, just replace !secret with your real SSID and password for first flash, but switch to secrets later—you’ll thank yourself when you inevitably share a screenshot.

Flashing and First Test

Connect the ESP32 via USB. In the ESPHome dashboard, click the three dots next to your node and choose “Install”. If this is the first upload, you’ll need to connect directly via USB and select the correct serial port. After that, OTA updates work wirelessly.

Once the device boots, open the ESPHome logs (again from the dashboard) and wave your hand in front of the IR module’s LEDs. You should see logs like:

[I][binary_sensor:036]: 'IR Obstacle Detected': Sending state ON
[I][binary_sensor:036]: 'IR Obstacle Detected': Sending state OFF

At the same time, the buzzer should chirp for half a second. If nothing happens, don’t panic—the next section covers the most common gremlins.

Adjusting the Sensitivity

That tiny blue potentiometer on the IR module is everything. Turn it slowly while keeping your hand at the distance you want to protect (I aimed for about 30 cm). When the detection LED on the module itself lights up, you’re in the sweet spot. Back it off just a hair until the LED turns off with nothing present, so the alarm doesn’t self‑trigger in still air. Yes, it took me three cups of coffee and a dozen “false positive shout‑tests” to dial mine in, but the result is rock‑solid.

Troubleshooting – The “Why Is It Laughing at Me?” Moments

The buzzer stays on continuously

Double‑check the delay block in the YAML. If you accidentally wrote delay: 500000ms you’ll be deaf for a good eight minutes. Also, make sure you’re using an active buzzer—passive buzzers need a PWM square wave, and feeding them straight DC does nothing or just silently destroys them.

Random triggers even with nothing nearby

Noise on the 3.3 V rail can cause the IR module’s comparator to jitter. Adding a 100 µF capacitor across VCC and GND of the module (observe polarity) often cleans it right up. Also, some cheap USB cables pick up Wi‑Fi interference; swapping to a ferrite‑beaded cable solved an intermittent phantom‑trigger case I had in the garage.

The logs show “GPIO” errors or the device boots but the sensor never changes state

Ensure the IR module’s OUT pin is actually connected to GPIO 13, not the other way around. Check with a multimeter: OUT should sit at ~3.3 V when idle and drop to near 0 V when you cover the LEDs. If it doesn’t, the module might be dead or the potentiometer is set so far out that it never crosses the comparator threshold.

ESPHome upload fails with “A fatal error occurred: Failed to connect to ESP32”

Hold the BOOT button on the board while plugging in USB, then release after the flash begins. Some boards also need you to press EN afterwards. I keep a cheap UART adapter handy just in case, but 90 % of the time the boot‑button dance works.

Enhancements – Because One Chirp Is Never Enough

After the basic alarm worked, I couldn’t help myself and layered on a few extras:

Home Assistant notifications

Since the binary sensor appears automatically in HA thanks to the API integration, I created an automation that pushes a notification to my phone whenever the beam is broken for more than two seconds. That way I know whether it’s the cat, the postman, or a stray football. (If you want a full alerting pipeline with custom messages, I’ve detailed a similar setup in my Grafana alerting custom message guide.)

Deep‑sleep for battery power

An IR obstacle alarm is a perfect candidate for deep‑sleep if you plan to put it somewhere far from an outlet. Add a deep_sleep component that wakes the ESP32 for 100 ms every second, checks the sensor, and only connects to Wi‑Fi and sends a notification if an obstacle is actually present. My test rig on a 2000 mAh LiPo ran for three weeks before I recharged—plenty long enough to guard a remote weather station.

Upgrading to a PIR or microwave sensor

The IR avoidance module works great indoors or under an eave, but direct sunlight confuses it badly. When I moved my weather station to a south‑facing wall, I swapped to a PIR sensor with a fresnel lens, keeping the exact same wiring pinout. The logic didn’t change at all, just the sensor.

Final Thoughts

What started as a cat‑proofing measure turned into a surprisingly useful sidecar for my ESP32 weather station. Now I know the second anyone—or any furry investigator—gets too close to the outdoor sensor, and I didn’t have to dive back into Arduino monstrosities to make it happen. ESPHome handled all the heavy lifting, just like it did when I first connected Xiaomi Mijia temperature sensors over Zigbee2MQTT, and the whole thing has been running stably for weeks.

If you’re building your own smart weather station ESP32, consider this $3 alarm a tiny insurance policy. It won’t stop a determined raccoon, but it’ll definitely give you peace of mind—and some amusing log entries.


FAQ

Can I use a passive buzzer instead of an active one?

Yes, but you’ll need to generate a PWM signal (e.g., using output.ledc) at around 2–4 kHz to make it sing. Active buzzers are much easier because they just need high/low, so I recommend sticking with the active kind for this project.

Why does my IR sensor trigger in bright sunlight?

Infrared obstacle avoidance modules can misinterpret strong ambient IR (like direct sunlight or halogen lamps) as a reflection. Shield the sensor with a small hood, or switch to a PIR/ultrasonic sensor for sunny outdoor locations.

How do I make the alarm beep continuously until I reset it?

Modify the on_press automation to turn the buzzer on without a delay, and remove the output.turn_off action. Add an on_release block to turn it off only when the obstacle clears. Be careful—you might regret not having a mute option if the cat discovers it at 3 AM.

Can I use a DHT22 temperature sensor alongside this alarm on the same ESP32?

Absolutely. The alarm only uses two GPIOs. You can add sensor components for a DHT22 on different pins (e.g., GPIO 14) without any conflict. In fact, that’s exactly how I ended up integrating the alarm directly onto the weather station board itself.

What’s the maximum detection distance?

The typical IR obstacle avoidance module can sense up to about 30–80 cm, depending on the surface’s reflectivity. A white wall triggers from farther away; a black velvet curtain may need to be nearly touching the sensor. Adjust the onboard potentiometer and test with the object you care about.

Why does the binary sensor state toggle on/off rapidly?

You probably forgot the delayed_on/delayed_off filters. Without them, the raw GPIO signal from the LM393 comparator can oscillate right at the threshold distance. The 50 ms debounce filter in the YAML example above cures that instantly.