ESPHome Basics: Build a Custom Sensor with ESP32
Commercial sensors cost $25–$80 and most phone home to the cloud. An ESP32 + DHT22 + PIR sensor costs under $8, runs ESPHome firmware, and reports directly to Home Assistant with zero cloud involvement. This guide walks you from blank chip to live HA entities.
What we're building
A multi-sensor node that reports to Home Assistant in real-time:
Temperature
DHT22 / AHT10
Humidity
DHT22 / AHT10
Motion
HC-SR501 PIR
WiFi RSSI
Built-in ESP32
Parts list (~$8 total)
| Part | Purpose | ~Cost |
|---|---|---|
| ESP32-C3 SuperMini (or any ESP32) | Microcontroller + WiFi | $3.50 |
| AHT10 or DHT22 breakout | Temperature + humidity sensor | $1.50 |
| HC-SR501 PIR module | Motion detection | $1.50 |
| Dupont jumper wires (10 cm) | Wiring | $0.50 |
| USB-C cable + 5V charger | Power | Usually on hand |
| Small project enclosure (optional) | Housing | $2.00 |
Wiring
The AHT10 uses I²C (2 wires + power), the PIR uses a single digital GPIO. Total: 7 wires.
AHT10 VCC → ESP32 3.3VAHT10 GND → ESP32 GNDAHT10 SDA → ESP32 GPIO4AHT10 SCL → ESP32 GPIO5PIR VCC → 5V (VIN pin)PIR OUT → ESP32 GPIO2PIR GND → ESP32 GNDFull ESPHome YAML config
Create a new device in the ESPHome add-on (Home Assistant → ESPHome → New Device) and paste this config. Replace your_wifi_ssid and your_wifi_password with your credentials.
esphome:
name: room-sensor
friendly_name: "Room Sensor"
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable Home Assistant native API (no MQTT needed)
api:
encryption:
key: !secret esphome_api_key
# OTA updates — push new firmware wirelessly
ota:
- platform: esphome
password: !secret esphome_ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Fallback hotspot if WiFi fails
ap:
ssid: "Room-Sensor Fallback"
password: "tinkertok123"
# Web dashboard at device IP (optional, comment out to save RAM)
web_server:
port: 80
# AHT10 temp + humidity via I2C
i2c:
sda: GPIO4
scl: GPIO5
scan: true
sensor:
# Temperature
- platform: aht10
temperature:
name: "Room Temperature"
accuracy_decimals: 1
filters:
- median:
window_size: 5
send_every: 5
humidity:
name: "Room Humidity"
accuracy_decimals: 1
update_interval: 30s
# WiFi signal strength
- platform: wifi_signal
name: "WiFi Signal"
update_interval: 60s
# PIR motion sensor
binary_sensor:
- platform: gpio
pin:
number: GPIO2
mode: INPUT
name: "Motion Detected"
device_class: motion
filters:
- delayed_off: 30s # keep "on" for 30s after last trigger
# Status LED (built-in on ESP32-C3 SuperMini)
light:
- platform: status_led
name: "Status LED"
pin: GPIO8
# Uptime and restart button for diagnostics
sensor:
- platform: uptime
name: "Uptime"
button:
- platform: restart
name: "Restart"
# Log level (reduce to WARNING in production)
logger:
level: DEBUGsecrets.yaml
ESPHome reads credentials from a shared secrets.yaml file so you never hardcode passwords. Create or update it in the ESPHome config directory:
# /config/esphome/secrets.yaml wifi_ssid: "YourNetworkName" wifi_password: "YourWiFiPassword" esphome_api_key: "generate_one_at_esphome.io/encryption-key" esphome_ota_password: "choose_a_strong_password"
First flash (USB)
The first flash must be done via USB. After that, all updates are wireless.
Install ESPHome add-on
Home Assistant → Settings → Add-ons → ESPHome. Install and start it. Open the Web UI.
Create device with the YAML above
Click "+ New Device" → Skip → paste the YAML. Hit Save.
Connect ESP32 via USB and flash
Click "Install" → "Plug into this computer". The ESPHome web flasher runs in your browser — no drivers needed on Chrome/Edge. Select the COM/USB port and flash.
Watch logs for WiFi connection
After flash, click "Logs" in the ESPHome dashboard. You should see: [wifi] Connected → IP: 192.168.x.x. From here, all future updates are OTA.
Accept device in Home Assistant
HA → Settings → Devices & Services. The ESPHome device appears automatically. Click "Configure" → enter your API key. All sensor entities are created instantly.
Extend your sensor
Add a CO₂ sensor
Swap in an SCD41 ($15) on the same I²C bus. Best room air quality sensor available.
platform: scd4xAdd an OLED display
Wire a 128×64 SSD1306 via I²C. Show temp, humidity, and HA states on-device.
platform: ssd1306_i2cAdd a presence radar
LD2410 mmWave radar ($8) — far better than PIR for human presence detection.
platform: ld2410Log to InfluxDB
Add the influxdb: block to push every reading to a time-series database for Grafana dashboards.
platform: influxdbControl a relay
Wire a 5V relay module to any GPIO. Add a switch: block to toggle it from HA.
platform: gpio (switch)Battery-powered node
Enable deep_sleep: in ESPHome. A 3000 mAh LiPo lasts 6–12 months on 5-minute reporting.
deep_sleep: run_duration: 10s