nRF5 IoT SDK
v0.9.0
|
The IETF draft "draft-ietf-core-observe" defines observable resources. It follows the common observe pattern which has two roles, an observer and an observable. The observer can subscribe to listen for any change in the state of an observable subject. CoAP resources representing a value can be set up to be observable, making the observing clients notified about any change in the state of the value.
smartCoAP defines both Client and Server role by flags in sdk_config.h
. If Server role is enabled, any resource in the resource hierarchy can be enabled to be an observable resource. The resource needs to allow the GET method in order to succeed in registering any observer client.
The code below shows how to set up a resource as an observable resource:
The example shows how the observable_resource is set to be shown as an observable resource. Setting this flag will also automatically trigger with the .well_known_core to generate the ;obs link format option. The configuration of max_age is set to 15 seconds, meaning that it will signal to any observer (client) that the value is valid for 15 seconds at the maximum.
The server can register up to COAP_OBSERVE_MAX_NUM_OBSERVERS number of observers in total. The configuration structure used for registering a new instance will be copied by the coap_observe module. The configuration sets the token used when subscribing to the observable resource. This token value will be used for any notification message sent to the client. It also sets the remote address to the client as well as the content format which the client and the server have agreed upon. The content format might vary between different clients. The handle returned could be kept by the application to unregister the observer later.
The code below shows how to register a new observer to the server:
When the server wants to unregister an observer, it uses its handle value. Either, it has kept the handle in the application or looked it up by a search.
The code below shows how to unregister an observer:
If the handle values are not kept by the application, it would still be possible to retrieve the handle value by searching for it based on the remote address and the resource of interest (pointer to the resource instance).
This could be useful if the client sends an unregistration message by setting its observe option to 1.
The code below shows how to search for an observer:
Sometimes it is handy to iterate through all observers that are subscribed to a given resource. The target could, for example, be to unregister observers if the resource is deleted, or to send notifications to all observers if the value changes. AS the handle would not be enough to send a notification, coap_observe_server_next_get API will return instances one by one, until there are no more observers in the list associated with the given resource.
The code below shows how to iterate through all the observers subscribed to a specific resource:
Based on the handle value, it would be possible to retrieve the observer instance associated with that handle. The instance has to be retrieved by keeping it in the application. Alternatively it can be retrieved by searching for it.
The code below shows how to retrieve the observer instance of a given handle:
The client can register up to COAP_OBSERVE_MAX_NUM_OBSERVABLES number of observable resources in total. The configuration structure used for registering a new instance will be copied by the coap_observe module.
The configuration sets the token to be used when matching the subsequent response messages from the server. It also sets the remote address of the server. The configuration also has to set the max age, in order to figure out when the server has stopped sending notifications, so that it can safely remove the observable resource. Likewise, a notification callback has to be configured so that notifications can be given to the application. The handle returned could be kept by the application to unregister the observable resource later.
The code below shows how to register a new observable resource to the client:
When the client wants to unregister an observable resource, it uses its handle value. Either, it has kept the handle in the application or looked it up by a search.
The code below shows how to unregister an observable resource:
If the handle values are not kept by the application, it would still be possible to retrieve the handle value by searching for it based on the registered token.
The code below shows how to search for an observable resource:
Sometimes it is handy to iterate through all the registered observable resources. The target could, for example, be to unregister an observable resource if the server has stopped sending notifications.
The code below shows how to iterate through all the observable resources registered:
Based on the handle value, it would be possible to retrieve the observable resource instance associated with that handle. The resource has to be retrieved by keeping it in the application. Alternatively it can be retrieved by searching for it.
The code below shows how to retrieve the observable resource instance of a given handle:
When a client sends a GET request with observe option set to 0, the server can choose to register the client as an observer to the resource value located at the URI path defined in the request. The example below demonstrates how the server can register the observer in order to send notifications if the value changes or updating the value before max age is reached. It also shows how to handle an unregistration message from the observing client.
Registration of observable resources is done by matching the response from the server with the request message in the transmission queue internally. If it is a match, it will add the observable resource to handle all subsequent response messages with this token id. On the other hand, if the messages do not arrive within the time of max age time-out, the client will not automatically remove the observable instance. This has to be handled by the application.
The example below demonstrates how the client can iterate through the observable resource and remove the instance if time-out has been reached. The function implemented below should be called continuously every second in order to obtain an approximately correct time-out interval.
The illustration in Figure 1 shows the flow of sending an observe request message from a CoAP client. The message has CoAP observe option set to 0, which indicates its interest in observing the resource defined in the message.
When sending the message with coap_message_send, a call to the coap_observe_client_send_handle function is issued. This is done to peek into the message in case of a cancellation of the subscription.
Next, the message is sent to the remote server and put into the transmission queue to be matched when the response arrives. Then the message from the application can safely be deleted, as all the needed matching parameters are in the transmission queue by now.
When the response arrives, it issues the coap_transport_read callback function in order to be processed by smartCoAP. Depending on the message type of the request message NON/CON, it will look up the queue request in the transmission queue by message id (CON) or token (NON). If the response contained an Observe option, the subscription succeeded. The observable resource will be register, and the response callback from the request will be copied to the observable resource instance for the subsequent response message using the same token.
Before removing the message from the transmission queue the response callback set by the request will be called.
The illustration in figure 2 shows the flow in the server when receiving an observe subscription request from a client.
The message will be processed by coap_transport_read in smartCoAP. If the resource queried is found in the resource hierarchy, it will issue a callback to the resource handler.
The resource handler function is responsible for sending a response message back to the client. It adds a sequence number in the observe option as well as a max age indicating how long the representation of the value is valid.
Last, the response is sent to the application and freed by the application.
The illustration in figure 3 shows how NON and CON notifications are handled by the smartCoAP modules.
If the server sends a NON notification response to the client, the client will receive this in the coap_transport_read function for processing. Before any callback is done, smartCoAP will check if the server has stopped sending the observe option. If so, the observable resource will be removed automatically. In any case, the response_callback function will be looked up and issued.
If the server sends a CON notification response to the client, the client will do the same as for a NON response, but in addition it will automatically send an ACK message back to the server indicating its continuous interest in the notifications from the resource.
The illustration in figure 4 shows how the server loops through the list of observers in order to feed them with an updated representation of the resource value.
The server will iterate through all the observers using the coap_observe_server_next_get API function and create a new message for each client. The loop will be broken when NRF_ERROR_NOT_FOUND is returned by the function. What is shown now is how to generate the correct payload for each client. The payload has to use the content format agreed during registration. How to generate the correct content format is up to the application.
The illustration in figure 5 shows how the client can unregister itself on the remote server. The client can actively discontinue its subscription by sending a new GET request with observe option value set to 1, or it can reply with a RESET message in reply to a NON/CON notification response.
When sending out a new GET request message with observe option value set to 1, the packet is also processed by the internal coap_observe_client_send_handle function. This function will check if the message contains an observe option. If so, check whether it is 1. If the value is 1, smartCoAP will remove the observable resource instance with the token used in the request. Then the request will be sent to the server.
The illustration in figure 6 shows how the server will unregister its observer clients.
At least every 24 hours the notification has to be sent as a CON response message. This is done in order to confirm the client's continuous interest in the observed value. If this CON message is not acknowledged, the server will immediately remove the client from the observer list.
It could also be that the client replies with a RESET message to one of the notifications sent by the server. This will also make the server remove the observer instance from its list.
The following configuration parameters should be defined in sdk_config.h
.
Enable CoAP observe server role. If enabled, the coap_observe module has to be included. It will enable the module with a table to store observers and provide access to functions to register and unregister observers. The list can be traversed in order to send notifications to the observers.
Restriction | Value |
---|---|
Possible values | 0 or 1. |
Dependencies | COAP_OBSERVE_MAX_NUM_OBSERVERS. |
Maximum number of CoAP observers that a server can have active at any point of time. The maximum number of observers to be registered by a server. For each observer added, it will increase the memory consumption of one coap_observer_t struct.
Restriction | Value |
---|---|
Minimum value | 0 |
Maximum value | 255 |
Recommended value | 1 - 10 |
Dependencies | COAP_ENABLE_OBSERVE_SERVER |
Enable CoAP observe client role. If enabled, the coap_observe module has to be included. It will enable the module with a table to store observable resources and provide access to functions to register and unregister observable resources. The observable resources list is used to match incoming notifications to an application callback function.
Restriction | Value |
---|---|
Possible values | 0 or 1. |
Dependencies | COAP_OBSERVE_MAX_NUM_OBSERVABLES. |
Maximum number of CoAP observable resources that a client can have active at any point of time. The maximum number of observable resources to be registered by a client. For each observable resource added, it will increase the memory consumption of one coap_observable_t struct.
Restriction | Value |
---|---|
Minimum value | 0 |
Maximum value | 255 |
Recommended value | 1 - 10 |
Dependencies | COAP_ENABLE_OBSERVE_CLIENT |