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

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