MQTT is the most popular way to connect an ESP32 to Home Assistant, but it is not the only way, and for many people it is not the best. It needs a broker, credentials, topic design, discovery messages and firmware you write and maintain yourself. If you only want a temperature sensor or a relay in Home Assistant, there are simpler routes.
This guide compares the four realistic alternatives, shows working configuration for each and tells you honestly when to pick which. In order of how much work they save you: ESPHome (no firmware to write at all), REST (Home Assistant polls your ESP32), webhooks (your ESP32 pushes events to Home Assistant) and the Home Assistant REST API (your ESP32 writes states directly). If you are not sure MQTT is wrong for you, the MQTT sensor guide and smart switch guide cover that path.
Which Method Should You Use?
| Method | Effort | Best for | Needs custom firmware? | Live updates? |
|---|---|---|---|---|
| ESPHome (native API) | Lowest | Sensors, switches, lights, most hobby devices | No, YAML only | Yes, pushed instantly |
| REST polling | Low | A device you already built with an HTTP API | Yes (an HTTP server) | Delayed by the polling interval |
| Webhooks | Low | Events: doorbell, motion, a button press | Yes (an HTTP POST) | Yes, on demand |
| HA REST API | Medium | Quick prototypes pushing a value | Yes (HTTP with a token) | Yes, but fragile |
| MQTT (for comparison) | Medium | Many devices, other systems consuming data | Yes | Yes, pushed |
Short answer: use ESPHome unless you have a reason not to. It gives you a proper device in Home Assistant, over-the-air updates, encryption and automatic reconnection with almost no code. Use the other methods when you already have firmware, need to integrate with something unusual, or want to understand how it works underneath.
Method 1: ESPHome (Recommended)
ESPHome turns a short YAML file into complete ESP32 firmware, compiles it and flashes it. Home Assistant discovers the device on its own and talks to it through an encrypted native API, a direct connection with no broker in between. It handles WiFi reconnection, OTA updates, fallback hotspot and logging for you.
Setup
- In Home Assistant, install the ESPHome Device Builder add-on (named an app in the newest versions) and open its web UI.
- Click New Device, give it a name and choose ESP32. The wizard creates a config with WiFi credentials and an encryption key.
- For the first flash, plug the ESP32 into the computer you are browsing from and use the Install → Plug into this computer option. This works in Chrome or Edge over USB. After that, updates are wireless.
A temperature sensor and a relay in one file
esphome:
name: workshop-node
esp32:
board: esp32dev
logger:
api:
encryption:
key: "PASTE_THE_KEY_THE_WIZARD_CREATED"
ota:
- platform: esphome
password: "choose-an-ota-password"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Workshop Node Fallback"
password: "fallback-pass"
sensor:
- platform: dht
pin: GPIO4
model: DHT22
temperature:
name: "Workshop Temperature"
humidity:
name: "Workshop Humidity"
update_interval: 30s
switch:
- platform: gpio
pin:
number: GPIO26
inverted: true # active-LOW relay module
name: "Workshop Relay"
restore_mode: RESTORE_DEFAULT_OFF
binary_sensor:
- platform: gpio
pin:
number: GPIO27
mode: INPUT_PULLUP
inverted: true
name: "Workshop Button"
on_press:
then:
- switch.toggle: workshop_relay
Give the switch an id: workshop_relay so the button action can reference it. Install, and within a minute Home Assistant shows a notification that a new ESPHome device was discovered. Click Configure, enter the encryption key if asked, and every entity appears: temperature, humidity, the relay and the button.
Why it is worth using
- No firmware to maintain. Add a sensor by adding five lines of YAML.
- Instant, encrypted push updates with no broker.
- Wireless updates. Edit the YAML, press Install, done.
- If the WiFi fails, the device raises its own fallback hotspot so you can fix credentials.
- Local logic keeps working. The button toggles the relay even if Home Assistant is offline, because the action runs on the ESP32 itself.
The ESPHome pin names (GPIO4, GPIO26) follow the same rules as everywhere else on the ESP32. Check the ESP32 pinout guide before choosing pins.
Method 2: Home Assistant Polls Your ESP32 Over REST
If you already built an ESP32 that serves JSON (for example from the REST API tutorial), Home Assistant can read it on a timer without any custom component.
Add to configuration.yaml:
rest:
- resource: http://192.168.1.184/api/v1/sensor
scan_interval: 30
sensor:
- name: "ESP32 Chip Temperature"
value_template: "{{ value_json.chip_temperature_c }}"
unit_of_measurement: "°C"
device_class: temperature
To control a relay or LED, use a REST switch:
switch:
- platform: rest
name: "ESP32 LED"
resource: http://192.168.1.184/api/v1/led
method: post
headers:
Content-Type: application/json
X-API-Key: "your-api-key"
body_on: '{"state":"on"}'
body_off: '{"state":"off"}'
is_on_template: "{{ value_json.state == 'on' }}"
Restart Home Assistant (or reload the YAML configuration) and the entities appear.
Trade-offs: HTTP polling is simple but not instant. The state can be up to scan_interval seconds stale, and if someone toggles the physical button, Home Assistant only finds out at the next poll. Give the ESP32 a fixed address (static IP guide) or the URL breaks whenever its address changes. Each entity you define also costs a request, so keep intervals sensible.
Method 3: Webhooks, the ESP32 Pushes Events to Home Assistant
A webhook flips the direction. Home Assistant listens at a secret URL, and the ESP32 calls it when something happens. It suits events such as a doorbell, a motion trigger or a button press, rather than continuous readings.
In Home Assistant, create an automation with a webhook trigger:
alias: Doorbell pressed
trigger:
- platform: webhook
webhook_id: "doorbell-8f3a2b7c91d04e5a"
allowed_methods:
- POST
local_only: true
action:
- service: notify.notify
data:
title: "Doorbell"
message: "Someone is at the door"
mode: single
Make the webhook_id long and random. It acts as the password. local_only: true restricts it to your home network.
On the ESP32, send a POST when the event happens:
#include <WiFi.h>
#include <HTTPClient.h>
const char* HA_WEBHOOK =
"http://192.168.1.10:8123/api/webhook/doorbell-8f3a2b7c91d04e5a";
void sendDoorbell() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(HA_WEBHOOK);
http.addHeader("Content-Type", "application/json");
int code = http.POST("{\"source\":\"front-door\"}");
Serial.printf("Webhook status: %d\n", code);
http.end();
}
You can read the posted data inside the automation through trigger.json, for example {{ trigger.json.source }}. The mechanics of the request are explained in the HTTP GET and POST guide.
Trade-offs: webhooks are perfect for fire-and-forget events but give Home Assistant no device, no availability tracking and no state. If the ESP32 is offline, Home Assistant cannot tell.
Method 4: Writing States Through the Home Assistant REST API
Home Assistant also has its own REST API. With a long-lived access token (create one on your profile page, at the bottom), the ESP32 can set a state directly:
#include <WiFi.h>
#include <HTTPClient.h>
const char* HA_URL = "http://192.168.1.10:8123/api/states/sensor.esp32_garage_temp";
const char* HA_TOKEN = "YOUR_LONG_LIVED_ACCESS_TOKEN";
void pushTemperature(float t) {
HTTPClient http;
http.begin(HA_URL);
http.addHeader("Authorization", String("Bearer ") + HA_TOKEN);
http.addHeader("Content-Type", "application/json");
String body = "{\"state\":\"" + String(t, 1) +
"\",\"attributes\":{\"unit_of_measurement\":\"°C\"," +
"\"device_class\":\"temperature\",\"friendly_name\":\"Garage Temperature\"}}";
int code = http.POST(body);
Serial.printf("HA API status: %d\n", code);
http.end();
}
This creates sensor.esp32_garage_temp instantly. It is handy for quick experiments, but understand the limits before building on it:
- Entities created this way have no unique ID, so they cannot be edited in the Home Assistant UI, and they disappear after a restart until the ESP32 posts again.
- There is no device, no availability handling and no history guarantee.
- A long-lived token gives broad access. If it ever leaks, anyone can control your whole house. Never put it in code you publish.
For anything permanent, ESPHome or MQTT Discovery is a better foundation.
Other Options Worth Knowing
- Matter. The newer Arduino-ESP32 core includes Matter support on chips such as the ESP32-C3, S3 and C6, and Home Assistant can add Matter devices. It is the future-proof option but still heavier to set up than ESPHome.
- Zigbee. The ESP32-H2 and C6 have a Zigbee-capable radio, so they can act as Zigbee end devices that work with Home Assistant's Zigbee integration.
- Bluetooth. Home Assistant can read BLE sensors directly, and ESPHome can turn an ESP32 into a Bluetooth proxy to extend that range around the house.
Troubleshooting
ESPHome device is not discovered. Home Assistant and the ESP32 must be on the same network and subnet, and mDNS must not be blocked by your router or a VLAN. You can always add the device manually by IP address under the ESPHome integration.
ESPHome says the encryption key is invalid. The key in the YAML and the one Home Assistant stores must match. Re-enter the key from the device config.
First flash fails over USB. Use a data USB cable, Chrome or Edge, and hold the BOOT button when the browser starts the connection.
REST sensor shows unavailable. Open the resource URL in a browser from the Home Assistant machine. If it fails, the ESP32 is unreachable, the address changed or the JSON key in value_template is wrong.
Webhook does nothing. The webhook_id must match exactly, the method must be allowed, and local_only blocks requests from outside the home network. Check the Settings → System → Logs page in Home Assistant.
HA API returns 401. The token is wrong or missing the Bearer prefix.
For general connectivity trouble, see the WiFi troubleshooting guide.
Frequently Asked Questions
Is ESPHome better than MQTT? For a single ESP32 doing normal home tasks, usually yes: less work, native encryption and wireless updates. MQTT wins when many different systems must consume the same data, or when you want full control of custom firmware.
Can I use ESPHome and MQTT together? Yes. ESPHome can publish to MQTT as well, in place of or alongside the native API.
Do I lose the ability to write my own code? No. ESPHome supports custom C++ lambdas and external components for anything the built-in options do not cover.
Will Home Assistant work if the internet is down? Yes, all four methods are local.
Can the same ESP32 serve a web page and talk to Home Assistant? ESPHome includes an optional web_server: component, and your own firmware can run a web server next to any of these methods.
Where next? Compare with the MQTT approach in the temperature sensor and smart switch guides.