ESP Local Control¶
Overview¶
ESP Local Control (esp_local_ctrl) component in ESP-IDF provides capability to control an ESP device over Wi-Fi + HTTPS or BLE. It provides access to application defined properties that are available for reading / writing via a set of configurable handlers.
Initialization of the esp_local_ctrl service over BLE transport is performed as follows:
esp_local_ctrl_config_t config = { .transport = ESP_LOCAL_CTRL_TRANSPORT_BLE, .transport_config = { .ble = & (protocomm_ble_config_t) { .device_name = SERVICE_NAME, .service_uuid = { /* LSB <--------------------------------------- * ---------------------------------------> MSB */ 0x21, 0xd5, 0x3b, 0x8d, 0xbd, 0x75, 0x68, 0x8a, 0xb4, 0x42, 0xeb, 0x31, 0x4a, 0x1e, 0x98, 0x3d } } }, .handlers = { /* User defined handler functions */ .get_prop_values = get_property_values, .set_prop_values = set_property_values, .usr_ctx = NULL, .usr_ctx_free_fn = NULL }, /* Maximum number of properties that may be set */ .max_properties = 10 }; /* Start esp_local_ctrl service */ ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Similarly for HTTPS transport:
/* Set the configuration */ httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT(); /* Load server certificate */ extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end"); https_conf.cacert_pem = cacert_pem_start; https_conf.cacert_len = cacert_pem_end - cacert_pem_start; /* Load server private key */ extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); https_conf.prvtkey_pem = prvtkey_pem_start; https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start; esp_local_ctrl_config_t config = { .transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD, .transport_config = { .httpd = &https_conf }, .handlers = { /* User defined handler functions */ .get_prop_values = get_property_values, .set_prop_values = set_property_values, .usr_ctx = NULL, .usr_ctx_free_fn = NULL }, /* Maximum number of properties that may be set */ .max_properties = 10 }; /* Start esp_local_ctrl service */ ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Creating a property¶
Now that we know how to start the esp_local_ctrl service, let’s add a property to it. Each property must have a unique name (string), a type (e.g. enum), flags (bit fields) and size.
The size is to be kept 0, if we want our property value to be of variable length (e.g. if its a string or bytestream). For fixed length property value data-types, like int, float, etc., setting the size field to the right value, helps esp_local_ctrl to perform internal checks on arguments received with write requests.
The interpretation of type and flags fields is totally upto the application, hence they may be used as enumerations, bitfields, or even simple integers. One way is to use type values to classify properties, while flags to specify characteristics of a property.
Here is an example property which is to function as a timestamp. It is assumed that the application defines TYPE_TIMESTAMP and READONLY, which are used for setting the type and flags fields here.
/* Create a timestamp property */ esp_local_ctrl_prop_t timestamp = { .name = "timestamp", .type = TYPE_TIMESTAMP, .size = sizeof(int32_t), .flags = READONLY, .ctx = func_get_time, .ctx_free_fn = NULL }; /* Now register the property */ esp_local_ctrl_add_property(×tamp);
Also notice that there is a ctx field, which is set to point to some custom func_get_time(). This can be used inside the property get / set handlers to retrieve timestamp.
Here is an example of get_prop_values() handler, which is used for retrieving the timestamp.
static esp_err_t get_property_values(size_t props_count, const esp_local_ctrl_prop_t *props, esp_local_ctrl_prop_val_t *prop_values, void *usr_ctx) { for (uint32_t i = 0; i < props_count; i++) { ESP_LOGI(TAG, "Reading %s", props[i].name); if (props[i].type == TYPE_TIMESTAMP) { /* Obtain the timer function from ctx */ int32_t (*func_get_time)(void) = props[i].ctx; /* Use static variable for saving the value. * This is essential because the value has to be * valid even after this function returns. * Alternative is to use dynamic allocation * and set the free_fn field */ static int32_t ts = func_get_time(); prop_values[i].data = &ts; } } return ESP_OK; }
Here is an example of set_prop_values() handler. Notice how we restrict from writing to read-only properties.
static esp_err_t set_property_values(size_t props_count, const esp_local_ctrl_prop_t *props, const esp_local_ctrl_prop_val_t *prop_values, void *usr_ctx) { for (uint32_t i = 0; i < props_count; i++) { if (props[i].flags & READONLY) { ESP_LOGE(TAG, "Cannot write to read-only property %s", props[i].name); return ESP_ERR_INVALID_ARG; } else { ESP_LOGI(TAG, "Setting %s", props[i].name); /* For keeping it simple, lets only log the incoming data */ ESP_LOG_BUFFER_HEX_LEVEL(TAG, prop_values[i].data, prop_values[i].size, ESP_LOG_INFO); } } return ESP_OK; }
For complete example see protocols/esp_local_ctrl
Client Side Implementation¶
The client side implementation will have establish a protocomm session with the device first, over the supported mode of transport, and then send and receive protobuf messages understood by the esp_local_ctrl service. The service will translate these messages into requests and then call the appropriate handlers (set / get). Then, the generated response for each handler is again packed into a protobuf message and transmitted back to the client.
See below the various protobuf messages understood by the esp_local_ctrl service:
- get_prop_count : This should simply return the total number of properties supported by the service
- get_prop_values : This accepts an array of indices and should return the information (name, type, flags) and values of the properties corresponding to those indices
- set_prop_values : This accepts an array of indices and an array of new values, which are used for setting the values of the properties corresponding to the indices
Note that indices may or may not be the same for a property, across multiple sessions. Therefore, the client must only use the names of the properties to uniquely identify them. So, every time a new session is established, the client should first call get_prop_count and then get_prop_values, hence form an index to name mapping for all properties. Now when calling set_prop_values for a set of properties, it must first convert the names to indexes, using the created mapping. As emphasized earlier, the client must refresh the index to name mapping every time a new session is established with the same device.
The various protocomm endpoints provided by esp_local_ctrl are listed below:
Endpoint Name (BLE + GATT Server) | URI (HTTPS Server + mDNS) | Description |
---|---|---|
esp_local_ctrl/version | https://<mdns-hostname>.local/esp_local_ctrl/version | Endpoint used for retrieving version string |
esp_local_ctrl/control | https://<mdns-hostname>.local/esp_local_ctrl/control | Endpoint used for sending / receiving control messages |
API Reference¶
Header File¶
Functions¶
-
const esp_local_ctrl_transport_t *
esp_local_ctrl_get_transport_ble
()¶ Function for obtaining BLE transport mode.
-
const esp_local_ctrl_transport_t *
esp_local_ctrl_get_transport_httpd
()¶ Function for obtaining HTTPD transport mode.
-
esp_err_t
esp_local_ctrl_start
(const esp_local_ctrl_config_t *config)¶ Start local control service.
- Return
- ESP_OK : Success
- ESP_FAIL : Failure
- Parameters
config
: Pointer to configuration structure
-
esp_err_t
esp_local_ctrl_add_property
(const esp_local_ctrl_prop_t *prop)¶ Add a new property.
This adds a new property and allocates internal resources for it. The total number of properties that could be added is limited by configuration option
max_properties
- Return
- ESP_OK : Success
- ESP_FAIL : Failure
- Parameters
prop
: Property description structure
-
esp_err_t
esp_local_ctrl_remove_property
(const char *name)¶ Remove a property.
This finds a property by name, and releases the internal resources which are associated with it.
- Return
- ESP_OK : Success
- ESP_ERR_NOT_FOUND : Failure
- Parameters
name
: Name of the property to remove
-
const esp_local_ctrl_prop_t *
esp_local_ctrl_get_property
(const char *name)¶ Get property description structure by name.
This API may be used to get a property’s context structure
esp_local_ctrl_prop_t
when its name is known- Return
- Pointer to property
- NULL if not found
- Parameters
name
: Name of the property to find
-
esp_err_t
esp_local_ctrl_set_handler
(const char *ep_name, protocomm_req_handler_t handler, void *user_ctx)¶ Register protocomm handler for a custom endpoint.
This API can be called by the application to register a protocomm handler for an endpoint after the local control service has started.
- Note
- In case of BLE transport the names and uuids of all custom endpoints must be provided beforehand as a part of the
protocomm_ble_config_t
structure set inesp_local_ctrl_config_t
, and passed toesp_local_ctrl_start()
. - Return
- ESP_OK : Success
- ESP_FAIL : Failure
- Parameters
ep_name
: Name of the endpointhandler
: Endpoint handler functionuser_ctx
: User data
Unions¶
-
union
esp_local_ctrl_transport_config_t
¶ - #include <esp_local_ctrl.h>
Transport mode (BLE / HTTPD) configuration.
Public Members
-
esp_local_ctrl_transport_config_ble_t *
ble
¶ This is same as
protocomm_ble_config_t
. Seeprotocomm_ble.h
for available configuration parameters.
-
esp_local_ctrl_transport_config_httpd_t *
httpd
¶ This is same as
httpd_ssl_config_t
. Seeesp_https_server.h
for available configuration parameters.
-
esp_local_ctrl_transport_config_ble_t *
Structures¶
-
struct
esp_local_ctrl_prop
¶ Property description data structure, which is to be populated and passed to the
esp_local_ctrl_add_property()
function.Once a property is added, its structure is available for read-only access inside
get_prop_values()
andset_prop_values()
handlers.Public Members
-
char *
name
¶ Unique name of property
-
uint32_t
type
¶ Type of property. This may be set to application defined enums
-
size_t
size
¶ Size of the property value, which:
- if zero, the property can have values of variable size
- if non-zero, the property can have values of fixed size only, therefore, checks are performed internally by esp_local_ctrl when setting the value of such a property
-
uint32_t
flags
¶ Flags set for this property. This could be a bit field. A flag may indicate property behavior, e.g. read-only / constant
-
void *
ctx
¶ Pointer to some context data relevant for this property. This will be available for use inside the
get_prop_values
andset_prop_values
handlers as a part of this property structure. When set, this is valid throughout the lifetime of a property, till either the property is removed or the esp_local_ctrl service is stopped.
-
void (*
ctx_free_fn
)(void *ctx)¶ Function used by esp_local_ctrl to internally free the property context when
esp_local_ctrl_remove_property()
oresp_local_ctrl_stop()
is called.
-
char *
-
struct
esp_local_ctrl_prop_val
¶ Property value data structure. This gets passed to the
get_prop_values()
andset_prop_values()
handlers for the purpose of retrieving or setting the present value of a property.Public Members
-
void *
data
¶ Pointer to memory holding property value
-
size_t
size
¶ Size of property value
-
void (*
free_fn
)(void *data)¶ This may be set by the application in
get_prop_values()
handler to tellesp_local_ctrl
to call this function on the data pointer above, for freeing its resources after sending theget_prop_values
response.
-
void *
-
struct
esp_local_ctrl_handlers
¶ Handlers for receiving and responding to local control commands for getting and setting properties.
Public Members
-
esp_err_t (*
get_prop_values
)(size_t props_count, const esp_local_ctrl_prop_t props[], esp_local_ctrl_prop_val_t prop_values[], void *usr_ctx)¶ Handler function to be implemented for retrieving current values of properties.
- Note
- If any of the properties have fixed sizes, the size field of corresponding element in
prop_values
need to be set - Return
- Returning different error codes will convey the corresponding protocol level errors to the client :
- ESP_OK : Success
- ESP_ERR_INVALID_ARG : InvalidArgument
- ESP_ERR_INVALID_STATE : InvalidProto
- All other error codes : InternalError
- Parameters
props_count
: Total elements in the props arrayprops
: Array of properties, the current values for which have been requested by the clientprop_values
: Array of empty property values, the elements of which need to be populated with the current values of those properties specified by props argumentusr_ctx
: This provides value of theusr_ctx
field ofesp_local_ctrl_handlers_t
structure
-
esp_err_t (*
set_prop_values
)(size_t props_count, const esp_local_ctrl_prop_t props[], const esp_local_ctrl_prop_val_t prop_values[], void *usr_ctx)¶ Handler function to be implemented for changing values of properties.
- Note
- If any of the properties have variable sizes, the size field of the corresponding element in
prop_values
must be checked explicitly before making any assumptions on the size. - Return
- Returning different error codes will convey the corresponding protocol level errors to the client :
- ESP_OK : Success
- ESP_ERR_INVALID_ARG : InvalidArgument
- ESP_ERR_INVALID_STATE : InvalidProto
- All other error codes : InternalError
- Parameters
props_count
: Total elements in the props arrayprops
: Array of properties, the values for which the client requests to changeprop_values
: Array of property values, the elements of which need to be used for updating those properties specified by props argumentusr_ctx
: This provides value of theusr_ctx
field ofesp_local_ctrl_handlers_t
structure
-
void *
usr_ctx
¶ Context pointer to be passed to above handler functions upon invocation. This is different from the property level context, as this is valid throughout the lifetime of the
esp_local_ctrl
service, and freed only when the service is stopped.
-
void (*
usr_ctx_free_fn
)(void *usr_ctx)¶ Pointer to function which will be internally invoked on
usr_ctx
for freeing the context resources whenesp_local_ctrl_stop()
is called.
-
esp_err_t (*
-
struct
esp_local_ctrl_config
¶ Configuration structure to pass to
esp_local_ctrl_start()
Public Members
-
const esp_local_ctrl_transport_t *
transport
¶ Transport layer over which service will be provided
-
esp_local_ctrl_transport_config_t
transport_config
¶ Transport layer over which service will be provided
-
esp_local_ctrl_handlers_t
handlers
¶ Register handlers for responding to get/set requests on properties
-
size_t
max_properties
¶ This limits the number of properties that are available at a time
-
const esp_local_ctrl_transport_t *
Type Definitions¶
-
typedef struct esp_local_ctrl_prop
esp_local_ctrl_prop_t
¶ Property description data structure, which is to be populated and passed to the
esp_local_ctrl_add_property()
function.Once a property is added, its structure is available for read-only access inside
get_prop_values()
andset_prop_values()
handlers.
-
typedef struct esp_local_ctrl_prop_val
esp_local_ctrl_prop_val_t
¶ Property value data structure. This gets passed to the
get_prop_values()
andset_prop_values()
handlers for the purpose of retrieving or setting the present value of a property.
-
typedef struct esp_local_ctrl_handlers
esp_local_ctrl_handlers_t
¶ Handlers for receiving and responding to local control commands for getting and setting properties.
-
typedef struct esp_local_ctrl_transport
esp_local_ctrl_transport_t
¶ Transport mode (BLE / HTTPD) over which the service will be provided.
This is forward declaration of a private structure, implemented internally by
esp_local_ctrl
.
-
typedef struct protocomm_ble_config
esp_local_ctrl_transport_config_ble_t
¶ Configuration for transport mode BLE.
This is a forward declaration for
protocomm_ble_config_t
. To use this, application must set CONFIG_BT_BLUEDROID_ENABLED and includeprotocomm_ble.h
.
-
typedef struct httpd_ssl_config
esp_local_ctrl_transport_config_httpd_t
¶ Configuration for transport mode HTTPD.
This is a forward declaration for
httpd_ssl_config_t
. To use this, application must set CONFIG_ESP_HTTPS_SERVER_ENABLE and includeesp_https_server.h
-
typedef struct esp_local_ctrl_config
esp_local_ctrl_config_t
¶ Configuration structure to pass to
esp_local_ctrl_start()