# ESP Button Service

[English]

## 简介

Button Service 是 ESP Service 上的按键封装。它发现 Board Manager 中登记的按键设备，为选定事件注册回调，并将按键动作作为带类型的服务事件转发。应用层不必自行维护设备名称列表。

## 功能清单

- 零配置自动发现：遍历 `esp_board_manager` 中登记的所有 `ESP_BOARD_DEVICE_TYPE_BUTTON` 设备，同时支持单路 GPIO 按键和 ADC 多按键组

- 精细化事件注册：通过位掩码 `event_mask` 精确选择要安装的 `iot_button` 回调，减少不必要的开销

- 生命周期感知转发：只在服务处于运行状态时发布事件；服务停止、暂停或进入低功耗时自动抑制转发，恢复时自动继续

- 类型化载荷：每个事件携带包含板级设备标签的 `esp_button_service_payload_t`，便于多按键场景的分发处理

- 继承 ESP Service 提供的标准生命周期与事件订阅接口，无需额外学习新的调用方式

## 技术拆解

### 自动发现与事件转发

`esp_button_service_create()` 扫描 `esp_board_manager` 的设备注册表，初始化每个按键设备，并按 `cfg->event_mask` 注册所选的 `iot_button` 回调；调用 `esp_service_start()` 后，每次按键动作都会通过服务的事件总线发布，所有订阅者均可响应。

            flowchart TD
        BM[esp_board_manager 按键设备] --> BS[esp_button_service]
        BS -->|iot_button 回调| BS
        BS -->|esp_service_publish_event| App[应用层订阅者]

    esp_board_manager_init();

    esp_button_service_cfg_t cfg = {
        .name       = "esp_button_service",
        .event_mask = ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT,
    };
    esp_button_service_t *svc = NULL;
    esp_button_service_create(&cfg, &svc);

    esp_service_t *base = (esp_service_t *)svc;
    adf_event_subscribe_info_t sub = ADF_EVENT_SUBSCRIBE_INFO_DEFAULT();
    sub.event_id = ADF_EVENT_ANY_ID;
    sub.handler  = on_button_event;
    esp_service_event_subscribe(base, &sub);

    esp_service_start(base);

### 事件掩码与事件 ID

服务定义了 10 个事件 ID（`ESP_BUTTON_SERVICE_EVT_PRESS_DOWN` 等，取值从 `1` 开始），每个都对应一个位掩码常量 `ESP_BUTTON_SERVICE_EVT_MASK_xxx`；`event_mask` 只影响回调注册，不影响事件 ID 本身。`ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT` 默认开启 `PRESS_DOWN`、`PRESS_UP`、`SINGLE_CLICK`、`DOUBLE_CLICK`、`LONG_PRESS_START` 和 `LONG_PRESS_UP` 六个常用的按键交互。

### 事件载荷

每个 `ESP_BUTTON_SERVICE_EVT_*` 事件携带一个堆分配的 `esp_button_service_payload_t`，在所有订阅者接收完毕后自动释放，应用层不需要手动 free：

    typedef struct {
        const char *label;  /* 板级设备名，进程生命周期内有效 */
    } esp_button_service_payload_t;

对于单路 GPIO 按键，`label` 就是该按键的板级设备名；对于 ADC 多按键组，`label` 取自板级设备配置里的 `button_labels[]`（`dev_button_config_t`），而不是设备名本身，因此同一路 ADC 通道下的不同电压挡位按键也能被区分。

## 应用示例

- `components/esp_button_service/examples/button_svc_example` 演示单 GPIO 按键与 ADC 多按键组的混合接入，以及完整的事件订阅流程。

## FAQ

Q1：事件掩码 event_mask 设为 0 会怎样？

等同于使用 `ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT`；`esp_button_service_cfg_t` 中说明 `event_mask` 为 `0` 时会回退到默认掩码。

## API 参考

### Header File

- components/esp_button_service/include/esp_button_service.h

### Functions

esp_err_t esp_button_service_create(const esp_button_service_cfg_t *cfg, esp_button_service_t **out_svc)

  Create a button service backed by esp_board_manager devices.

          Discovers all registered board-manager devices of type
          ESP_BOARD_DEVICE_TYPE_BUTTON and initializes them,
          registers iot_button callbacks for the events selected by cfg->event_mask,
          and places the service in the INITIALIZED state.

          Call esp_service_start() to begin forwarding events, and
          esp_service_event_subscribe() to receive them.

  参数:

    - cfg – [in] Configuration.

    - out_svc – [out] Output: allocated service instance.

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG cfg or out_svc is NULL

    - ESP_ERR_NOT_FOUND No button devices are registered in board manager

    - ESP_ERR_NO_MEM Allocation failed

    - other Device initialization or callback registration failed

esp_err_t esp_button_service_destroy(esp_button_service_t *svc)

  Stop, deinitialize, and free the button service.

          Deinitializes all board-manager devices and releases all resources.
          After this call the pointer is invalid.

  参数:

    svc – [in] Service instance returned by esp_button_service_create().

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG svc is NULL

### Structures

struct esp_button_service_payload_t

  Payload carried by every ESP_BUTTON_SERVICE_EVT_* event.

          Heap-allocated per event; freed automatically after all subscribers
          have received it.

  备注

  label points to a static board-manager device name string and is valid for the lifetime of the process.

  Public Members

  const char *label

    Board-manager device name identifying the button

struct esp_button_service_cfg_t

  Button service creation configuration.

  Public Members

  const char *name

    Service name used as event hub domain; NULL → “esp_button_service”

  uint32_t event_mask

    OR of ESP_BUTTON_SERVICE_EVT_MASK_xxx; 0 → ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT

### Macros

ESP_BUTTON_SERVICE_EVT_MASK_PRESS_DOWN

  Bitmask constants for selecting which iot_button events to register.

          Pass an OR of these values in esp_button_service_cfg_t::event_mask.

ESP_BUTTON_SERVICE_EVT_MASK_PRESS_UP

ESP_BUTTON_SERVICE_EVT_MASK_SINGLE_CLICK

ESP_BUTTON_SERVICE_EVT_MASK_DOUBLE_CLICK

ESP_BUTTON_SERVICE_EVT_MASK_LONG_PRESS_START

ESP_BUTTON_SERVICE_EVT_MASK_LONG_PRESS_HOLD

ESP_BUTTON_SERVICE_EVT_MASK_LONG_PRESS_UP

ESP_BUTTON_SERVICE_EVT_MASK_PRESS_REPEAT

ESP_BUTTON_SERVICE_EVT_MASK_PRESS_REPEAT_DONE

ESP_BUTTON_SERVICE_EVT_MASK_PRESS_END

ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT

  Default event mask: the most common button interactions

### Type Definitions

typedef struct esp_button_service esp_button_service_t

### Enumerations

enum [anonymous]

  Button event IDs — which iot_button action occurred.

          These are published via the service event hub.  Subscribers can
          filter on a specific event_id or use ADF_EVENT_ANY_ID to receive all.

  备注

  Event IDs start at 1; 0 is reserved as “no event”.

  Values:

  enumerator ESP_BUTTON_SERVICE_EVT_PRESS_DOWN

    Button physically pressed

  enumerator ESP_BUTTON_SERVICE_EVT_PRESS_UP

    Button physically released

  enumerator ESP_BUTTON_SERVICE_EVT_SINGLE_CLICK

    Single click detected

  enumerator ESP_BUTTON_SERVICE_EVT_DOUBLE_CLICK

    Double click detected

  enumerator ESP_BUTTON_SERVICE_EVT_LONG_PRESS_START

    Long press threshold reached

  enumerator ESP_BUTTON_SERVICE_EVT_LONG_PRESS_HOLD

    Long press hold tick

  enumerator ESP_BUTTON_SERVICE_EVT_LONG_PRESS_UP

    Long press released

  enumerator ESP_BUTTON_SERVICE_EVT_PRESS_REPEAT

    Repeat press tick

  enumerator ESP_BUTTON_SERVICE_EVT_PRESS_REPEAT_DONE

    Repeat press sequence ended

  enumerator ESP_BUTTON_SERVICE_EVT_PRESS_END

    Press sequence complete

提供有关此文档的反馈