esphome
tested on simulator
| Tier | Tier 1 |
|---|---|
| Protocol | ESPHome native API over TCP, plaintext or Noise encrypted |
| Covers | ESP32, ESP8266, RP2040 and BK72xx boards running ESPHome, sensors, switches, lights, fans, numbers, selects and buttons defined in ESPHome YAML |
| Hazard default | low |
| Conformance | control |
| Tested with | native API simulator over a local TCP socket, driven by the real aioesphomeapi client |
Estimated reach. Every ESPHome node, hundreds of thousands of installs. ESPHome is the most common firmware for DIY ESP-based devices and is preinstalled on a growing set of commercial products under the Made for ESPHome program. Every node uses the same native API, and the driver maps the common entity types without per-device code.
The esphome driver connects to ESPHome devices over the native API through aioesphomeapi 46.22.0, MIT. Channels bind to entities by object id, buttons become actions, and describe() builds channels from the entity list.
Supports
| Entity | Channel | Type | Command |
|---|---|---|---|
| sensor | read | number, converted from unit_of_measurement, or string | none |
| text_sensor | read | string or enum | none |
| binary_sensor | read | bool | none |
| switch | write | bool | switch_command |
| light | write <id> | bool | light_command with state |
| light | write <id>_brightness | number, percent | light_command with brightness 0 to 1 |
| fan | write <id> | bool | fan_command with state |
| fan | write <id>_speed | number, percent | fan_command with speed_level out of supported_speed_count |
| fan | write <id>_preset | enum | fan_command with preset_mode |
| number | write | number, converted to unit_of_measurement | number_command |
| select | write | enum | select_command |
| button | action | no arguments | button_command |
A channel binds to the entity whose object id is the channel name, minus any _brightness, _speed or _preset suffix, or to map: { object_id: pump_seconds, attribute: state }. A missing entity fails the connect with the list of entities on the device. A write succeeds only when the device reports the new state within timeout, and fan speeds snap to the nearest level. match.esphome holds glob patterns for device info fields such as name and model.
Setup
- Install with
uv tool install --compile-bytecode "halkit[esphome] @ git+https://github.com/sohan-bhat/OpenHAL". - Add an
api:block to the node. Withencryption: key: ..., put the key in a variable such asPLANT_PSKand setnoise_psk_env. - Add node failsafes such as an
on_turn_onpump timer orapi: reboot_timeout, and list the failsafes insafe_state_note. - Start from
openhal/drivers/esphome/examples/plant-waterer.hal.yamlordescribe().
| Key | Default | Meaning |
|---|---|---|
host | required | Host name, .local name or address |
port | 6053 | Native API port |
noise_psk_env | none | Variable holding the API encryption key |
password_env | none | Variable holding the legacy API password |
timeout | 5 s | Handshake deadline and write confirmation window |
Known limitations
- No covers, climate, locks, valves, media players, alarm panels or user-defined services yet.
- Lights expose state and brightness only.
- A deep-sleeping node reads as disconnected most of the time.
- Home Assistant automations on the same node bypass OpenHAL's limits.
Hazard defaults
low, with safe_state from the device file only. A relay switching mains to a heater needs medium or high.
Sources
- ESPHome native API component for port, encryption, password and reboot_timeout, https://esphome.io/components/api.html
- ESPHome api.proto message types, https://github.com/esphome/esphome/blob/dev/esphome/components/api/api.proto
- aioesphomeapi client, MIT, https://github.com/esphome/aioesphomeapi
- ESPHome mDNS and
_esphomelib._tcpdiscovery, https://esphome.io/components/mdns.html