class: title, smokescreen, shelf, bottom, no-footer background-image: url(images/coap-arm.png) # 181U Spring 2020 ### IoT Protocols (part 2) --- layout: true .footer[ - Geoffrey Brown, 2020 - 181U ] <style> h1 { border-bottom: 8px solid rgb(32,67,143); border-radius: 2px; width: 90%; } .smokescreen h1 { border-bottom: none; } .small.remark-slide-content.compact {font-size:1.2rem} .smaller.remark-slide-content.compact {font-size:1.1rem} .small-code.remark-slide-content.compact code {font-size:1.0rem} .very-small-code.remark-slide-content.compact code {font-size:0.9rem} .line-numbers{ /* Set "line-numbers-counter" to 0 */ counter-reset: line-numbers-counter; } .line-numbers .remark-code-line::before { /* Increment "line-numbers-counter" by 1 */ counter-increment: line-numbers-counter; content: counter(line-numbers-counter); text-align: right; width: 20px; border-right: 1px solid #aaa; display: inline-block; margin-right: 10px; padding: 0 5px; } </style> --- class: compact # Agenda * MQTT Review * COAP --- class: compact # Ways to exchange messages ![](images/space.png# w-10pct) ![](images/push-pull.png# # w-70pct) --- class:compact # Request/Response * **REST** : Representational State Transfer * Widely used; often based upon HTTP * Today we'll discuss a lighter approach **CoAP** for IoT ![](images/space.png# w-20pct) ![](images/rest.png# w-60pct) --- class: compact # MQTT > MQTT is a machine-to-machine (M2M)/Internet of Things connectivity protocol. > It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote > locations where a small code footprint is required and/or network bandwidth is at a premium. (http://mqtt.org) ![](images/space.png# w-20pct) ![](images/mqtt-flow.png# w-40pct) Figure:http://istsos.org/en/trunk/doc/ws_mqtt.html --- class: compact,small # MQTT works on top of ... * Mainly TCP * There is a closely related protocol MQTT-SN (MQTT for sensor networks) that runs on UDP, but COAP is a UDP protocol that is used more which we will look at. * Websockets can also be used. * Enables embedding in web pages. ![](images/space.png# w-2-12th) ![](images/websockets-mqtt.png# w-70pct) * Both TCP and websockets can operate on top of "transport layer security" (TLS) and SSL. --- class: compact # MQTT Protocol ![](images/MQTT_protocol_example_without_QoS.svg# w-30pct fr) MQTT is connection based. Publishers and Subscribers connect to a broker (using TCP protocol). * In this example, a publisher (client B) regularly updates the current temperature. A subscriber (client A) connects and receives the temperature. * The example illustrates the use of topics -- **temperature/roof** and an optional feature -- retained messages. Simon A. Eugster [<a href="https://creativecommons.org/licenses/by-sa/4.0">CC BY-SA 4.0</a>], <a href="https://commons.wikimedia.org/wiki/File:MQTT_protocol_example_without_QoS.svg">via Wikimedia Commons</a> --- class: compact # MQTT -- but * Use of TCP * implies always on & connected * heavy protocol implementation for lightweight devices * Architecture naturally fits a medium to large network of relatively chunky, stable things * Routing is all based upon subscriptions - no device discovery * Adding things requires significant configuration --- class: compact # CoAP : REST based web of things protocol ![](images/coap-arm.png# w-50pct fr) * Asynchronous Subscription * REST based * Compact message format * UDP messages * Basis of Thread mesh network (later in semester) <br> * Differences with MQTT * MQTT broker is the "server". Publishers (e.g. "things") and Subscribers are clients * CoAP things are all "servers". Clients are applications or gateways that query servers --- class: compact # From Web Applications to IoT Nodes ![](images/space.png# w-10pct) ![](images/webtoiot.png# w-80pct) --- class: compact # HTTP RESTful Transaction ![](images/space.png# w-25pct) ![](images/http-transaction.png# w-50pct) REST(ful) transactions are stateless -- to access a resource, a complete connect/request/disconnect is used. --- class: compact # HTTP RESTful Transaction ![](images/space.png# w-25pct) ![](images/rest-transaction.png# w-50pct) --- class: compact # Resource Constrained Devices ![](images/space.png# w-10pct) ![](images/resource-constrained-devices.png# w-80pct) --- class: compact # Constrained Application Protocol (CoAP) * RESTful protocol designed from scratch * Transparent mapping to HTTP ![](images/coap-layers.png# w-60-pct mr-4 fl) * **GET**, **POST**, **PUT**, **DELETE** * Deduplication with optional retransmissions --- class: compact # What CoAP is (and is not) * CoAP is * A very efficient RESTful protocol * Suitable for constrained devices/networks * Easy to proxy to/from HTTP * CoAP is not * A general replacement for HTTP * HTTP compression --- class: compact # CoAP Features * Embedded web transfer protocol (coap://) * Asynchronous transaction mode * UDP binding * URI support * Simple message format * Discovery mode --- class: compact # Transaction Model ![](images/coap-transaction-model.png# fr) * Transport: CoAP defines * UDP binding with DTLS security * CoAP over SMS or TCP possible * Base Messaging * Simple message exchange between endpoints * Confirmable and non-Confirmable messages * REST Semantics * Request/Response on top of CoAP messages --- class: compact # Constrained Application Protocol (CoAP) ![](images/coap-messages.png# w-60pct, fr) **Binary Protocol** * Low parsing complexity * Small message size **Options** * Numbers with IANA registry * Type-lenght-value * Payload --- class: compact # Request Example ![](images/space.png# w-10pct) ![](images/coap-request-example.png# w-80pct) --- # CoAP Resources * [implementations](http://coap.technology/impls.html) - [c library](https://libcoap.net/) - [go library](https://github.com/dustin/go-coap) - [microcap embedded c library](https://github.com/1248/microcoap) - [lobaro embedded c library](https://github.com/Lobaro/lobaro-coap) * [Protocol cheatsheet](https://github.com/markushx/coap-cheatsheet/blob/master/coap-cheatsheet.pdf) --- class:compact,very-small-code,hljs-tomorrow-night-eighties,col-2 # CoAP Server in Golang ```golang ... import statements elided func handleA(l *net.UDPConn, a *net.UDPAddr, m *coap.Message) *coap.Message { if m.IsConfirmable() { res := &coap.Message{ Type: coap.Acknowledgement, Code: coap.Content, MessageID: m.MessageID, Token: m.Token, Payload: []byte("hello to you!"), } res.SetOption(coap.ContentFormat, coap.TextPlain) return res } return nil } ``` <br> ```golang func handleB(l *net.UDPConn, a *net.UDPAddr, m *coap.Message) *coap.Message { if m.IsConfirmable() { res := &coap.Message{ Type: coap.Acknowledgement, Code: coap.Content, MessageID: m.MessageID, Token: m.Token, Payload: []byte("good bye!"), } res.SetOption(coap.ContentFormat, coap.TextPlain) return res } return nil } func main() { mux := coap.NewServeMux() mux.Handle("/a", coap.FuncHandler(handleA)) mux.Handle("/b", coap.FuncHandler(handleB)) } ``` --- class:compact,very-small-code,hljs-tomorrow-night-eighties,col-2 # CoAP client in go ```golang ... import statements elided func main() { req := coap.Message{ Type: coap.Confirmable, Code: coap.GET, MessageID: 12345, Payload: []byte("hello, world!"), } path := "/some/path" if len(os.Args) > 1 { path = os.Args[1] } req.SetOption(coap.ETag, "weetag") req.SetOption(coap.MaxAge, 3) req.SetPathString(path) c, err := coap.Dial("udp", "localhost:5683") ... error handling ... rv, err := c.Send(req) ... error handling ... } ``` --- class: compact # Dealing With Packet Loss ![](images/space.png# w-10pct) ![](images/coap-packet-loss.png# w-80pct) --- class: compact # Proxying and Caching ![](images/space.png# w-10pct) ![](images/coap-proxy.png# w-80pct) --- class: compact # CoAP Observation * Problem: * REST paradigm is "PULL" * Data may be periodic/triggered (e.g. get temperature sample every two seconds) * Solution * CoAP "observation" --- class: compact # Observing Resources ![](images/space.png# w-10pct) ![](images/coap-observe.png# w-80pct) --- class: compact # CoAP Protocol -- Message Formats * Message Format ```plaintext 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Ver| T | TKL | Code | Message ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Token (if any, TKL bytes) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options (if any) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1 1 1 1 1 1 1 1| Payload (if any) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Ver: Version, T: Type, TKL: Token Length ``` --- class: compact,col-2 # Message Types and Codes ```plaintext +------+-----------------+ | Type | Name | +------+-----------------+ | 0 | CONfirmable | | 1 | NON-confirmable | | 2 | ACKnowledgement | | 3 | ReSeT | +------+-----------------+ ``` ```plaintext +------+--------+ | Code | Name | +------+--------+ | 0.00 | EMPTY | +------+--------+ | 0.01 | GET | | 0.02 | POST | | 0.03 | PUT | | 0.04 | DELETE | +------+--------+ ``` --- class: compact # Example messages ![](images/space.png# w-20pct) ![](images/bitsandbytes.png# w-60pct) --- class: compact # CoAP Specification [RFC7252](https://tools.ietf.org/html/rfc7252) ```plaintext The work on Constrained RESTful Environments (CoRE) aims at realizing the REST architecture in a suitable form for the most constrained nodes (e.g., 8-bit microcontrollers with limited RAM and ROM) and networks (e.g., 6LoWPAN, [RFC4944]). Constrained networks such as 6LoWPAN support the fragmentation of IPv6 packets into small link- layer frames; however, this causes significant reduction in packet delivery probability. One design goal of CoAP has been to keep message overhead small, thus limiting the need for fragmentation. ``` --- class: compact # Issues * Discovery -- how to find servers ? * Semantics -- message payloads are undefined (even the format !) -- this is a problem for MQTT too. * https://sensorup.com/iot/building-iot-apps-how-to-use-open-data-standards/ * https://github.com/opengeospatial/sensorthings --- class: compact # Ikea Home IoT gateway is based on CoAP ![](images/tradfri-1.png# w-50pct fr) The trådfri series provides a number of products for home automation including the following: * Light bulbs of various capabilties (dimming, CIE 1931 color, cold/warm etc.) * Light panels * Power plugs (on/off) * Motion sensors * Electric blinds * Accessories such as remote control, dimming controls * The gateway https://callistaenterprise.se/blogg/teknik/2019/03/15/a-quick-home-automation/ --- class: compact # Reverse Engineering Ikea CoAP API [link](https://learn.pimoroni.com/tutorial/sandyj/controlling-ikea-tradfri-lights-from-your-pi) The endpoints all begin with coaps://192.168.0.10:5684/ followed by either 15001 to control bulbs individually or 15004 to control them as a group. We'll focus on controlling an individual bulb here. The individual bulbs will have addresses beginning at 65537 for the first bulb, 65538 for the second, and so on. So, to control the first bulb, as we will here, you would hit the following endpoint: `coaps://192.168.0.10:5684/15001/65537` Now that we know the endpoint to control that first bulb, we need to structure a payload to send to the endpoint with the coap-client. We'll send a put request to that endpoint to toggle the light off (make sure that it's switched on first, so that we know whether it worked or not!). Here's the payload: `{ "3311": [{ "5850": 0 }] }` --- class: compact # Reverse Engineering Ikea CoAP API The structure of that payload is as follows: the 3311 represents a dimmer and the 5850 is the toggle for on/off, with 0 being off and 1 being on. Let's put that all together into a call to the coap-client that will toggle the light off: `coap-client -m put -u "Client_identity" -k "1a2b3c4d5e6f7g8h" -e '{ "3311": [{ "5850": 0 }] }' "coaps://192.168.0.10:5684/15001/65537"` --- class: compact # Reverse Engineering Ikea CoAP API As well as sending put requests, we can send get requests to query the state of either a single bulb, a group, or the whole shebang. Try the following to query the state of the first bulb that we're controlling: `coap-client -m get -u "Client_identity" -k "1a2b3c4d5e6f7g8h" "coaps://192.168.0.10:5684/15001/65537"` You'll get a response back with a bunch of information, that we won't get into here, but one tidbit is that if you send a payload substituting the 5850 for 5851 and pass in a value of 0 to 254 then you can control the brightness of your bulb, as follows: `coap-client -m put -u "Client_identity" -k "1a2b3c4d5e6f7g8h" -e '{ "3311": [{ "5851": 127 }] }' "coaps://192.168.0.10:5684/15001/65537"` That should set your bulb to 50% brightness. --- class: compact # Summary * Cover Photo: ARM Semiconductor (ARM IoT Tutorial -- Zach Selby) * Acknowledgements -- slide content and images drawn from: * https://github.com/moleike/mqtt-slides * https://www.oasis-open.org/committees/download.php/49205/MQTT-OASIS-Webinar.pdf * http://wireless.ictp.it/school_2019/slides/MQTT_v2.pdf Pietro Manzoni Intro * [ ARM CoAP Tutorial April 30 2014.pdf](https://community.arm.com/docs/DOC-8633) * Hands-on with CoAP https://www.eclipsecon.org/france2014/sites/default/files/slides/Hands-on%20with%20CoAP.pdf