ESPHome and Home Assistant: Custom Sensors Guide 2026
This post may contain affiliate links. As an Amazon Associate we earn from qualifying purchases. Disclosure.
Arduino sketches are a fine way to build smart sensors if you enjoy C++ and manual library management. ESPHome replaces all of that with a short YAML file that compiles into native firmware for ESP32 and ESP8266 boards, then talks to Home Assistant over a local API.
Arduino sketches are a fine way to build smart sensors if you enjoy C++ and manual library management. ESPHome replaces all of that with a short YAML file that compiles into native firmware for ESP32 and ESP8266 boards. This guide covers what ESPHome is, when to pick it over Arduino, and the workflow from first flash to a sensor in Home Assistant.
A note on sourcing: this guide is built from the ESPHome and Home Assistant documentation rather than from my own fleet of ESPHome devices, so the numbers below come from those docs and I've left out any "it ran for months" claims.
What ESPHome Actually Does
ESPHome takes a YAML configuration describing the sensors, actuators, and behaviour you want, and produces firmware that implements it. It targets ESP32 and ESP8266 and, per its home page, also the Raspberry Pi RP2040/RP2350 and several other chips. The framework handles WiFi connection, OTA updates, sensor reading, and the Home Assistant API connection for you.
The contrast with raw Arduino is sharp. An Arduino sketch for a DHT22 temperature sensor reporting to Home Assistant over MQTT needs include directives, WiFi setup, an MQTT client, a reading loop, and JSON formatting. The same sensor in ESPHome is a handful of YAML lines naming the platform, the pin, and the entity names.
The official ESPHome documentation describes "hundreds of components", each with documented example snippets. The catalogue covers a lot of the cheap sensors you find on AliExpress, plus more specialised ones such as mmWave presence, particulate matter, and NDIR CO2 sensors.

The Five-Step ESPHome Workflow
The standard workflow is the same on every project:
The first step is writing a YAML file describing the device. ESPHome's structure encourages readability: each section (esphome, esp32/esp8266, wifi, api, sensor, switch, light) has a clear purpose.
The second step is compiling. Run "esphome compile" or click Install in the ESPHome dashboard, and the YAML is compiled into a firmware binary. The first compile is the slow one because the toolchain has to download; later compiles reuse the cache.
The third step is flashing. The first time, connect the board via USB and run "esphome upload" with the serial device. After that, updates happen wirelessly through OTA. The dashboard's Install button handles both first-time and OTA flashing.
The fourth step is waiting for the device to boot and join WiFi. The dashboard shows live status through its Logs view.
The fifth step is using the device. Home Assistant can auto-discover ESPHome devices, and they appear as Discovered under Settings > Devices & services. Confirm, and the sensor entities show up in Home Assistant ready for automations.

A Minimal ESPHome Config
Here is a complete temperature and humidity node, adapted from the example in the ESPHome DHT documentation:
esphome:
name: utility-room-sensor
friendly_name: Utility Room Temp
esp8266:
board: d1_mini
wifi:
ssid: "..."
password: "..."
ap:
ssid: "Utility Room Fallback"
password: "..."
captive_portal:
api:
encryption:
key: "..."
ota:
- platform: esphome
logger:
level: WARN
sensor:
- platform: dht
pin: D2
model: DHT22
temperature:
name: Utility Room Temperature
filters:
- filter_out: nan
humidity:
name: Utility Room Humidity
filters:
- filter_out: nan
update_interval: 60s
binary_sensor:
- platform: status
name: Utility Room Sensor Online
The sensor reports temperature and humidity every 60 seconds (the DHT component's default), supports OTA updates, exposes an online/offline binary sensor, and falls back to its own hotspot if WiFi disappears. The ESPHome docs mention filter_out: nan for discarding failed reads, which keeps a momentary read error out of your history. One wiring note from the same page: the DHT22 data line needs a pull-up resistor of roughly 4.7 kOhm to 3.3V, and on ESP8266 you should disable the internal pull-up if your module already has one.
When ESPHome Beats Arduino IDE
Five scenarios where ESPHome wins decisively:
The first is when you have more than a few custom sensors. Maintaining three Arduino sketches with separate WiFi/MQTT logic is annoying; maintaining thirty is worse. ESPHome centralises that boilerplate.
The second is when you need OTA updates. Arduino IDE supports OTA but the setup is fiddly. ESPHome enables it with a short block in the YAML config.
The third is when you want consistent behaviour across devices. Every ESPHome device reports through the same API and shows up in Home Assistant the same way. Sketches written months apart tend to behave subtly differently.
The fourth is when you don't want to manage Arduino libraries. ESPHome pulls in the libraries a component needs, so you rarely deal with version drift yourself.
The fifth is when you want declarative documentation. The YAML file is itself the documentation for what the device does, and a 40-line YAML is easier to reread in six months than a long sketch.
When Arduino IDE Still Wins
For honesty, three scenarios where Arduino IDE remains the better choice:
Very tight memory or timing requirements. ESPHome adds overhead compared to a hand-tuned Arduino sketch. For projects where you need every byte of flash or sub-millisecond timing, hand-coded Arduino still wins.
Sensor types ESPHome does not yet support. The catalogue is large but not infinite. If you have a niche sensor that lacks ESPHome support, an Arduino sketch with the vendor library is the fastest path until someone contributes ESPHome support.
Complex custom behaviour. ESPHome supports lambda expressions for custom logic, but once a lambda grows past a dozen or so lines the YAML gets harder to read than the equivalent Arduino C++. For genuinely complex behaviour, drop into Arduino.
Common Patterns Worth Knowing
Three patterns that show up in many ESPHome configs:
The filter_out: nan filter, shown above, handles sensor disconnections gracefully. Without it, a momentary read failure can push "NaN" into Home Assistant and upset downstream automations.
The deep sleep pattern for battery-powered devices uses the deep_sleep component with a run_duration and a sleep_duration. The docs flag one hardware catch: on an ESP8266, GPIO16 must be wired to the RST pin or the board won't wake up again, and boards with an onboard USB chip can misbehave when powered over USB. The docs don't promise a battery life figure, and the result depends heavily on how often you wake and how long WiFi takes to connect, so measure your own before trusting a number.
The captive portal fallback gives the device a recovery path if WiFi credentials change. After a minute of failed WiFi connection attempts the device starts its own hotspot, and you can connect from a phone to update credentials without USB. It needs the ap: block shown in the config above.
Debugging ESPHome Devices
Three debugging approaches that work consistently:
Serial logging via USB shows live device behaviour. Connect the board, run "esphome logs" with your config file, and the device's log stream appears in the terminal. Useful for diagnosing boot loops, sensor read failures, or WiFi connection issues.
Wireless logging via the ESPHome dashboard works after the first flash. Click the device, then Logs. The Home Assistant docs describe the same LOGS button in the Device Builder add-on. It's faster than reconnecting USB every time.
Home Assistant Developer Tools shows the current state of every ESPHome entity. If a sensor reports in the device logs but doesn't appear in HA, the issue is the API connection rather than the sensor itself. Reload the ESPHome integration in HA before reflashing the device.
What to Build First
For someone with one ESP8266 D1 Mini in a drawer, three projects worth tackling in order:
A temperature and humidity sensor with a DHT22. The classic first ESPHome project, and the config above is nearly all you need. It's cheap and quick enough that you'll find out whether you enjoy the workflow in an evening.
A motion sensor with a PIR module. Slightly more complex because many PIR modules have trim pots that need adjusting. It pays back in motion-triggered hallway light automations.
A smart plug with a relay module wired to a wall socket. Important: this is mains voltage, use a proper enclosure or buy a pre-built smart plug and reflash it with ESPHome rather than wiring relays yourself. The reflash path is safer and cheaper than the DIY relay approach for most readers.
The Home Assistant ESPHome integration docs cover pairing edge cases such as encryption keys and name conflicts. Most installs never need to look beyond the dashboard UI for setup. After three or four projects the ESPHome workflow becomes routine, and writing custom sensors stops feeling like a project and starts feeling like normal smart home work.
Cost Comparison Versus Commercial Sensors
A DIY ESPHome temperature node is an ESP8266 or ESP32 board, a DHT22 or similar sensor, wires, and ideally an enclosure. Prices move around and vary by seller, so check current listings, but the pattern is stable: a DIY temperature node costs about as much as a basic commercial Zigbee temperature sensor from Aqara or Sonoff, and a cheap Tuya or Xiaomi WiFi sensor can undercut it.
On a per-sensor basis, DIY ESPHome saves little or nothing once you count your time. Where DIY wins is the long tail: a probe built for one specific appliance, a soil moisture sensor for a specific plant, a custom multi-sensor combining temperature plus light plus motion in one enclosure. Commercial equivalents for these niche cases either do not exist or cost a lot more. A watering controller is the textbook example, and the ESP32 irrigation controller build shows the ESPHome side of one.
The rule of thumb: buy commercial for standard sensors (door contacts, basic temperature, motion) where market pricing is competitive, and use ESPHome for the specialised ones where you control the form factor, the protocol, and the data ownership. The hybrid approach keeps the smart home affordable while letting you build the parts no vendor sells.
Migration Path From Arduino to ESPHome
If you already have a few Arduino sensors running and want to migrate to ESPHome, the path is gradual rather than wholesale. Pick the most-recently broken Arduino device and rebuild it in ESPHome; run it for a week and watch the behaviour. Then migrate the next one.
Treat it as a slow improvement project rather than a forced rewrite. The payoff is a lower maintenance burden, a consistent OTA workflow, and unified logs. One caveat once you're all-in on ESPHome: each release can shift config syntax or deprecate options (the Home Assistant docs already call the legacy API password deprecated in favour of encryption keys), so skim the release notes before you update a fleet of devices.
Frequently Asked Questions
What is ESPHome and how does it differ from Arduino code?
ESPHome is a YAML-based firmware framework that compiles into native C++ for ESP32 and ESP8266 boards. You describe sensors and behaviour in declarative YAML; ESPHome generates and compiles the equivalent C++ code automatically. Arduino IDE requires you to write C++ by hand, manage libraries, and handle WiFi/MQTT connection logic. The difference per project is large: a basic sensor is a few lines of YAML instead of a sketch with its own WiFi and reconnect logic.
Do I need an Arduino background to use ESPHome?
No. ESPHome was designed for people who want smart sensors without learning C++. Knowing basic electronics (wiring sensors to GPIO pins) helps but is not required for most projects. The official ESPHome documentation includes ready-to-copy YAML for dozens of common sensor types including DHT22, PIR, magnetic reed switches, soil moisture, lux meters, mmWave radar, and capacitive touch.
Can I update ESPHome devices wirelessly after the first flash?
Yes. The first flash requires USB connection to give the device WiFi credentials. After that, all updates happen over-the-air via WiFi. Edit the YAML in the ESPHome dashboard, click Install, the dashboard compiles a new binary and sends it to the device automatically, then the board reboots into the new firmware. No more disconnecting hardware to update.
How does ESPHome connect to Home Assistant?
Through the native ESPHome API, an encrypted persistent connection between the device and Home Assistant Core, using a Noise pre-shared key. Because the connection is persistent, state changes are pushed immediately instead of polled. Home Assistant can auto-discover ESPHome devices on the network and shows them as Discovered, so adding one takes a confirmation in the UI. MQTT remains optional.
How many ESPHome devices can one Home Assistant install handle?
There's no documented hard limit. The native API keeps one persistent connection per device, and the ESPHome integration is used by roughly 27% of active Home Assistant installations according to the Home Assistant docs, so large fleets are normal. In practice the limit you meet first is usually your WiFi network, not Home Assistant itself.
Sources & References
- ESPHome official documentation esphome.io
- Home Assistant - ESPHome integration home-assistant.io