CoAP Client
The coap_client component lets you send CoAP (RFC7252) GET/POST requests to remote CoAP servers.
# Example configuration entry
coap_client:Overview
The CoAP Client component allows an ESPHome device to send CoAP messages to remote CoAP servers over UDP.
This is useful for integrating ESPHome devices with:
- Constrained IoT devices/sensors
- CoAP-enabled home automation systems
- Local microcontrollers using lightweight UDP messaging
- Any endpoint that exposes CoAP resources (GET/POST/etc.)
This component uses libCoap via espressif/coap. Please refer to the links for all license requirements
This component provides an easy YAML interface and Actions usable from automations and lambda blocks.
Configuration variables
- id (Optional, ID): Manually specify the ID used for code generation.
- max_block_size (Optional, bytes): Maximum size of payload for a given datagram packet. Packet size is larger since it includes the header. Maxium value is 1024B, defaults to 512B.
- request_timeout (Optional, duration): Time client will block while waiting for response within the processing thread, defaults to 2 seconds.
- ack_timeout (Optional, duration): The initial number of seconds to wait for an acknowledgment (ACK) or a response to a Confirmable (CON) message,defaults to 2 seconds.
- max_retransmit (Optional, integers): The maximum number of times a Confirmable message is retransmitted before the library stops sending it and signals a failure, defaults to 4 attempts.
Actions
The coap_client component supports a number of actions that can be used to send coap requests.
coap_client.get Action
This action sends a GET Request. Providing a request_name allows the later use of stop (when observe = true), resume (observe = true), and remove. If you send again to the same request_name, then the stored request is overwritten and the CoAP Session is reused. It is the responsibility of the caller to ensure the url does not change scheme or destination and that the resource does not require a different credential requirement.
If request_name is not provided, a temporary name is assigned and the request is deleted from storage after timeout or response. In the case of observe=true, the request is stored until timeout or stop action with pause = false.
on_...:
then:
- coap_client.get:
url: coap://example-server.com/test
# Short form
- coap_client.get: coap://example-server.com/testConfiguration variables
- url (Required, string, templatable): URL to which to send the Request.
- request_name (Optional, string): Name the request, usable when removing the observe Request.
- capture_response (Optional, boolean): when set to
true, the response data will be captured and placed into thepayloadvariable as astd::stringfor use in lambdas. Defaults tofalse. - response_timeout (Optional, duration): Time client will wait for a response before removing the request. Defaults to 4 seconds.
- observe (Optional, boolean): when set to
trueand url points to an observable resource, the system will continue to accept responses - max_response_buffer_size (Optional, integer): The maximum buffer size to be used to store the response. Defaults to
1 kB. - on_response (Optional, Automation): An automation to perform after the Request is received.
- on_error (Optional, Automation): An automation to perform if the Request cannot be completed.
coap_client.post Action
This action sends a POST Request.
on_...:
then:
- coap_client.post:
request_name: "post example"
url: coap://example-server.com/test
payload:"this is a post"
# Short form
- coap_client.post: CoAPs://esphome.ioConfiguration variables
- media_type (*Optional, string): Type of payload sent, defaults to text/plain or application/json.
- payload (Optional, string, templatable): A CoAP payload string to send with Request.
- json (Optional, mapping): A CoAP payload in JSON format. Values are templatable.
- All other options from
coap_client.getAction.
coap_client.send Action
This action sends a Request.
on_...:
then:
- coap_client.send:
request_name: "send example"
method: PUT
media_type: "application/json"
url: coap://example-server.com/testConfiguration variables
- method (Required, string): CoAP method to use (
GET,POST,PUT,DELETE,FETCH,PATCH,IPATCH). - All other options from
coap_client.postAction andcoap_client.getAction.
coap_client.stop Action
This action stops an observe Request
on_...:
then:
- coap_client.stop:
request_name: "Test Observe"
# keep in storage
pause: true
# Short form
- coap_client.stop: "Test Observe"Configuration variables
- request_name (Required, string): Name the request, usable when removing the observe Request.
- pause (Optional, bool): if true, keep request in storage for future resume or send. Defaults to True
coap_client.resume Action
This action resumes an observe Request that was pause=true when stopped.
on_...:
then:
- coap_client.resume:
request_name: "Test Observe"
# Short form
- coap_client.resume: "Test Observe"Configuration variables
- request_name (Required, string): Name the request, usable when removing the observe Request. If not provided, then all observe requests are removed.
coap_client.remove Action
This action removes a stored request, if request is observe=true, then it must be stopped prior to remove.
on_...:
then:
- coap_client.remove:
request_name: "Test Observe"
# Short form
- coap_client.remove: "Test Observe"Configuration variables
- request_name (Required, string): Name the request, usable when removing the observe Request. If not provided, then all observe requests are removed.
Triggers
on_response Trigger
This automation will be triggered when the CoAP Client is complete. If the Request had observe set to true and the server resource was observable, then it will keep responding on a schedule defined by the server.
The following variables are available for use in lambdas:
responseas a pointer toCoapResponseStatisticsobject which containscontent_length,status_codeand `duration_ms``.request_nameas std::string, an unique number as a std::string is provided when no request_name is configured.payloadasstd::stringwhich contains the response payload whencapture_response(seecoap_client.getAction) is set totrue.
ℹ️ Note
The
status_codeshould be checked before using thepayloadvariable. A successful response will have a status code in the200's. Server errors such as “not found” (404) or “internal server error” (500) will have an appropriate status code, and may contain an error message in thepayloadvariable.
on_...:
then:
- delay: 5 sec
- coap_client.get:
request_name: "Test Observe"
url: coap://example-server.com/obs
capture_response: true
response_timeout: 10sec
observe: true
on_response:
then:
- logger.log:
format: '%s Response status: %d, Duration: %u ms, %s'
args:
- request_name.c_str()
- response->status_code
- response->duration_ms
- payload.c_str()POST Payload in JSON format (syntax 1)
Note: all values of the map must be strings. It is not possible to send JSON boolean or numbers with this
syntax.
on_...:
- coap_client.post:
url: coap://example-server.com/test
json:
key: !lambda |-
return id(my_sensor).state;
greeting: "Hello World"
# Will send:
# {"key": "42.0", "greeting": "Hello World"}POST Payload in JSON format (syntax 2)
Note: use this syntax to send boolean or numbers in JSON.
The JSON message will be constructed using the ArduinoJson library.
In the json option you have access to a root object which represents the base object of the JSON message. You
can assign values to keys by using the root["KEY_NAME"] = VALUE; syntax as shown below.
on_...:
- coap_client.post:
url: coap://example-server.com/test
json: |-
root["key"] = id(my_sensor).state;
root["greeting"] = "Hello World";
# Will send:
# {"key": 42.0, "greeting": "Hello World"}GET values from a JSON payload response
If you want to retrieve the value for the vol key and assign it to a template sensor or number component whose id is set to player_volume you can do this, but note that checking for the presence of the key will prevent difficult-to-read error messages:
This example assumes that the server returns a response as a JSON object similar to this:
{"status":"play","vol":"42","mute":"0"}
If you want to retrieve the value for the vol key and assign it to a template sensor or number component
whose id is set to player_volume :
on_...:
- coap_client.get:
url: coap://example-server.com/test
capture_response: true
on_response:
then:
- if:
condition:
lambda: return response->status_code == 205;
then:
- lambda: |-
json::parse_json(payload, [](JsonObject root) -> bool {
if (root["vol"]) {
id(player_volume).publish_state(root["vol"]);
return true;
}
else {
ESP_LOGI(TAG,"No 'vol' key in this json!");
return false;
}
});
else:
- logger.log:
format: "Error: Response status: %d, message %s"
args: [ 'response->status_code', 'payload.c_str()' ]Programatic Integration
Example code for usage within another component
//unique_ptr is required
std::unique_ptr<CoapClientRequestData> tx_request = std::make_unique<CoapClientRequestData>();
tx_request->name = this->request_name;
tx_request->method = CoapMethod::POST
tx_request->uri = this->url;
tx_request->callback = callback;
tx_request->callback_context = this;
tx_request->media_type = CoapMediaType::TEXT_PLAIN;
tx_request->payload = this->payload;
tx_request->response_timeout = this->response_timeout;
tx_request->observe = this->observe;
global_coap_client->process_request(std::move(tx_request)); // Move is required!
Create a callback for the response information
- response_code - 205 is good!, anything outside of 200’s is an error. 0 is response timeout.
- data - payload returned.
- len - of the data.
- offset - in case the data is returned in blocks.
- total - isn’t trustworthy till last block when len + offset = total.
- context - the provided callback_context.
If len, offset, and total are all 0 when there is a response timeout or other response error. if response is in blocks, then your code is responsible for assembly.
static void callback(uint16_t response_code, const unsigned char *data, size_t len, size_t offset, size_t total, void *context) {
\\... Your Code Here
}