ESPHome Raspberry Pi: Complete Dashboard Setup and Hardware Guide

Esphome dashboard on raspberry pi

ESPHome Raspberry Pi turns a Pi 4 into a central dashboard for building, flashing, and managing firmware on ESP32 and ESP8266 devices. You define each device behaviour in a YAML file: sensors, GPIO outputs, Wi-Fi credentials, OTA settings. ESPHome ESPHome compiles and flashes the firmware directly. Once a device is flashed, all future updates go over Wi-Fi. This guide covers installing ESPHome on Bookworm, creating your first device YAML, wiring common sensors, configuring GPIO outputs, OTA updates, and Home Assistant integration.

Last tested: Raspberry Pi OS Bookworm Lite 64-bit | April 22, 2026 | Raspberry Pi 4 Model B (4GB) | ESPHome 2024.11 | ESP32-WROOM-32 + NodeMCU v3 (ESP8266)

Key Takeaways

  • The first flash must be done over USB. After that, all firmware updates can be delivered over Wi-Fi via OTA as long as the device has a reachable IP address. Assign a static IP in the YAML or via router DHCP reservation to prevent OTA from failing after router reboots.
  • Some ESP8266 GPIO pins affect boot mode. GPIO0 must be HIGH at boot, GPIO2 must be HIGH, and GPIO15 must be LOW. Connecting a sensor or relay to these pins without accounting for their boot state can prevent the device from starting.
  • Install ESPHome with pip install esphome --break-system-packages on Bookworm, not sudo pip3 install esphome. The latter installs into the system Python environment which Bookworm protects by default, producing a “externally managed environment” error.

ESPHome Raspberry Pi: How It Works

ESPHome is a framework for ESP32 and ESP8266 microcontrollers. You describe what a device should do in a YAML configuration file: which sensors are attached, which GPIO pins control outputs, how often to report readings, how to connect to Wi-Fi. ESPHome compiles that into C++ firmware and flashes it to the device. The Pi runs the ESPHome dashboard, a web interface on port 6052 where you manage all device configurations, trigger builds, and monitor live device logs.

After initial USB flashing, devices connect back to the Pi over Wi-Fi using the ESPHome native API. From the dashboard you can push firmware updates wirelessly, view real-time sensor readings, and check connectivity status for every device on the network.

FeatureESPHomeTasmotaArduino IDE
Configuration methodYAML filesWeb UI + rulesC++ code
Home Assistant integrationNative API, automatic discoveryMQTTManual
OTA updatesBuilt-in, dashboard-managedBuilt-inManual
Custom sensor supportExtensive component libraryLimitedFull
Skill requiredYAML editingWeb UIC++ programming

Installation on Raspberry Pi OS Bookworm

Flash Raspberry Pi OS Bookworm Lite 64-bit using Raspberry Pi Imager. In the advanced settings, set hostname, enable SSH, and configure credentials. After first boot:

sudo apt update && sudo apt full-upgrade -y
sudo apt install python3-pip python3-venv -y

Install ESPHome into a virtual environment to keep it isolated from the system Python:

python3 -m venv ~/esphome-venv
source ~/esphome-venv/bin/activate
pip install esphome
esphome version

Alternatively, install directly with the Bookworm-compatible flag:

pip install esphome --break-system-packages
esphome version

Create the config directory and start the dashboard:

mkdir -p ~/esphome/config
esphome dashboard ~/esphome/config/

Navigate to http://<pi-ip>:6052 in a browser. The dashboard loads with an option to create a new device. Set a dashboard username and password when prompted on first access.

To run the dashboard as a systemd service that starts at boot, create /etc/systemd/system/esphome-dashboard.service:

[Unit]
Description=ESPHome Dashboard
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/esphome
ExecStart=/home/pi/esphome-venv/bin/esphome dashboard config/
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now esphome-dashboard
sudo systemctl status esphome-dashboard

Expected result: systemctl status esphome-dashboard shows the service active. The dashboard is accessible at http://<pi-ip>:6052 after a reboot without manual intervention.

ESPHome Raspberry Pi ecosystem diagram showing Pi dashboard compiling firmware to ESP devices connecting to Home Assistant and MQTT broker

Creating a Device Configuration

From the dashboard, click New Device. Enter a device name (lowercase, no spaces), select the platform (ESP32 or ESP8266), and enter Wi-Fi credentials. ESPHome generates a starter YAML file. A minimal working config for a NodeMCU (ESP8266) with a DHT22 temperature and humidity sensor:

esphome:
  name: livingroom-sensor

esp8266:
  board: nodemcuv2

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.150
    gateway: 192.168.1.1
    subnet: 255.255.255.0

logger:

api:
  encryption:
    key: !secret api_encryption_key

ota:
  password: !secret ota_password

sensor:
  - platform: dht
    pin: GPIO14
    model: DHT22
    temperature:
      name: "Living Room Temperature"
      device_class: temperature
      state_class: measurement
    humidity:
      name: "Living Room Humidity"
      device_class: humidity
      state_class: measurement
    update_interval: 60s

The !secret references pull values from a secrets.yaml file in the same directory, keeping credentials out of device configs:

# secrets.yaml
wifi_ssid: "YourNetworkName"
wifi_password: "YourPassword"
api_encryption_key: "base64-encoded-32-byte-key"
ota_password: "strong-ota-password"

Validate the config before flashing:

esphome config ~/esphome/config/livingroom-sensor.yaml

Expected result: esphome config returns no errors. Any YAML formatting errors, unknown component names, or missing required fields are reported with line numbers before a flash attempt is made.

NodeMCU (ESP8266) GPIO pin mapping

The NodeMCU board labels pins D0 through D8, but ESPHome uses GPIO numbers. Reference:

Board labelGPIO numberBoot note
D0GPIO16No PWM, no interrupt
D1GPIO5Safe general use
D2GPIO4Safe general use
D3GPIO0Must be HIGH at boot
D4GPIO2Must be HIGH at boot, onboard LED
D5GPIO14Safe general use
D6GPIO12Safe general use
D7GPIO13Safe general use
D8GPIO15Must be LOW at boot

Wiring Common Sensors and Outputs

DHT22 temperature and humidity sensor

Wire VCC to 3.3V, GND to GND, and DATA to GPIO14 (D5). Place a 10k pull-up resistor between VCC and DATA for reliable readings. The sensor does not work reliably without the pull-up at 3.3V. Use GPIO numbers in the YAML config, not board labels.

PIR motion sensor (HC-SR501)

The HC-SR501 output pin pushes 3.3V on some modules and 5V on others. Check yours with a multimeter before connecting it to an ESP GPIO. A 5V signal on a 3.3V GPIO will damage the ESP. Use a voltage divider or level shifter if needed. Wire VCC to 5V, GND to GND, OUT to a safe GPIO.

binary_sensor:
  - platform: gpio
    pin: GPIO5
    name: "Motion Sensor"
    device_class: motion
    filters:
      - delayed_on: 50ms
      - delayed_off: 2s

Relay or LED output

For a relay or LED controlled via GPIO, define a switch component. The relay module draws its control signal from the GPIO pin. Never power the relay coil from the GPIO directly, use the module’s VCC/GND pins from a 5V supply:

switch:
  - platform: gpio
    pin: GPIO13
    id: relay_output
    name: "Relay Control"

Button input with action

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: true
    name: "Button"
    on_press:
      - switch.toggle: relay_output

INPUT_PULLUP keeps the pin HIGH until the button pulls it LOW. inverted: true means press = ON. The on_press action references the relay switch by its id.

I2C sensors (CCS811, BME280, SSD1306)

I2C sensors share SDA and SCL lines. On ESP8266, SDA is typically GPIO4 (D2) and SCL is GPIO5 (D1). On ESP32, you can assign any pins. Declare the I2C bus once at the top of the config:

i2c:
  sda: GPIO4
  scl: GPIO5
  scan: true

sensor:
  - platform: bme280_i2c
    temperature:
      name: "BME280 Temperature"
    pressure:
      name: "BME280 Pressure"
    humidity:
      name: "BME280 Humidity"
    address: 0x76
    update_interval: 30s

OTA Updates and Device Management

The first flash requires a USB connection between the Pi (or your computer) and the ESP device. After the device boots and connects to Wi-Fi, all subsequent firmware updates go over the network. From the dashboard, click Install on any device and choose Wirelessly. The dashboard compiles the firmware, transfers it to the device, and the device reboots into the new firmware automatically.

From the CLI:

# First flash (USB required)
esphome run ~/esphome/config/livingroom-sensor.yaml

# Subsequent OTA updates
esphome upload ~/esphome/config/livingroom-sensor.yaml

# Monitor live logs
esphome logs ~/esphome/config/livingroom-sensor.yaml

If OTA fails, the most common causes are: the device IP changed (fix with a static IP in the YAML or a DHCP reservation on the router), the OTA password does not match the one in secrets.yaml, or the device is not reachable from the Pi. Confirm with:

ping 192.168.1.150
esphome logs ~/esphome/config/livingroom-sensor.yaml --device 192.168.1.150

Expected result: esphome logs connects and streams sensor readings every 60 seconds. You see entries like [D][dht:048]: Got Temperature=22.4°C Humidity=47.8%. A device that connects to Wi-Fi but shows no sensor readings usually has a wiring problem or wrong GPIO number.

Log verbosity

Set the log level in the YAML logger: block. DEBUG is useful during development; reduce to WARN or ERROR in production to reduce log noise and serial overhead:

logger:
  level: DEBUG

Home Assistant Integration

When a device has the api: component in its YAML and Home Assistant is on the same network, Home Assistant auto-discovers the device and prompts to add it. No MQTT broker is needed for this path. The ESPHome native API is direct and encrypted. Accept the discovery notification in Home Assistant under Settings > Devices and Services > Discovered.

All entities defined in the YAML (sensors, switches, binary sensors) appear automatically in Home Assistant after pairing. Changes to YAML that add or rename entities are reflected in Home Assistant after the next OTA update and a Home Assistant page reload.

For setups where you want ESPHome devices to communicate via MQTT rather than the native API (for example, if Home Assistant is not running or you want to route messages through a Mosquitto broker), replace api: with an MQTT component:

mqtt:
  broker: 192.168.1.80
  username: sensor1
  password: !secret mqtt_password
  topic_prefix: esphome/livingroom-sensor

For the Mosquitto broker setup including TLS and ACL configuration, see Mosquitto MQTT Raspberry Pi. For Home Assistant on Pi, see Home Assistant Raspberry Pi.

Troubleshooting

Device fails to boot after flash

A device that reboots continuously after flashing usually has a GPIO conflict at boot. Review the GPIO pin mapping table. If you assigned GPIO0, GPIO2, or GPIO15 to a sensor or relay, the physical connection may be pulling that pin to the wrong state. Disconnect the sensor, reflash, and confirm the device boots cleanly before reconnecting.

esphome command not found

# If using venv
source ~/esphome-venv/bin/activate
esphome version

# If installed with --break-system-packages
which esphome
# If not found:
export PATH=$PATH:~/.local/bin

YAML validation errors

esphome config ~/esphome/config/livingroom-sensor.yaml

Run this before every flash. ESPHome reports the exact line and component causing the error. Common causes: indentation errors (YAML is whitespace-sensitive), wrong platform name (esp8266 not ESP8266), missing required fields, or referencing an id that does not exist.

No sensor readings in logs

Confirm wiring with a multimeter: VCC is at the correct voltage, GND is connected, and the data pin is connected to the GPIO number in the YAML (not the board label). For the DHT22, check the pull-up resistor is present. For I2C sensors, run scan: true in the i2c: block and check the log for detected addresses. A missing address means a wiring problem or wrong I2C address in the config.

Dashboard service not starting after reboot

journalctl -u esphome-dashboard -n 30

The most common cause is that the ExecStart path in the service file does not match the actual ESPHome binary location. If using a virtual environment, the path must point to the venv binary: /home/pi/esphome-venv/bin/esphome. Confirm with which esphome while the venv is active.

FAQ

Can ESPHome run on a Pi Zero 2 W?

Yes. The dashboard runs fine on a Pi Zero 2 W for a small number of devices. The limitation is compile time. Building firmware for an ESP32 takes 2-3 minutes on a Pi Zero 2 W versus under a minute on a Pi 4. For a network with more than 5-10 devices getting regular OTA updates, Pi 4 is the practical choice.

Does ESPHome work without Home Assistant?

Yes. ESPHome is independent of Home Assistant. You can use it with any MQTT broker, read sensor data from the native API with custom scripts, or simply log data locally. Home Assistant provides the most seamless integration but is not required.

Can I use ESP8266 and ESP32 devices together?

Yes. Each device has its own YAML config specifying its platform. The dashboard manages both simultaneously. ESP32 supports more GPIO pins, more ADC channels, Bluetooth, and faster processing. ESP8266 is smaller, cheaper, and adequate for simple sensor and relay work.

How do I add HTTPS to the ESPHome dashboard?

Put Caddy in front of the dashboard as a reverse proxy. ESPHome serves on port 6052 on the Pi. Caddy terminates TLS and proxies to it. See Caddy Reverse Proxy Raspberry Pi for the full setup. The Caddyfile entry is a single block pointing to localhost:6052.

What if a device is physically inaccessible and OTA fails?

If a bad firmware update breaks Wi-Fi connectivity and the device is physically unreachable, the only recovery option is serial flash. The ESPHome web flasher at web.esphome.io works in Chrome via WebSerial without installing anything. Download a known-good firmware binary from the dashboard (Install > Manual Download), then flash it via the web flasher using a USB cable. This recovers the device and re-enables OTA for future updates.

References


About the Author

Chuck Wilson has been programming and building with computers since the Tandy 1000 era. His professional background includes CAD drafting, manufacturing line programming, and custom computer design. He runs PidiyLab in retirement, documenting Raspberry Pi and homelab projects that he actually deploys and maintains on real hardware. Every article on this site reflects hands-on testing on specific hardware and OS versions, not theoretical walkthroughs.

Last tested hardware: Raspberry Pi 4 Model B (4GB), ESP32-WROOM-32, NodeMCU v3 (ESP8266), DHT22, HC-SR501. Last tested OS: Raspberry Pi OS Bookworm Lite 64-bit. ESPHome 2024.11.

Was this helpful?

Yes
No
Thanks for your feedback!