そういやCoAPについて何も書いてなかったな…と思って書いておくことに。
CoAP(RFC7252)で定義されているUDPベースのプロトコルで、MQTTと同じくIoT/M2M向けの軽量版みたいな感じ。
ググればRFC/Wikipediaとかに詳しい説明があるから、そっちを見て貰った方が早いと思われ。MQTTとの比較はこんな感じ。
■ Simple Coap Library
このシンプルな実装を何年か前に作って公開している。ArduinoやPlatformIOで”CoAP”で検索すると出てくる、Simple Coap Libraryというもので。シンプルという名の通り、ライブラリのサイズ・実装も非常に軽量なものにしている。
一応動作するのは、Ardiuno物、ESP8266、ESP32、Particleといった環境での動作確認をしている。少し改造すれば、まぁ何でも動くと思われ。

このCoAPだけど、見事なほどまで人気が無いと個人的には思っている。MQTTとかはよく見るし、Google/AWS/AzureのIoT向けサービスもMQTTに対応している。ただ、CoAPに対応している物は数少ない。MQTT(TCP)、CoAP(UDP)とあるにも関わらず。CoAP over TCP/TLS/WebSocket(RFC 8323)という、TCP上に実装した物や、DTLS(TLSのUDP版みたいなもの)上に実装したりセキュリティには配慮していたりするのだけど。
個人的にCoAPの良いと思う点は、
・UDPで軽い
・HTTP Likeでとっつきやすい
・ノード間通信を意識している
このあたりかな。まぁ、こういう選択肢もあるよ、くらいな感じで使う感じだとは思っている。
■ サンプルコード
ESP32向けのサンプルコードはこんな感じ。githubにあるサンプルそのまんま、UDP サーバー・クライアントとして動作する。もちろん、クライアントだけで動作させてもOK。
#include <WiFi.h> #include <WiFiUdp.h> #include <coap-simple.h> // WiFi接続用 const char* ssid = "your-ssid"; const char* password = "your-password"; // デフォルトコールバック用関数 void callback_response(CoapPacket &packet, IPAddress ip, int port); // endpoint(/light)に対するコールバック用関数 void callback_light(CoapPacket &packet, IPAddress ip, int port); // UDPとCoAPクラスの定義 WiFiUDP udp; Coap coap(udp); // Lチカ用の状態 bool LEDSTATE; // endpoint(/light)に対するコールバック用関数 // LEDのON/OFFに対応する void callback_light(CoapPacket &packet, IPAddress ip, int port) { char p[packet.payloadlen + 1]; memcpy(p, packet.payload, packet.payloadlen); p[packet.payloadlen] = NULL; String message(p); if (message.equals("0")) LEDSTATE = false; else if(message.equals("1")) LEDSTATE = true; // 状態によってLEDをON/OFFして、応答パケットを返送 if (LEDSTATE) { digitalWrite(9, HIGH) ; coap.sendResponse(ip, port, packet.messageid, "1"); } else { digitalWrite(9, LOW) ; coap.sendResponse(ip, port, packet.messageid, "0"); } } // デフォルトのコールバック。CoAPのプロトコルをハンドリングする。 void callback_response(CoapPacket &packet, IPAddress ip, int port) { Serial.println("[Coap Response got]"); char p[packet.payloadlen + 1]; memcpy(p, packet.payload, packet.payloadlen); p[packet.payloadlen] = NULL; Serial.println(p); } void setup() { Serial.begin(9600); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Lチカ用の状態 pinMode(9, OUTPUT); digitalWrite(9, HIGH); LEDSTATE = true; // エンドポイント(/light)に対応するコールバック登録 coap.server(callback_light, "light"); // デフォルトのコールバックを登録 coap.response(callback_response); // CoAPの起動 coap.start(); } void loop() { delay(1000); coap.loop(); }
URIのコールバック用の関数を登録して動かすだけ。登録以外のURLにパケットが来た場合はデフォルトコールバックが動作する(コールバックを登録していないとパケットを無視する)。例えば…
coap.server(callback_light, "light"); coap.server(callback_light_state, "light/state"); coap.server(callback_light_hogehoge, "light/hogehoge");
こんな感じで複数登録して、そのURIに来たリクエストをハンドリングすることが出来る。クライアントだけで動作させたい場合は、次の関数を用意している。
coap.get(IPAddress(XXX, XXX, XXX, XXX), 5683, "time"); coap.put(IPAddress(XXX, XXX, XXX, XXX), 5683, "light", "1");
PUT/GETに対応した関数で、[IPアドレス、ポート番号、endpoint(time/)、value(PUTする時)] を投げることが出来る。CoAPサーバー(UDPサーバ)としての動作と、クライアント単体としての動作のどちらでも動かせる感じ。
Simple CoAP Libraryという名前の通り、シンプルな動作でProxyとしての動作、DELETEや他のHTTPメソッドについては実装していない。もしその手の動作をさせたい場合は、デフォルトコールバック関数で自分でやれば良いんじゃね?基本的なPUT/GETで十分でしょ、と思っていたりする。
MQTTをこの手のデバイスで使う時は、サーバーが必要になるけど、CoAPはクライアント&サーバーとしての役割があるから、単体で動作させることが出来るというのが大きな違いかな。