ESP Local Controller

[中文]

esp_local_controller is a controller-side client for ESP-IDF esp_local_ctrl.

Component

Role

esp_local_ctrl

Device (server): exposes properties

protocomm_ext

Controller pipe (transport + Security 0 / 1 / 2)

esp_local_controller

Controller business (esp_local_ctrl/control protobuf)

It encodes and decodes the local-control protobufs. Session transport and security handshake stay in protocomm_ext.

Features

  • HTTP, BLE (NimBLE Central), UART Console

  • Runtime version JSON parsing (local_ctrl.sec_ver / sec_patch_ver)

  • Property count / get / set by index

  • Security 0 / 1 / 2 via protocomm_ext

Supported targets: ESP32 / ESP32-S3 / ESP32-C2 / ESP32-C3 / ESP32-C5 / ESP32-C6 / ESP32-C61 / ESP32-H2 / ESP32-P4

Typical Flow

#include "esp_local_controller.h"
#include "protocomm_ext.h"
#include "protocomm_ext_security.h"

protocomm_ext_t *pc = protocomm_ext_new(&pe_cfg); /* transport + Sec0 placeholder */
esp_local_controller_t *ctrl = esp_local_controller_create(pc);

esp_local_controller_fetch_version(ctrl, /* BLE: &ble_addr, else NULL */ NULL);
esp_local_controller_version_t ver = {0};
esp_local_controller_get_version(ctrl, &ver);
/* protocomm_ext_set_security(pc, ...) from ver.sec_ver + PoP / Sec2 creds */
esp_local_controller_version_free(&ver);

esp_local_controller_establish_security(ctrl);

uint32_t count = 0;
esp_local_controller_get_property_count(ctrl, &count);

esp_local_controller_stop_session(ctrl);
esp_local_controller_delete(ctrl);
protocomm_ext_delete(pc);

If the peer scheme is already known, call protocomm_ext_set_security() first, then esp_local_controller_start_session().

Thread safety: APIs on one instance are not thread-safe; serialize from a single task.

Add Dependency

dependencies:
  espressif/esp_local_controller: "^1.0.0"

Example

See examples/esp_local_controller. Pair with the official IDF example examples/protocols/esp_local_ctrl.

API Reference

Header File

Functions

esp_local_controller_t *esp_local_controller_create(protocomm_ext_t *pc)

Wrap an existing protocomm_ext instance.

Ownership of pc remains with the caller; call esp_local_controller_delete() before protocomm_ext_delete().

Registers BLE endpoint UUID mappings (ESP_LOCAL_CONTROLLER_EP_*_UUID).

Note

APIs on a given instance are not thread-safe. Serialize from one task.

Parameters

pc – [in] Existing protocomm_ext instance (must not be NULL)

Returns

  • non-NULL: new controller instance

  • NULL: invalid argument, endpoint registration failure, or out of memory

void esp_local_controller_delete(esp_local_controller_t *ctrl)

Delete a controller created by esp_local_controller_create()

Does not delete the underlying protocomm_ext instance.

Parameters

ctrl – [in] Instance to delete (NULL-safe)

protocomm_ext_t *esp_local_controller_get_protocomm(esp_local_controller_t *ctrl)

Return the wrapped protocomm_ext instance.

Parameters

ctrl – [in] Controller instance

Returns

Underlying protocomm_ext pointer, or NULL if ctrl is NULL

esp_err_t esp_local_controller_fetch_version(esp_local_controller_t *ctrl, const void *transport_connect_cfg)

Open transport session and read version JSON (plaintext)

Does not run the security handshake. Stores parsed version for esp_local_controller_get_version(). On failure, any previously cached version is invalidated and the transport session is closed.

Parameters
  • ctrl – [in] Controller instance

  • transport_connect_cfg – [in] HTTP/Console: NULL; BLE: ble_addr_t *

Returns

  • ESP_OK: version fetched and parsed

  • ESP_ERR_INVALID_ARG: bad arguments

  • ESP_ERR_INVALID_RESPONSE: JSON missing / invalid sec_ver

  • Other: transport or allocation errors from protocomm_ext

esp_err_t esp_local_controller_establish_security(esp_local_controller_t *ctrl)

Run security_init + establish_security on esp_local_ctrl/session.

Call after protocomm_ext_set_security() with peer sec_ver / credentials (typically after esp_local_controller_fetch_version() + get_version()).

Parameters

ctrl – [in] Controller instance (session must already be open)

Returns

  • ESP_OK: security established; property APIs may be used

  • ESP_ERR_INVALID_ARG: bad arguments

  • Other: errors from protocomm_ext security APIs

esp_err_t esp_local_controller_start_session(esp_local_controller_t *ctrl, const void *transport_connect_cfg)

Convenience: fetch_version + establish_security.

Prerequisite: call protocomm_ext_set_security() first when the peer scheme is already known (Sec0/1/2 credentials). Equivalent to the recommended split flow when discovery is not needed at runtime.

On establish failure, closes the session and invalidates cached version.

Parameters
Returns

  • ESP_OK: session ready for property get/set

  • Other: see fetch_version / establish_security

esp_err_t esp_local_controller_stop_session(esp_local_controller_t *ctrl)

Close the transport session.

Parameters

ctrl – [in] Controller instance

Returns

Result of protocomm_ext_close_session(), or ESP_ERR_INVALID_ARG

esp_err_t esp_local_controller_get_version(esp_local_controller_t *ctrl, esp_local_controller_version_t *out)

Deep-copy the last successfully fetched version into out.

Parameters
  • ctrl – [in] Controller instance

  • out – [out] Output version (must not be NULL)

Returns

  • ESP_OK: out filled; caller must call esp_local_controller_version_free()

  • ESP_ERR_INVALID_ARG: bad arguments

  • ESP_ERR_INVALID_STATE: no successful fetch yet

  • ESP_ERR_NO_MEM: strdup failed

void esp_local_controller_version_free(esp_local_controller_version_t *ver)

Free heap fields inside a version struct from get_version / parse_version.

Parameters

ver – [inout] Version to clear (NULL-safe for pointer; no-op if NULL)

esp_err_t esp_local_controller_get_property_count(esp_local_controller_t *ctrl, uint32_t *count)

Query how many properties the peer exposes.

Requires an established secure session (or Sec0 after establish_security).

Parameters
  • ctrl – [in] Controller instance

  • count – [out] Property count

Returns

ESP_OK on success, or a transport / protocol error

esp_err_t esp_local_controller_get_property_values(esp_local_controller_t *ctrl, const uint32_t *indices, size_t index_count, esp_local_controller_prop_t **out_props, size_t *out_count)

Fetch property metadata + values for the given indices.

On success, allocates *out_props of length *out_count. If the peer returns zero properties, *out_props is NULL and *out_count is 0. Caller frees with esp_local_controller_props_free() (NULL-safe).

Parameters
  • ctrl – [in] Controller instance

  • indices – [in] Array of zero-based property indices

  • index_count – [in] Number of indices (must be > 0)

  • out_props – [out] Allocated property array

  • out_count – [out] Number of entries in *out_props

Returns

ESP_OK on success, or a transport / protocol / OOM error

void esp_local_controller_props_free(esp_local_controller_prop_t *props, size_t count)

Free an array from esp_local_controller_get_property_values()

Parameters
  • props – [in] Property array (NULL-safe)

  • count – [in] Number of elements

esp_err_t esp_local_controller_set_property_values(esp_local_controller_t *ctrl, const esp_local_controller_prop_set_t *props, size_t prop_count)

Set one or more property values by index.

Parameters
  • ctrl – [in] Controller instance

  • props – [in] Array of set descriptors

  • prop_count – [in] Number of entries (must be > 0)

Returns

ESP_OK on success, or a transport / protocol / OOM error

esp_err_t esp_local_controller_parse_version(const char *json, esp_local_controller_version_t *out)

Parse version JSON into out (exposed for unit tests / advanced use)

Note

Prefer esp_local_controller_fetch_version() in application code.

Parameters
Returns

  • ESP_OK: parsed

  • ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_RESPONSE / ESP_ERR_NO_MEM

Structures

struct esp_local_controller_version_t

Parsed fields from the plaintext version endpoint JSON.

Device format: {"local_ctrl":{"ver":"...","sec_ver":N,"sec_patch_ver":M}}

Public Members

char *ver

Heap copy of local_ctrl.ver; free with version free helper

int sec_ver

0 / 1 / 2; -1 if missing

int sec_patch_ver

Patch; -1 if missing

struct esp_local_controller_prop_t

One property returned by esp_local_controller_get_property_values()

Caller owns name and value; free with esp_local_controller_props_free().

Public Members

char *name

Property name (may be NULL)

uint32_t type

Application-defined type

uint32_t flags

Application-defined flags (e.g. read-only)

uint8_t *value

Raw value bytes (may be NULL)

size_t value_len

Length of value

struct esp_local_controller_prop_set_t

One property value for esp_local_controller_set_property_values()

Public Members

uint32_t index

Zero-based property index on the device

const uint8_t *value

Value bytes (may be NULL if value_len == 0)

size_t value_len

Length of value

Macros

ESP_LOCAL_CONTROLLER_EP_VERSION

Version endpoint name (IDF esp_local_ctrl)

ESP_LOCAL_CONTROLLER_EP_SESSION

Session endpoint name (IDF esp_local_ctrl)

ESP_LOCAL_CONTROLLER_EP_CONTROL

Control endpoint name (IDF esp_local_ctrl)

ESP_LOCAL_CONTROLLER_EP_VERSION_UUID

BLE UUID16 for version, matching IDF declare_ep starting at 0xFF50.

ESP_LOCAL_CONTROLLER_EP_SESSION_UUID

BLE UUID16 for session (version + 1).

ESP_LOCAL_CONTROLLER_EP_CONTROL_UUID

BLE UUID16 for control (version + 2).

ESP_LOCAL_CONTROLLER_MAX_PROPERTIES

Upper bound on property indices / returned props accepted from a peer. Rejects oversized count / n_props before allocating (DoS / OOM guard). IDF device examples typically use a much smaller max_properties.

Type Definitions

typedef struct esp_local_controller esp_local_controller_t

Opaque local-controller instance.