Writing Arduino code is powerful, but sometimes you just want a sensor that works without debugging C++. That is where ESPHome comes in. ESPHome lets you configure ESP32 devices using simple YAML files -- describe what hardware is connected and how it should behave, and ESPHome generates the firmware for you.
In this article, you will install ESPHome, create your first device, and see it appear automatically in Home Assistant.
🔗What Is ESPHome?
ESPHome is a system that turns YAML configuration files into compiled firmware for ESP32 (and ESP8266) devices. You describe your hardware -- "I have a DHT22 on GPIO 4" -- and ESPHome generates, compiles, and flashes the firmware. No C++ needed.
graph LR
A[YAML Config] -->|compile| B[ESPHome]
B -->|flash USB / OTA| C[ESP32]
C -->|auto-discovery| D[Home Assistant]Key features:
- YAML-based -- readable, version-controllable configuration
- Auto-discovery -- devices appear in Home Assistant automatically
- OTA updates -- after the first USB flash, update wirelessly over your network
- Logs -- view real-time logs from the device in your browser
- 1,800+ supported components -- sensors, displays, LEDs, motors, and more
- Home Assistant native API -- direct connection, no MQTT broker needed
🔗Installing ESPHome
🔗In Home Assistant (Recommended)
If you followed the Home Assistant setup guide, ESPHome is available as an add-on:
- Go to Settings > Add-ons > Add-on Store.
- Search for ESPHome.
- Click Install, wait for it to finish, then click Start.
- Enable Show in sidebar for quick access.
You now have an ESPHome dashboard accessible from Home Assistant's sidebar.
🔗Standalone (Without Home Assistant)
You can also run ESPHome standalone on your computer using pip:
pip install esphomeThen use the command line to create and flash devices:
esphome wizard my_device.yaml # Create a new config interactively
esphome run my_device.yaml # Compile and flash
esphome logs my_device.yaml # View live logsThe Home Assistant add-on is more convenient, but the standalone option works well if you prefer the command line or do not have Home Assistant yet.
🔗Your First ESPHome Device
Let us create a device with a DHT22 temperature/humidity sensor and an LED connected to an ESP32.
🔗Wiring
| Component | Pin | ESP32 Pin | Notes |
|---|---|---|---|
| DHT22 | VCC | 3.3V | Power |
| DHT22 | GND | GND | Ground |
| DHT22 | DATA | GPIO 4 | Add a $10\,\text{k}\Omega$ pull-up resistor to 3.3V |
| LED | Anode (+) | GPIO 2 | Through a $220\,\Omega$ resistor |
| LED | Cathode (-) | GND |
Many ESP32 DevKit boards have a built-in LED on GPIO 2. If yours does, you can skip the external LED and just use the onboard one.
🔗Step 1: Create the Device
- Open the ESPHome dashboard (from the Home Assistant sidebar or at
http://<HA_IP>:6052). - Click New Device.
- Give it a name:
living-room-sensor(use lowercase with hyphens, no spaces). - Select ESP32 as the device type.
- ESPHome will generate a basic configuration. Click Install and choose Plug into this computer for the first flash.
🔗Step 2: Edit the Configuration
After the initial setup, click Edit on the device card. Replace the generated configuration with this:
esphome:
name: living-room-sensor
friendly_name: Living Room Sensor
esp32:
board: esp32dev
# WiFi connection
wifi:
ssid: "YourNetworkName"
password: "YourPassword"
# Fallback hotspot in case WiFi fails
ap:
ssid: "Living-Room-Sensor"
password: "fallback123"
# Enable Home Assistant API
api:
encryption:
key: "auto-generated-key-here"
# Enable OTA updates
ota:
- platform: esphome
password: "auto-generated-password"
# Enable logging
logger:
# DHT22 temperature and humidity sensor
sensor:
- platform: dht
pin: GPIO4
model: DHT22
temperature:
name: "Temperature"
unit_of_measurement: "°C"
accuracy_decimals: 1
humidity:
name: "Humidity"
unit_of_measurement: "%"
accuracy_decimals: 1
update_interval: 30s
# LED as a controllable light
light:
- platform: binary
name: "Status LED"
output: led_output
output:
- platform: gpio
id: led_output
pin: GPIO2Security note: The
apiencryption key andotapassword are automatically generated when you create the device. Keep them as-is -- they secure communication between the ESP32 and Home Assistant.
🔗Step 3: Flash the Firmware
- Connect your ESP32 to your computer via USB.
- In the ESPHome dashboard, click the three-dot menu on your device and select Install.
- Choose Plug into this computer (for the first flash).
- Select the correct serial port.
- Wait for the compilation and upload to complete.
The first flash must be done over USB. After that, you can flash wirelessly (OTA) -- just select Wirelessly instead of Plug into this computer.
🔗Step 4: See It in Home Assistant
After flashing, the ESP32 will connect to your WiFi and announce itself to Home Assistant.
- In Home Assistant, go to Settings > Devices & Services.
- You should see a notification that a new ESPHome device was discovered.
- Click Configure and enter the API encryption key if prompted.
- The device and its entities (temperature, humidity, LED) will appear automatically.
You can now see the temperature and humidity on your dashboard, and toggle the LED from the Home Assistant interface.
🔗YAML Configuration Explained
ESPHome's YAML structure is straightforward. Every configuration file has these core sections:
# Identity
esphome:
name: device-name # Unique name (used as hostname)
friendly_name: My Device # Display name in Home Assistant
# Hardware
esp32:
board: esp32dev # Board type (esp32dev works for most DevKit boards)
# Network
wifi:
ssid: "..."
password: "..."
# Home Assistant connection
api:
encryption:
key: "..."
# Over-the-air updates
ota:
- platform: esphome
# Serial logging
logger:
# Components (sensors, lights, switches, etc.)
sensor:
- platform: ...
light:
- platform: ...The sensor, light, switch, and binary_sensor sections are where you define your hardware components. Each platform has its own set of options -- the ESPHome documentation lists them all.
🔗More YAML Examples
🔗Binary Sensor (Push Button)
A physical button connected between GPIO 14 and GND, exposed to Home Assistant as a binary sensor:
binary_sensor:
- platform: gpio
pin:
number: GPIO14
mode: INPUT_PULLUP
inverted: true
name: "Desk Button"
device_class: none
filters:
- delayed_on: 50ms # Debounce
- delayed_off: 50msThe INPUT_PULLUP mode enables the ESP32's internal pull-up resistor, so you only need a button between the GPIO pin and GND -- no external resistor required. The inverted: true setting means pressing the button (pulling the pin LOW) registers as "on."
🔗Switch (Relay Control)
Control a relay module connected to GPIO 26:
switch:
- platform: gpio
pin: GPIO26
name: "Garden Pump"
icon: "mdi:water-pump"
restore_mode: ALWAYS_OFF # Default to off after rebootThe restore_mode option controls what happens when the ESP32 reboots. ALWAYS_OFF ensures the relay does not accidentally turn on after a power outage.
🔗PWM Light (Dimmable LED)
A dimmable LED using PWM on GPIO 16:
output:
- platform: ledc
pin: GPIO16
id: pwm_led
frequency: 1000Hz
light:
- platform: monochromatic
name: "Desk Lamp"
output: pwm_led
gamma_correct: 2.8The ledc platform uses the ESP32's hardware LED Control (LEDC) peripheral for smooth PWM output. The gamma_correct value adjusts the brightness curve so that "50% brightness" looks like 50% brightness to your eyes (LEDs are not linear).
🔗I2C Sensor (BME280)
A BME280 environment sensor connected via I2C:
i2c:
sda: GPIO21
scl: GPIO22
scan: true
sensor:
- platform: bme280_i2c
address: 0x76
temperature:
name: "Temperature"
oversampling: 16x
humidity:
name: "Humidity"
pressure:
name: "Pressure"
update_interval: 60sNotice that you do not need to install libraries or write initialization code. ESPHome handles all of that -- you just specify the platform, pin, and desired settings.
🔗WiFi Signal Strength
ESPHome can also expose diagnostic information:
sensor:
- platform: wifi_signal
name: "WiFi Signal"
update_interval: 60s
- platform: uptime
name: "Uptime"
button:
- platform: restart
name: "Restart"This gives you the WiFi signal strength, device uptime, and a restart button -- all visible in Home Assistant. Very useful for monitoring device health.
🔗OTA Updates
After the initial USB flash, you never need to physically access the device again. ESPHome supports Over-The-Air (OTA) updates:
- Edit the YAML configuration.
- Click Install > Wirelessly.
- ESPHome compiles the new firmware and uploads it to the ESP32 over WiFi.
The update process takes about 30-60 seconds. The device briefly disconnects, installs the new firmware, reboots, and reconnects to Home Assistant automatically.
Fallback hotspot: If the ESP32 cannot connect to your WiFi (wrong password, router change), it creates its own WiFi access point using the
apcredentials from your config. Connect to it and navigate to192.168.4.1to update the WiFi settings.
🔗Viewing Logs
Real-time device logs are invaluable for debugging. You can view them in two ways:
- ESPHome dashboard -- click Logs on the device card. Works wirelessly.
- USB serial -- click Logs and select the serial port. Useful if WiFi is not working.
Logs show sensor readings, WiFi connection status, API connections, and any errors:
[14:32:15][D][dht:048]: Got Temperature=23.4°C Humidity=51.2%
[14:32:15][D][sensor:094]: 'Temperature': Sending state 23.40000 °C
[14:32:15][D][sensor:094]: 'Humidity': Sending state 51.20000 %🔗ESPHome vs. Arduino: When to Use Which
Both ESPHome and Arduino (with MQTT) are valid ways to connect ESP32 devices to Home Assistant. Here is when to choose each:
| ESPHome | Arduino + MQTT | |
|---|---|---|
| Best for | Standard sensors, switches, lights | Custom logic, complex calculations |
| Programming | YAML (no code) | C++ |
| Learning curve | Low | Moderate |
| Setup speed | Fast | Slower |
| Flexibility | High (1,800+ components) | Unlimited |
| Custom logic | Limited (lambdas for simple C++) | Full control |
| HA connection | Native API (no broker needed) | MQTT (needs Mosquitto) |
| OTA updates | Built-in | Must implement yourself |
| Logging | Built-in web viewer | Serial or custom MQTT logging |
Choose ESPHome when:
- You want a temperature sensor, a switch, or a light with minimal effort
- You prefer configuration over programming
- You want automatic OTA updates and built-in diagnostics
- You are new to ESP32 and just want things to work
Choose Arduino + MQTT when:
- You need complex calculations or custom algorithms
- You want to learn how things work at a lower level
- You need features not supported by ESPHome components
- You are connecting to platforms other than Home Assistant
- You enjoy writing code
You can mix both. Many home automation setups use ESPHome for simple sensor nodes and Arduino-coded devices for more complex projects. Home Assistant does not care how the device communicates -- both ESPHome and MQTT devices appear as entities on the same dashboard.
🔗Lambdas: Adding Custom Code to ESPHome
ESPHome is not entirely code-free. For situations that require a bit of custom logic, you can use lambdas -- small inline C++ snippets within your YAML:
sensor:
- platform: adc
pin: GPIO34
name: "Battery Voltage"
update_interval: 60s
attenuation: 11db
filters:
- multiply: 2.0 # Voltage divider ratio
- lambda: |-
if (x < 3.3) {
return 0.0; # Battery empty
} else if (x > 4.2) {
return 100.0; # Battery full
}
// Linear interpolation between 3.3V and 4.2V
return (x - 3.3) / (4.2 - 3.3) * 100.0;
unit_of_measurement: "%"
accuracy_decimals: 0Lambdas let you handle edge cases without leaving the ESPHome ecosystem. However, if your custom logic grows beyond a few lines, Arduino + MQTT is probably a better fit.
🔗Secrets Management
Avoid hardcoding WiFi passwords and API keys in your YAML files. ESPHome supports a secrets.yaml file:
secrets.yaml:
wifi_ssid: "YourNetworkName"
wifi_password: "YourPassword"
api_key: "your-encryption-key"
ota_password: "your-ota-password"device.yaml:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
encryption:
key: !secret api_keyThis way, you can share or version-control your device configs without exposing credentials.
🔗Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Device not discovered in HA | mDNS issues or different subnet | Check that HA and ESP32 are on the same network. Try adding the device manually by IP. |
| Compilation fails | YAML syntax error | Check indentation. YAML is sensitive to spaces (no tabs). |
| Cannot flash over USB | Wrong serial port or driver issue | Try a different USB cable (data cables, not charge-only). Install CP2102 or CH340 drivers. |
| OTA update fails | Device unreachable | Check WiFi signal. Move the device closer to the router during update. |
| Sensor reads wrong values | Wiring issue or wrong GPIO | Double-check connections. Verify the GPIO number matches your board. |
| "Already connected" error | Another ESPHome dashboard instance | Only one dashboard can connect to a device at a time. Close other tabs. |
🔗What is Next?
If ESPHome covers your needs, skip ahead to building a custom sensor node for a complete end-to-end project. If you prefer writing your own Arduino code and using MQTT, the next article shows you how to connect an Arduino-coded ESP32 to Home Assistant using MQTT auto-discovery.