Getting Started with IPWorks IoT CoAP

Requirements: IPWorks IoT

IPWorks IoT is a suite of components aimed at providing lightweight yet fully-featured implementations of protocols used by the Internet of Things. This article focuses specifically on the CoAP component.

CoAP, which stands for "Constrained Application Protocol", is a client/server protocol that allows devices to interact through requests and responses, similar to HTTP. It operates over UDP. The CoAP component provides CoAP client and server implementations based on RFC 7252 and RFC 7641.

This article will discuss how to use the CoAP component in both client mode and server mode.

Contents

Client Mode

To operate the CoAP component in client mode, ensure that the Listening property is disabled (this is the default state). While in client mode, the component can be used to send requests to a CoAP server. It can also be used to observe server-side resources, causing the server to send notifications anytime said resources change.

Sending Requests

To send a request, populate the RequestData, RequestContentFormat, RequestETag, and RequestOptions properties (if necessary, and as applicable), and then call one of the following methods:

  • Get
  • Post
  • Put
  • Delete
  • SendCustomRequest

Once a response is received, the ResponseCode, ResponseData, ResponseContentFormat, ResponseETag, and ResponseOptions properties will be populated, and the RequestComplete event will fire. (If the request times out, the properties are not populated, but the event still fires.)

coap.OnRequestComplete += (s, e) => {
  Console.WriteLine("Request complete!");
  Console.WriteLine(coap.ResponseCode);
};

// Make a GET request to download a picture.
coap.Get("coap://mycoapserver/pictures/animals/cats4.dat?format=png");
// Imaginary function which accepts PNG image data and displays the picture to the user.
showPicture(coap.ResponseDataB);

Observing Resources

To observe a resource, call the StartObserving method. Assuming the server accepts the observer registration request, it will begin sending notifications for the resource anytime it changes. Each change notification will cause the ResponseCode, ResponseData, ResponseContentFormat, ResponseETag, and ResponseOptions properties to be populated, and the Notification event to fire.

To stop observing a resource, either call StopObserving with the same URI value used to call StartObserving, or set the Notification event's StopObserving parameter to True.

coap.OnNotification += (s, e) => {
  // Notifications can arrive out of order; only print to the log if this is the latest one we've received.
  if (e.IsLatest) {
    Console.WriteLine("Received notification for the resource at: " + e.URI);
    Console.WriteLine("New Value: " + coap.ResponseData);
  }
}

// Start observing a temperature sensor's data. Assume temperature values are sent back in text format.
coap.StartObserving("coap://mycoapserver/home/living_room/sensors/temperature?unit=fahrenheit");

// Assume the server accepts the request and starts sending notifications every so often.
// ...
// Later, stop observing the resource.
coap.StopObserving("coap://mycoapserver/home/living_room/sensors/temperature?unit=fahrenheit");

Server Mode

To operate in server mode, set the LocalPort to the port the component should listen on (typically 5683, the standard CoAP port), then enable the Listening property. Each time a request arrives, the RequestData, RequestContentFormat, RequestETag, and RequestOptions properties will be populated, and the Request event will fire.

Responding to Requests

A response can be sent by populating the ResponseCode, ResponseData, ResponseContentFormat, ResponseETag, and ResponseOptions properties as desired before the event finishes.

Alternatively, the Request event's SendResponse parameter can be set to False in order to send a response back later. In this case, the RequestId value from the event should be used to call the SendResponse method later.

coap.OnRequest += (s, e) => {
  // For the purpose of this snippet, assume we only service GET requests, which have a method code of 1.
  if (e.Method == 1) {
    Console.WriteLine("GET request received for URI path: " + e.URIPath + " and URI query params: " + e.URIQuery);
    coap.ResponseCode = "2.05"; // "Content".
    // Imaginary methods that look up the data and content format of the resource based on the URI path and URI query parameters.
    coap.ResponseData = lookupResourceData(e.URIPath, e.URIQuery);
    coap.ResponseContentFormat = lookupResourceContentFormat(e.URIPath, e.URIQuery);
  } else {
    coap.ResponseCode = "4.05"; // "Method Not Allowed".
    coap.ResponseData = "Only GET requests are allowed."; // Include a diagnostic payload.
    coap.ResponseContentFormat = "";
  }
  // Alternatively, this event could simply save the e.RequestId value somewhere, then some other code could fill in the
  // Response* properties and call the SendResponse() method later.
};

coap.OnResponseComplete += (s, e) => {
  Console.WriteLine("Response sent for request with Id " + e.RequestId);
};

Handling Observers

In server mode, the component can also support resource observation. When a client attempts to register itself as an observer of a resource, the Register event will fire; setting this event's Accept parameter to True will cause the component to accept the registration.

To notify clients that a resource has changed, populate the ResponseCode, ResponseData, ResponseContentFormat, ResponseETag, and ResponseOptions properties as desired, and then call the SendNotification method, passing it the URI of a resource that has registered observers.

When a client has unregistered from further change notifications, the Unregistered event will fire.

coap.OnRegister += (s, e) => {
  Console.WriteLine("Client " + e.RemoteHost + ":" + e.RemotePort + " has registered for notifications for the URI " + e.URI);
  // Imaginary method that helps ensure the application keeps track of observed URIs. The component itself maintains the
  // list of observers for each URI, so the application just needs to know that there are observers in the first place.
  observerRegisteredForURI(e.URI);
  e.Accept = true;
};
coap.OnUnregistered += (s, e) => {
  Console.WriteLine("Client " + e.RemoteHost + ":" + e.RemotePort + " has unregistered from notifications for the URI " + e.URI);
  // As above, imaginary method that helps ensure the application keeps track of observed URIs.
  observerUnregisteredForURI(e.URI);
};

// Somewhere else in the application, this sort of code might get called after a resource changes to inform any observers of
// the change. We use another imaginary method here to check if the changed resource is observed, and to get its information.
if (isResourceObserved()) {
  coap.ResponseCode = "2.05"; // "Content".
  coap.ResponseDataB = getResourceContent();
  coap.ResponseContentFormat = getResourceContentFormat();
  coap.SendNotification(getResourceURI());
}

We appreciate your feedback.  If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.