そういや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はクライアント&サーバーとしての役割があるから、単体で動作させることが出来るというのが大きな違いかな。
