Smart Weather Station ESP32: Control High-Voltage Appliances with a 2-Way Relay
Last winter my garage turned into a walk‑in freezer every night because I’d simply forget to flip the heater switch before bed. I wanted something that didn’t just display the temperature but actually did something with it—so I set out to build an ESP32 weather station that reads the room conditions and physically switches a high‑voltage appliance. The result is a small, Wi‑Fi‑connected brain that uses a 5V 2‑way relay module to control a space heater and an exhaust fan. It’s been running ever since, and I’ll show you exactly how I put it together, including the mistakes I made along the way.
Building Your ESP32 Weather Station
The idea is simple: a DHT22 sensor feeds temperature and humidity to an ESP32, a tiny OLED display shows the current readings, and when things get too cold or too hot, the 2‑way relay kicks in to turn mains‑powered appliances on or off. All the logic lives in ESPHome—no Arduino IDE compile‑dance required, though I’ll point out the alternative if you prefer C++.
I started with a bare ESP32 DevKitC and a $3 relay module I had lying around, and quickly learned that choosing the right pins and power supply makes the difference between a reliable automation tool and a paperweight.
Materials & Tools
Here’s everything you need. I’ve added notes from my own trial and error so you skip the parts where I smoked a DHT22 (literally).
ESP32 Development Board Module
ESP32-DevKit board: Buy it here
Any 30‑pin or 38‑pin ESP32 DevKit board will work; I used the standard ESP32‑DevKitC V4.5V 2‑way relay module (e.g., SRD‑05VDC with optocoupler)
Look for one that has a JD‑VCC jumper and accepts 3.3 V logic input. Many modules claim 5 V logic but will still trigger with 3.3 V—I’ll cover that in the wiring.DHT22 temperature / humidity sensor (the DHT11 works too, but the DHT22 is far more accurate—see the FAQ for differences).
SSD1306 128×64 OLED display (I2C, usually address 0x3C). This is optional; you can always read values over Wi‑Fi.
4.7 kΩ – 10 kΩ resistor (pull‑up for the DHT22 data line).
Jumper wires, breadboard, USB power supply (any 5 V ≥ 1 A phone charger).
A lamp or small heater for testing (keep a fire extinguisher ready and double‑check your 110/230 V wiring).
Wiring the ESP32 Weather Station
I originally routed the relays straight to GPIO0 and GPIO2. Huge mistake. Those pins are strapping pins that control boot mode, and the ESP32 refused to start unless the relay inputs were floating exactly at the right voltage. After a few hours of head‑scratching I moved to safer GPIOs. Here’s the layout I’ve used ever since.
Pin connections
| ESP32 Pin | Component | Notes |
|---|---|---|
| 3V3 | OLED VCC, DHT22 VCC | 3.3 V power |
| GND | OLED GND, DHT22 GND, Relay GND | Common ground – tie everything together |
| GPIO21 (SDA) | OLED SDA | I2C data |
| GPIO22 (SCL) | OLED SCL | I2C clock |
| GPIO25 | DHT22 DATA | 10 kΩ pull‑up to 3V3 |
| GPIO26 | Relay IN1 | Ch 1 control (e.g., heater) |
| GPIO27 | Relay IN2 | Ch 2 control (e.g., fan) |
| 5V (VIN) | Relay VCC (JD‑VCC jumper removed) | See power note below |
Relay module power trick: Many 5 V relay boards have a JD‑VCC jumper that connects the relay coil power to the logic VCC. If you keep the jumper, the relay coils will draw current directly from the ESP32’s 3.3 V or 5 V pin—bad idea for high‑current coils. Remove the jumper and feed the relay JD‑VCC pin from the ESP32’s 5 V (VIN) pin, while VCC (logic side) gets 3.3 V. This isolates the coil supply from the logic, and your ESP32 stays stable.
I also strongly recommend a 10 kΩ pull‑up resistor from the DHT22 data pin to 3.3 V. Without it, you’ll get NaN readings—ask me how I know.
Software Setup: ESPHome and the “IDE”
You can write an Arduino sketch if you like. If that’s your jam, install the ESP32 board manager URL (https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json) and grab the Adafruit SSD1306 and DHT sensor library. But for this weather station, ESPHome makes configuration a breeze and integrates seamlessly with Home Assistant, MQTT, and Grafana—topics I’ll mention later.
Install ESPHome
I use the ESPHome dashboard via Docker; you can also pip install esphome. Once you have the dashboard running:
- Click New Device, name it
weather-station. - Copy the unique encryption key that ESPHome generates.
- Connect the ESP32 via USB, select the serial port, and flash a basic “online” node.
This creates an initial YAML file that we’ll modify.
Configuring the ESP32 Weather Station in ESPHome
Below is the complete ESPHome configuration I landed on. It defines the DHT22 sensor, the OLED display, two relay switches, and a simple automation that turns the heater on when the temperature drops below 5 °C.
substitutions:
device_name: weather-station
friendly_name: Garage Weather Station
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
platform: ESP32
board: esp32dev
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: ${device_name} Fallback
password: !secret fallback_password
logger:
api:
password: !secret api_password
ota:
password: !secret ota_password
i2c:
sda: GPIO21
scl: GPIO22
scan: True
id: bus_a
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
address: 0x3C
lambda: |-
it.printf(0, 0, id(my_font), "Temp: %.1f°C", id(garage_temp).state);
it.printf(0, 20, id(my_font), "Hum: %.1f%%", id(garage_humidity).state);
it.printf(0, 40, id(my_font), "Heater: %s", id(heater_relay).state ? "ON" : "OFF");
font:
- file: "gfonts://Roboto"
id: my_font
size: 16
sensor:
- platform: dht
pin: GPIO25
model: DHT22
temperature:
name: "Garage Temperature"
id: garage_temp
humidity:
name: "Garage Humidity"
id: garage_humidity
update_interval: 30s
switch:
- platform: gpio
pin: GPIO26
name: "Heater Relay"
id: heater_relay
restore_mode: ALWAYS_OFF
- platform: gpio
pin: GPIO27
name: "Fan Relay"
id: fan_relay
restore_mode: ALWAYS_OFF
# Simple automation: turn heater on when cold
interval:
- interval: 5s
then:
- if:
condition:
lambda: 'return id(garage_temp).state < 5.0;'
then:
- switch.turn_on: heater_relay
else:
- switch.turn_off: heater_relay
Key sections:
- The
i2cblock uses the standard pins and enables scanning, helpful when your OLED doesn’t show up. - The
displaylambda updates every time a sensor changes, so the OLED always reflects the current values. restore_mode: ALWAYS_OFFensures the relays stay off after a power cut—important for safety.- The
intervalautomation runs every 5 seconds and decides the heater state; you could easily add a second condition for humidity or time‑of‑day.
Save the YAML, then hit Install → Wirelessly (or Plug into this computer) to upload the configuration.
Upload & Test Your ESP32 Weather Station
After a successful upload, the OLED should light up with temperature and humidity. Open the ESPHome dashboard logs (or serial monitor) and you’ll see readings like:
[20:34:52][D][dht:048]: Got temperature=4.8°C humidity=62.0%
Now, connect a low‑power LED or a lamp to the relay’s Normally Open (NO) and COM terminals after unplugging everything from mains. Power up the relay module. When the temperature falls below 5 °C, you should hear the relay click and the appliance turns on.
For a real high‑voltage load, I tested with an old desk lamp plugged into the relay’s input. Always enclose the high‑voltage wiring inside a proper junction box and never touch bare terminals while powered.
Troubleshooting
Real‑world gotchas that drove me crazy:
- Relay not switching, or intermittent clicking: Many 5 V relay modules expect 5 V on the logic input. The ESP32 GPIO outputs only 3.3 V, which can be marginal. I solved it by choosing a module rated for 3.3 V control (they have a low‑current optocoupler). If yours doesn’t trigger, use a level‑shifter or a simple NPN transistor circuit.
NaNtemperature / humidity: Almost always a missing pull‑up resistor on the DHT22 data line. Add a 4.7 kΩ – 10 kΩ resistor between DATA and 3.3 V. Also, use short wires (<20 cm).- Blank OLED display: Check the I2C address. Run
i2c scanin the logs to see if0x3Cis found. Some clones use0x3D. If nothing appears, verify VCC and GND; the SSD1306 can’t tolerate 5 V on its I2C pins, so don’t power it from the VIN pin. - Upload fails, “Timed out waiting for packet”: GPIO0 and GPIO2 strapping pins mess with boot. Move your relays to GPIO26/27 (or any clean GPIO 12, 13, 14, 32, 33) and try again. Also, try holding the BOOT button while flashing.
- ESP32 reboots when relay toggles: The relay coil draws a spike of current. Power the coil from a separate 5 V rail (the VIN pin) with the JD‑VCC jumper removed, and add a 100 µF capacitor across the relay power supply.
Enhancements & Next Steps
This weather station is just the start. Once you have stable automation, you can:
- Log data over Wi‑Fi: In the ESPHome YAML, add an
mqttclient and push readings to a broker. I later connected the station to Home Assistant, where I combined multiple temperature sensors—including the Aqara ones I set up with Zigbee2MQTT back when I wrote this guide. Home Assistant then becomes the central brain, overriding the local automation when no one’s home. - Add visual alerts: I use Grafana to plot long‑term temperature trends and fired‑off alerts with custom messages. If that sounds useful, my Grafana alerting walkthrough shows how to template your own.
- Deep sleep for battery operation: If you don’t need real‑time switching, put the ESP32 into deep sleep and wake it every 10 minutes. Combine with a relay that latches (use a bistable relay module).
- Upgrade the sensor: Swap the DHT22 for a BME280 to get barometric pressure. The I²C wiring stays identical—just change the
sensorplatform in ESPHome. - Safety first: Add a temperature fail‑safe: if the sensor reading fails, turn off the relays. In ESPHome, you can use
on_valueautomation withsensor.timestampto detect stale data.
For a simpler indoor‑only monitoring setup that doesn’t need relay control, I previously documented a pure monitoring build using the Xiaomi Mijia sensor and ESPHome: How to Monitor Your Home Temperature.
FAQ
Can I use a DHT11 instead of the DHT22?
Yes, but the DHT11 has ±2 °C accuracy and a slower update interval, while the DHT22 delivers ±0.5 °C. If you only need approximate readings, the DHT11 will work; just change model: DHT22 to model: DHT11 in the YAML. Personally, I’d spend the extra dollar for the DHT22—when you’re controlling a heater, half a degree matters.
Why is my relay clicking but the appliance doesn’t turn on?
Check that you’re using the normally‑open (NO) terminal, not the normally‑closed (NC). Also make sure the high‑voltage circuit is complete—I once forgot to plug the appliance into the relay output. Finally, verify that the relay coil is actually switching the contacts; sometimes the mechanical armature sticks if the coil power is too weak.
Can I control more than two appliances?
Absolutely. Use an ESP32 with more free GPIOs and connect a 4‑ or 8‑channel relay module. Just be mindful of the total current draw of the relay coils—you may need an external 5 V supply. ESPHome supports up to 128 switch instances.
How do I power the ESP32 and relay from the same 5 V USB supply?
Take 5 V from the USB input (VIN pin) to power the relay coils (JD‑VCC), and let the ESP32’s onboard regulator provide 3.3 V to the logic side. This works as long as your USB source can deliver enough current—typically 2 A for a 2‑channel relay board. I’ve run this 24/7 with a standard 5 V / 2 A phone charger without issues.
Is it safe to control high voltage with this relay module?
The module itself is designed to handle up to 250 VAC at 10 A, but your wiring is what determines safety. Always mount the relay and high‑voltage terminals inside an insulating enclosure, use proper cable glands, and include a dedicated fuse or circuit breaker. If you’re not comfortable with mains electricity, ask an electrician—no tutorial is worth a shock.
My ESPHome configuration fails to find the SSD1306 after a while. What’s wrong?
I’ve seen this with certain clone displays that have a slow power‑on reset. Add reset_pin: GPIO16 (or any unused output pin) and set reset_duration: 10ms in the ssd1306_i2c component. Also, ensure the I2C wires are short and not routed near the relay’s high‑current paths, which can induce noise.
Now that your ESP32 weather station controls appliances, you’ve got a solid foundation for an energy‑efficient, automated space. Keep tinkering—every relay click feels like a small victory.