跳转到内容

原生 API 组件

ESPHome 原生 API 用于通过高度优化的网络协议与客户端直接通信。目前,只有 ESPHome 工具、Home Assistant 和 ioBroker 使用此原生 API。

在 ESPHome 配置中添加一行 api: 后,您可以进入 Home Assistant 网页界面,并在”配置”面板中导航到”集成”界面。然后等待 ESPHome 设备出现在”已发现”部分下(最多可能需要 5 分钟),或者在集成概览中选择”ESPHome”手动添加设备,并在”主机”字段中输入 “<NODE_NAME>.local” 或设备的 IP 地址。

ESPHome 原生 API 基于使用 protocol buffers 的自定义 TCP 协议。您可以在此处找到协议数据结构定义:api.proto 实现此协议的 Python 库是 aioesphomeapi。

NOTE

Actions 以前被称为 Services。ESPHome 为与 Home Assistant 保持一致而更改了名称,但在可预见的将来仍会继续支持带有 services 和 homeassistant.service 的 YAML。 文档将只引用 Actions。

# Example configuration entry
api:
# Example with more options
api:
port: 6053
batch_delay: 50ms # Reduce latency for real-time applications
listen_backlog: 2 # Allow 2 pending connections in queue
max_connections: 6 # Allow up to 6 simultaneous connections
max_send_queue: 10 # Maximum queued messages per connection before disconnect
encryption:
key: "YOUR_ENCRYPTION_KEY_HERE"
reboot_timeout: 30min
  • port (可选, int):运行 API 服务器的端口。默认为 6053。

  • listen_backlog (可选, int):监听队列中允许的最大挂起连接数。必须在 1 到 10 之间。 ESP8266/RP2040 默认为 1,ESP32 和其他平台默认为 4。值越小占用的内存越少,但在突发情况下可能拒绝连接。

  • max_connections (可选, int):允许的最大同时 API 连接数。必须在 1 到 20 之间。 默认值为:

    • ESP8266/RP2040 为 4,
    • ESP32/BK72xx/RTL87xx/LN882x 为 5,
    • host 平台为 8。

    NOTE

    max_connections 作为编译时常量固化在编译后的固件中——连接槽是静态分配的,因此每个槽无论是否被使用都会占用少量静态 RAM,更改该值必须重新刷写固件。 此外,每个活动的 API 连接在连接期间大约会消耗 500–1000 字节的 RAM。ESP8266 和 RP2040 设备的可用 RAM 有限(ESP8266 启动后通常约有 40KB 的空闲 RAM,但在配置了传感器和其他组件后可能会降至 20KB 以下;RP2040 使用 LWIP 原始套接字,限制类似),因此注意不要将该值设置得太高,否则可能导致内存不足崩溃。 默认值是在内存使用与允许多个同时连接之间取得平衡而设定的。

  • max_send_queue (可选, int):每个连接在断开之前可以排队等待发送的最大消息数。必须在 1 到 64 之间。 默认值为:

    • ESP8266/RP2040 为 5,
    • ESP32/BK72xx/LN882x/nRF52/RTL87xx 为 8,
    • host 平台为 16。

    这可以防止在客户端速度慢或网络停滞时耗尽内存。 每条排队的消息大约使用 8-12 字节的开销加上消息本身的大小。

    NOTE

    当某个连接的发送队列已满时,设备会记录错误并断开该客户端,以防止内存不足崩溃。 客户端速度慢、Wi-Fi 连接不佳导致的重试或网络拥塞都可能触发此情况。如果有正常客户端被断开,请增大此值,但要注意嵌入式设备的内存限制。

  • encryption (可选):如果存在此配置,将为 API 启用加密。使用加密有助于保护运行 ESPHome 的设备与已连接的客户端之间的通信。

    • key (可选, string):用作加密密钥的 32 字节 base64 编码字符串。如果未提供, 密钥可以在运行时设置,但在设置之前不会使用加密。

      如果您需要密钥,可以使用下面的密钥;它会在每次页面加载时由您的浏览器随机生成:

NOTE

支持在运行中配置加密密钥将在 Home Assistant 的未来版本中实现。

TIP

有关包括 API 加密最佳实践在内的全面安全指南,请参阅安全最佳实践指南。

  • actions (可选, list):用户定义的操作列表。请参阅用户定义操作。
  • batch_delay (可选, 时间):将多个状态更新消息批量发送以降低网络开销的延迟时间。较低的值能使更新更快发送,但会使用更多网络数据包,而较高的值批量发送效率更高,但会增加延迟。必须在 0ms 和 65535ms(65.535 秒)之间。默认为 100ms。

NOTE

设置 batch_delay: 0ms 可启用状态更新的立即发送模式。这对于需要实时响应的应用程序很有用,例如必须保留快速 ON→OFF 转换的红外遥控二进制传感器。但是,这会增加网络流量,并且可能在使用许多快速变化的传感器时影响 Wi-Fi 性能。仅在必要时使用此设置。

  • custom_services (可选, boolean):为使用 C++ CustomAPIDevice 类的外部组件启用自定义 API 服务的编译。仅当外部组件通过原生 API 注册自己的服务时才需要。默认为 false。

  • homeassistant_services (可选, boolean):为使用 C++ CustomAPIDevice::call_homeassistant_service() 或 CustomAPIDevice::fire_homeassistant_event() 方法的外部组件启用编译 Home Assistant 服务调用支持。当使用 homeassistant.service 或 homeassistant.event 操作,或为 number 或 switch 组件使用 homeassistant 平台时,会自动启用。仅当外部组件在不使用内置操作的情况下调用 Home Assistant 服务时才需要手动设置。默认为 false。

  • homeassistant_states (可选, boolean):为使用 C++ CustomAPIDevice::subscribe_homeassistant_state() 方法的外部组件启用编译 Home Assistant 状态订阅支持。当使用任何 homeassistant 平台组件(sensor、binary_sensor、text_sensor、switch 或 number)时会自动启用。仅当外部组件在不使用内置组件的情况下订阅 Home Assistant 状态时才需要手动设置。默认为 false。

  • reboot_timeout (可选, 时间):当没有客户端连接到 API 时,在重启之前等待的时间。这是必要的,因为有时底层 ESP 功能会报告 ESP 已连接到网络,而实际上并没有 - 只有完全重启才能解决。可以通过将其设置为 0s 来禁用。默认为 15min。

  • id (可选, ID):手动指定用于代码生成的 ID。

  • on_client_connected (可选, Action):当客户端连接到 API 时执行的自动化。请参阅 on_client_connected 触发器。

  • on_client_disconnected (可选, Action):当客户端断开与 API 的连接时执行的自动化。请参阅 on_client_disconnected 触发器。

在使用下面的任何操作之前,您需要告诉 Home Assistant 允许您的设备执行操作。

NOTE

从 ESPHome 2025.10.0 开始,您可以使用 capture_response、on_success 和 on_error 配置操作来接收和处理来自 Home Assistant 的响应。有关详细信息,请参阅操作响应处理。

在您的 Home Assistant 实例上打开 ESPHome 集成页面:

打开您的 Home Assistant 实例并显示 ESPHome 集成。

然后:

  1. 在设备列表中找到您的设备

  2. 单击其旁边的”配置”按钮

  3. 选中”允许设备执行 Home Assistant 操作”复选框

  4. 然后点击”提交”

NOTE

务必按照上面的说明告诉 Home Assistant 允许 您的设备执行操作。

将原生 API 与 Home Assistant 一起使用时,您可以直接从 ESPHome 自动化在 Home Assistant 事件总线中创建事件。

# In some trigger
on_...:
# Simple
- homeassistant.event:
event: esphome.button_pressed
data:
message: Button was pressed
  • event (必填, string):要创建的事件 - 必须以 esphome. 开头

  • data (可选, mapping):可选的要随事件传递的静态数据。

  • data_template (可选, mapping):可选的要随事件传递的模板数据。 这会使用 Home Assistant 的模板引擎在 Home Assistant 端求值。

  • variables (可选, mapping):可在 data_template 中使用的可选变量。 值类型为 lambdas,将在发送请求前求值。

NOTE

务必按照上面的说明告诉 Home Assistant 允许 您的设备执行操作。

将原生 API 与 Home Assistant 一起使用时,您可以直接从 ESPHome 自动化执行 Home Assistant 操作。

# In some trigger
on_...:
# Simple
- homeassistant.action:
action: notify.html5
data:
message: Button was pressed
# With templates and variables
- homeassistant.action:
action: notify.html5
data:
title: New Humidity
data_template:
message: The humidity is {{ my_variable }}%.
variables:
my_variable: |-
return id(my_sensor).state;
  • action (必填, string, templatable):要执行的 Home Assistant Action。

  • data (可选, mapping):可选的要执行操作所用的静态数据。

  • data_template (可选, mapping):可选的要执行操作所用的模板数据。 这会使用 Home Assistant 的模板引擎在 Home Assistant 端求值。

  • variables (可选, mapping):可在 data_template 中使用的可选变量。 值类型为 lambdas,将在发送请求前求值。

  • capture_response (可选, boolean):启用捕获 Home Assistant 操作调用的响应。 启用后,必须配置 on_success。默认为 false。

  • response_template (可选, string, templatable):用于处理操作响应数据的可选 Jinja 模板。该模板会使用 Home Assistant 的模板引擎在 Home Assistant 端求值。 需要 capture_response: true。

  • on_success (可选, 自动化):当 Home Assistant 操作调用成功时执行的可选自动化。当 capture_response: true 时,响应数据作为一个类型为 JsonObjectConst 的 response 变量可用。 请参阅操作响应处理。

  • on_error (可选, 自动化):当 Home Assistant 操作调用失败时执行的可选自动化。请参阅操作响应处理。

NOTE

Home Assistant 在 API 连接建立后稍晚才开始监听设备操作,因此在连接时立即触发的操作(例如来自 on_client_connected 或 on_time_sync)可能会在 Home Assistant 就绪之前触发。此类操作不会被传递,ESPHome 会记录警告(2026.8.0 之前的版本会静默丢弃)。homeassistant.event 也是如此。如果您需要在连接建立后立即执行操作,请在其之前添加一个短的 delay,以便 Home Assistant 有时间开始监听。

数据结构是不可能的,但您可以在 Home Assistant 中创建一个脚本并以纯格式调用所有参数。

# Home Assistant Configuration
script:
...
set_light_rgb:
alias: 'ESPHome RGB light set'
sequence:
- action: light.turn_on
data_template:
entity_id: '{{ light_name }}'
rgb_color:
- '{{ red }}'
- '{{ green }}'
- '{{ blue }}'

然后,在 ESPHome 中:

# In some trigger
on_...:
- homeassistant.action:
action: script.set_light_rgb
data:
light_name: 'my_light'
red: '255'
green: '199'
blue: '71'

NOTE

操作响应处理在 ESPHome 2025.10.0 及更高版本中可用。

您可以配置操作来接收和处理来自 Home Assistant 的响应。这实现了双向通信,ESPHome 不仅可以调用 Home Assistant 操作,还可以处理它们的响应。

使用 on_success 和 on_error 来响应操作完成:

on_...:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.demo_light
on_success:
- logger.log: "Toggled demo light"
on_error:
- logger.log: "Failed to toggle demo light"

要捕获并处理来自操作的响应数据,请设置 capture_response: true。启用后,必须配置 on_success,并且响应数据作为一个名为 response 的 JsonObjectConst 变量可用。

# Example: Get weather forecast and parse JSON response
on_...:
- homeassistant.action:
action: weather.get_forecasts
data:
entity_id: weather.forecast_home
type: hourly
capture_response: true
on_success:
- lambda: |-
JsonObjectConst next_hour = response["response"]["weather.forecast_home"]["forecast"][0];
float next_temperature = next_hour["temperature"].as<float>();
ESP_LOGI("weather", "Temperature next hour: %.1f", next_temperature);

使用 response_template 通过 Home Assistant 的 Jinja 模板引擎从复杂响应中提取和格式化数据。这需要 capture_response: true。

# Example: Extract temperature using a template
on_...:
- homeassistant.action:
action: weather.get_forecasts
data:
entity_id: weather.forecast_home
type: hourly
capture_response: true
response_template: "{{ response['weather.forecast_home']['forecast'][0]['temperature'] }}"
on_success:
- lambda: |-
float temperature = response["response"].as<float>();
ESP_LOGI("weather", "Temperature next hour: %.1f", temperature);

使用 response_template 时,处理后的结果可以在 response["response"] 中获取。

NOTE

务必按照上面的说明告诉 Home Assistant 允许 您的设备进行操作调用。

将原生 API 与 Home Assistant 一起使用时,您可以直接从 ESPHome 自动化将 tag_scanned 推送到 Home Assistant。

# In some trigger
on_...:
# Simple
- homeassistant.tag_scanned: some-tag
  • tag (必填, string, templatable):已扫描标签的 ID

每当客户端连接到 API 时,都会激活此触发器。此触发器内部调用的操作可以使用两个 std::string 类型的变量:

  • client_address :已连接客户端的 IP 地址
  • client_info :已连接客户端的名称
api:
# ...
on_client_connected:
- logger.log:
format: "Client %s connected to API with IP %s"
args: ["client_info.c_str()", "client_address.c_str()"]

每当 API 与 API 断开连接时,都会激活此触发器。此触发器内部调用的操作可以使用两个 std::string 类型的变量:

  • client_address :已断开连接客户端的 IP 地址
  • client_info :已断开连接客户端的名称
api:
# ...
on_client_disconnected:
- logger.log: "API client disconnected!"

此 Condition 检查是否至少有一个客户端连接到 ESPHome 原生 API。

  • state_subscription_only (可选, boolean, templatable):启用后,只计算已订阅实体状态更新的客户端。这可过滤掉仅日志连接(例如 esphome logs 命令),这些连接在等待 Home Assistant 时可能导致误报。默认为 false。

检查是否有任何客户端已连接:

on_...:
if:
condition:
api.connected:
then:
- logger.log: Client is connected to API!

等效的 lambda 是 id(api_id).is_connected()。

检查是否有订阅实体状态的客户端已连接(通常是 Home Assistant):

on_boot:
- wait_until:
condition:
api.connected:
state_subscription_only: true
- logger.log: Home Assistant is connected!
- homeassistant.event:
event: esphome.device_booted

等效的 lambda 是 id(api_id).is_connected(true)。

使用场景:

  • 使用 state_subscription_only: false(默认值)检测任何 API 连接
  • 当您需要确保 Home Assistant(或其他订阅状态的连接)在发送事件或调用服务之前已连接时,使用 state_subscription_only: true,以防止仅日志连接导致的错误

还可以通过用户定义操作将数据从 Home Assistant 获取到 ESPHome。当您在 ESPHome YAML 文件中声明操作时,它们会自动出现在 Home Assistant 中,您可以直接调用它们。

NOTE

用户定义操作还可以使用 api.respond 操作将响应发送回调用客户端。 有关详细信息,请参阅操作响应。

# Example configuration entry
api:
actions:
- action: start_laundry
then:
- switch.turn_on: relay
- delay: 3h
- switch.turn_off: relay

例如,使用上面的配置,上传后您会看到一个名为 esphome.livingroom_start_laundry 的操作(livingroom 是节点名称),您可以随后调用它。

此外,您还可以使用此方法将数据从 Home Assistant 传输到 ESPHome:

# Example configuration entry
api:
actions:
- action: start_effect
variables:
my_brightness: int
my_effect: string
then:
- light.turn_on:
id: my_light
brightness: !lambda 'return my_brightness;'
effect: !lambda 'return my_effect;'

使用 variables 键,您可以告诉 ESPHome 期望从 Home Assistant 收到哪些变量。例如,上面的操作会以类似于下面这样的方式执行:

# Example Home Assistant Action
action: esphome.livingroom_start_effect
data_template:
my_brightness: "{{ states.brightness.state }}"
my_effect: "Rainbow"

然后,您在 variables 部分中定义的每个变量都可以在由用户定义操作触发的自动化中通过您在 variables 部分中赋予它的名称来访问(注意:这是一个局部变量,因此访问它时不要用 id(...) 包裹)。

目前有 4 种变量类型:

  • bool:布尔值(ON/OFF)。C++ 类型:bool
  • int:整数。C++ 类型:int /int32_t
  • float:浮点数。C++ 类型:float
  • string:字符串。C++ 类型:std::string

这些也都有对应的数组形式:

  • bool[]:布尔值数组。C++ 类型:std::vector<bool>
  • … - 其他类型同理。

用户定义操作可以将响应发送回调用客户端(例如 Home Assistant)。这实现了双向通信,操作可以报告成功/错误状态或返回结构化 JSON 数据。

响应行为由 supports_response 选项控制,可以显式设置,也可以根据您的操作配置自动检测:

  • none(默认):不发送响应。该操作是”发射后就忘记”。
  • status:报告成功/错误状态而不带数据。当 api.respond 不配合 data: 使用时自动检测。
  • optional:当客户端请求时返回 JSON 数据。当 api.respond 配合 data: 使用时自动检测。
  • only:始终返回 JSON 数据。必须显式设置。适用于查询类型的操作。
  • supports_response (可选, string):此操作的响应模式。为 none、status、 optional 或 only 之一。如果未指定,则根据操作中 api.respond 的使用情况自动检测模式。

当 supports_response 不是 none 时,以下变量在操作中可用:

  • call_id (uint32_t):此操作调用的唯一标识符。由 api.respond 在内部使用。
  • return_response (bool):仅在 optional 模式下可用。指示客户端是否请求了响应。您通常不需要检查它 - api.respond 会自动处理。

此操作将响应发送回调用用户定义操作的客户端。它可以报告成功/错误状态,并可选择包含 JSON 数据。

  • success (可选, boolean, templatable):操作是否成功。 默认为 true。
  • error_message (可选, string, templatable):当 success 为 false 时要包含的错误消息。默认为空字符串。
  • data (可选, lambda):用于填充包含响应数据的 JSON 对象的 lambda。该 lambda 接收一个类型为 JsonObject 的 root 变量,您可以在其中填充键值对。

在不返回数据的情况下报告成功或错误:

api:
actions:
- action: validate_input
variables:
value: int
then:
- if:
condition:
lambda: 'return value < 0;'
then:
- api.respond:
success: false
error_message: "Value must be positive"
else:
- api.respond:
success: true

向调用方返回结构化 JSON 数据:

api:
actions:
- action: get_sensor_data
variables:
sensor_name: string
then:
- api.respond:
data: !lambda |-
root["sensor"] = sensor_name;
root["value"] = id(my_sensor).state;
root["unit"] = "°C";
root["timestamp"] = id(homeassistant_time).now().timestamp;

此操作将自动检测为 optional 模式,因为它使用带 data: 的 api.respond。

对于始终返回数据的操作(如查询),请显式设置 supports_response: only:

api:
actions:
- action: get_device_info
supports_response: only
then:
- api.respond:
data: !lambda |-
root["hostname"] = App.get_name();
root["version"] = ESPHOME_VERSION;
root["uptime"] = millis() / 1000;

您可以创建复杂的嵌套 JSON 结构:

api:
actions:
- action: get_full_status
supports_response: only
then:
- api.respond:
data: !lambda |-
root["device"]["name"] = "living_room";
root["device"]["version"] = 1;
root["sensors"]["temperature"] = id(temp_sensor).state;
root["sensors"]["humidity"] = id(humidity_sensor).state;

支持响应的操作在 Home Assistant 中会显示其响应模式。您可以调用它们并接收响应数据:

# Home Assistant automation example
action: esphome.device_get_sensor_data
data:
sensor_name: "living_room"
response_variable: sensor_response

响应将在 sensor_response 变量中可用,其结构为您在 data: lambda 中定义的结构。

ESPHome 原生 API 与使用 MQTT 和家庭自动化软件(目前只有 Home Assistant 和 ioBroker)通信相比有许多优势。但 MQTT 是一个很好的协议,永远不会被移除。原生 API 的功能(相对于 MQTT):

  • 效率高得多: ESPHome 使用高度优化的格式配合 protocol buffers 对所有消息进行编码 - 例如,二进制传感器状态消息的大小约为 MQTT 的 1/10。

  • 一键配置: ESPHome 只需一次点击即可在 Home Assistant 中完成设置 - 无需再处理保留的 MQTT 发现消息等类似内容。

  • 少一个单点故障: 在 ESPHome 原生 API 中,每个 ESP 都是自己的服务器。使用 MQTT 时,当 broker 关闭后,就无法再进行任何通信。

  • 稳定性: 由于 ESPHome 对协议的控制远强于对 MQTT 的,因此对我们来说推出稳定性改进非常容易。

  • 低延迟: 原生 API 针对极低延迟进行了优化,通常只有几毫秒,远低于肉眼可察觉的程度。