# ESP Button Service

[中文]

## Introduction

Button Service is a ESP Service wrapper for buttons. It discovers button devices registered in Board Manager, registers callbacks for a selected set of events, and forwards button actions as typed service events. The application does not need to maintain a list of device names.

## Feature List

- Zero-configuration auto-discovery: iterates over all `ESP_BOARD_DEVICE_TYPE_BUTTON` devices registered in `esp_board_manager`, supporting both single-GPIO buttons and ADC multi-button groups

- Fine-grained event registration: uses the `event_mask` bitmask to precisely select which `iot_button` callbacks to install, reducing unnecessary overhead

- Lifecycle-aware forwarding: events are only published while the service is in the running state; forwarding is automatically suppressed when the service is stopped, paused, or enters low power mode, and automatically resumes when the service resumes

- Typed payload: each event carries an `esp_button_service_payload_t` containing the board-level device label, facilitating dispatch handling in multi-button scenarios

- Inherits the standard lifecycle and event subscription interfaces provided by ESP Service, requiring no additional learning of new calling conventions

## Technical Deep Dive

### Auto-Discovery and Event Forwarding

`esp_button_service_create()` scans the device registry of `esp_board_manager`, initializes each button device, and registers the selected `iot_button` callbacks according to `cfg->event_mask`; after calling `esp_service_start()`, every button action is published through the service’s event bus, and all subscribers can respond to it.

            flowchart TD
        BM[esp_board_manager button devices] --> BS[esp_button_service]
        BS -->|iot_button callback| BS
        BS -->|esp_service_publish_event| App[Application subscribers]

    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);

### Event Mask and Event IDs

The service defines 10 event IDs (`ESP_BUTTON_SERVICE_EVT_PRESS_DOWN` and others, with values starting from `1`), each corresponding to a bitmask constant `ESP_BUTTON_SERVICE_EVT_MASK_xxx`; `event_mask` only affects callback registration and does not affect the event IDs themselves. `ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT` enables six commonly used button interactions by default: `PRESS_DOWN`, `PRESS_UP`, `SINGLE_CLICK`, `DOUBLE_CLICK`, `LONG_PRESS_START`, and `LONG_PRESS_UP`.

### Event Payload

Each `ESP_BUTTON_SERVICE_EVT_*` event carries a heap-allocated `esp_button_service_payload_t`, which is automatically freed after all subscribers have received it; the application layer does not need to free it manually:

    typedef struct {
        const char *label;  /* Board-level device name, valid for the lifetime of the process */
    } esp_button_service_payload_t;

For a single-GPIO button, `label` is the board-level device name of that button; for an ADC multi-button group, `label` is taken from `button_labels[]` in the board-level device configuration (`dev_button_config_t`) rather than the device name itself, so that different voltage-level buttons on the same ADC channel can be distinguished.

## Application Examples

- `components/esp_button_service/examples/button_svc_example` demonstrates a mixed setup of a single GPIO button and an ADC multi-button group, along with the complete event subscription flow.

## FAQ

Q1: What happens if the event mask ``event_mask`` is set to 0?

This is equivalent to using `ESP_BUTTON_SERVICE_EVT_MASK_DEFAULT`; `esp_button_service_cfg_t` states that when `event_mask` is `0`, it falls back to the default mask.

## API Reference

### 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.

  Parameters:

    - cfg – [in] Configuration.

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

  Returns:

    - 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.

  Parameters:

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

  Returns:

    - 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.

  Note

  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.

  Note

  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

Provide feedback about this document