本記事では、クラウド上の FIWARE 基盤に IoT デバイスから測定データを定期的に送信したり、FIWARE 基盤から IoT デバイスを制御したり、する方法を紹介します。
本記事を含め、次の複数の記事から構成されています。
- FIWARE Big Bang と M5Stack による FIWARE 対応 IoT システムの構築
- MQTT に対応した FIWARE 基盤の構築
- MQTT に対応した IoT デバイス (センサ) の作成とセンサ・データの送信
- MQTT に対応した IoT デバイス (アクチュエータ) の作成とデバイス制御
- MQTT の通信チャネルのセキュア化
M5Stack とセンサ・デバイス
温湿度と気圧センサを持つ IoT デバイスを、M5Stack Fire と ENV. III SENSOR Unitを使って作成します。次の写真のように、M5Stack と ENV. III を接続します。
Ultralight 2.0 over MQTT 対応デバイスの作成
次に、M5Stack を IoT デバイスとして動作させるための、ソースコードを GitHub から取得します。
以下のディレクトリにある m5stack_fire_sensor_mqtt.ino がプログラムです。
m5stack_fire/m5stack_fire_sensor_mqtt
プログラム全体
MQTT ベースの Ultralight 2.0 対応デバイスです。プログラムは次のとおりです。一定間隔でセンサからデータを取得し、Ultralight 2.0 のペイロードを作成して、温湿度、気圧の情報を クラウドにある、MQTT Broker の Mosquitto に送信します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
#include <M5Stack.h> #include <PubSubClient.h> #include <WiFi.h> #include "time.h" #include "M5_ENV.h" WiFiClient gWifiClient; PubSubClient gClient(gWifiClient); SHT3X gSht30; QMP6988 gQmp6988; // Configure parameters const char* gEssid = "ESSID"; const char* gPassword = "ESSID_PASSWORD"; const char* gMqttServer = "MOSQUITTO.EXAMPLE.COM"; const char* gMqttUsername = "MQTT_USER"; const char* gMqttPassword = "MQTT_PASSOWRD"; const int gMqttPort = 1883; const String gMqttCientId = "sensor001-"; const char *gMqttTopic = "/izqetq603ovjcqpx627e4eib1u/sensor001/attrs"; const int gInterval = 2 * 1000; // milli seconds #define MSG_MAX_SIZE (100) char msg[MSG_MAX_SIZE]; void setup() { M5.begin(); M5.Power.begin(); M5.Lcd.setTextSize(2); Wire.begin(); gQmp6988.init(); WiFi.mode(WIFI_STA); WiFi.begin(gEssid, gPassword); while (WiFi.status() != WL_CONNECTED) { delay(500); M5.Lcd.print("."); } gClient.setServer(gMqttServer, gMqttPort); configTime(9 * 3600, 0, "ntp.jst.mfeed.ad.jp"); } void loop() { static int count = 0; static unsigned long previous = 0; while (!gClient.connected()) { String clientId = gMqttCientId + String(random(0xffff), HEX); if (!gClient.connect(clientId.c_str(), gMqttUsername, gMqttPassword)) { M5.Lcd.setTextColor(RED, BLACK); M5.Lcd.print("Failed. state="); M5.Lcd.print(gClient.state()); delay(3000); } } gClient.loop(); unsigned long now = millis(); if (now - previous > gInterval) { Serial.println("loop"); previous = now; ++count; struct tm timeinfo; getLocalTime(&timeinfo); float pressure = gQmp6988.calcPressure() / 100; float temperature = 0.0, humidity = 0.0; if (gSht30.get() == 0) { temperature = gSht30.cTemp; humidity = gSht30.humidity; } snprintf(msg, MSG_MAX_SIZE, "d|%04d-%02d-%02dT%02d:%02d:%02d+0000|t|%2.1f|h|%2.1f|p|%2.1f", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, temperature, humidity, pressure ); gClient.publish(gMqttTopic, msg); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextColor(WHITE, BLACK); M5.Lcd.setCursor(0, 0); M5.Lcd.print("Temperature: "); M5.Lcd.setTextColor(GREEN, BLACK); M5.Lcd.print(String(temperature, 1)); M5.Lcd.setTextColor(WHITE, BLACK); M5.Lcd.print("c"); M5.Lcd.setCursor(0, 20); M5.Lcd.print("Humidity: "); M5.Lcd.setTextColor(GREEN, BLACK); M5.Lcd.print(String(humidity, 1)); M5.Lcd.setTextColor(WHITE, BLACK); M5.Lcd.print("%"); M5.Lcd.setCursor(0, 40); M5.Lcd.print("Pressure: "); M5.Lcd.setTextColor(GREEN, BLACK); M5.Lcd.print(String(pressure, 1)); M5.Lcd.setTextColor(WHITE, BLACK); M5.Lcd.print("hPa"); M5.Lcd.setCursor(0, 60); M5.Lcd.print("Send: "); M5.Lcd.setTextColor(GREEN, BLACK); M5.Lcd.println(String(count)); } } |
プログラム中の次の変数に適切な値に変更してください。
const char* gEssid = “ESSID”;
const char* gPassword = “ESSID_PASSWORD”;
const char* gMqttServer = “MOSQUITTO.EXAMPLE.COM”;
const char* gMqttUsername = “MQTT_USER”;
const char* gMqttPassword = “MQTT_PASSOWRD”;
MQTT サーバとユーザ名、パスワードは、FIWARE Big Bang をインストールしたディレクトリで、make mqtt コマンドを実行すると確認できます。
1 2 3 4 5 6 7 8 9 |
$ make mqtt ./config/script/mqtt.sh MOSQUITTO=mosquitto.big-bang.letsfiware.jp MQTT_USERNAME=fiware MQTT_PASSWORD=OHUvmoB7ai7e5QDq MQTT_1883=true MQTT_TLS=true MQTT_PORT=1883 MQTT_TLS_PORT=8883 |
プログラムの解説
WiFi 接続
WiFi の初期化は、setup() 関数で行います。WiFi のモードを指定して、ESSID と パスワードを指定して開始します。そして、接続が確立するまで待ち合せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <WiFi.h> WiFiClient gWifiClient; const char* gEssid = "ESSID"; const char* gPassword = "ESSID_PASSWORD"; void setup() { WiFi.mode(WIFI_STA); WiFi.begin(gEssid, gPassword); while (WiFi.status() != WL_CONNECTED) { delay(500); } } |
時刻の設定
センサの測定データの送信時に、測定時刻も送信します。このため、現在時刻を取得できるよう設定を行います。setup() 関数で、configTime() 関数を使用して、NTP サーバに接続して、時刻を合わせます。loop () 関数では、getLocalTime () 関数を使用して、現在時刻を取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <time.h> void setup() { configTime(9 * 3600, 0, "ntp.jst.mfeed.ad.jp"); } void loop() { struct tm timeinfo; getLocalTime(&timeinfo); } |
センサの測定値の取得
ENV. III SENSOR Unit から、温湿度と気圧の測定値を取得します。setup() 関数でセンサを初期化して、loop() 関数で測定値を取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "M5_ENV.h" SHT3X gSht30; QMP6988 gQmp6988; void setup() { Wire.begin(); gQmp6988.init(); } void loop() { float pressure = gQmp6988.calcPressure() / 100; float temperature = 0.0, humidity = 0.0; if (gSht30.get() == 0) { temperature = gSht30.cTemp; humidity = gSht30.humidity; } } |
MQTT の設定と処理
MQTT には、Arduino Client for MQTT を使用します。
MQTT は、WiFi ネットワークを使用するため、WiFiClient クラスのオブジェクトを指定して、PubSubClient のオブジェクトをグローバル変数として作成します。
setup() 関数では、PubSubClient オブジェクトの接続先の MQTT Broker のアドレスとポートを指定します。
loop() 関数では、MQTT Broker への接続状況を確認し、未接続の場合は再接続を行います。また、センサの測定値と現在時刻から Ultralight 2.0 形式のメッセージを作成して、MQTT Broker にパブリッシュします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <PubSubClient.h> PubSubClient gClient(gWifiClient); const char* gMqttServer = "MOSQUITTO.EXAMPLE.COM"; const char* gMqttUsername = "MQTT_USER"; const char* gMqttPassword = "MQTT_PASSOWRD"; const int gMqttPort = 1883; const String gMqttCientId = "actuator001"; const char *gMqttTopicCmd = "/izqetq603ovjcqpx627e4eib1u/actuator001/cmd"; const char *gMqttTopicCmdExe = "/ul/izqetq603ovjcqpx627e4eib1u/actuator001/cmdexe"; #define MSG_MAX_SIZE (100) char msg[MSG_MAX_SIZE]; void callback(char* topic, byte* payload, unsigned int length); void setup() { gClient.setServer(gMqttServer, gMqttPort); } void loop() { while (!gClient.connected()) { String clientId = gMqttCientId + String(random(0xffff), HEX); if (!gClient.connect(clientId.c_str(), gMqttUsername, gMqttPassword)) { delay(3000); } } gClient.loop(); snprintf(msg, MSG_MAX_SIZE, "d|%04d-%02d-%02dT%02d:%02d:%02d+0000|t|%2.1f|h|%2.1f|p|%2.1f", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, temperature, humidity, pressure ); gClient.publish(gMqttTopic, msg); } |
プログラムのビルド
プログラムのビルドとM5Stackへの書き込みは、Arduino IDE を使用します。事前にボードマネージャとライブラリの導入と設定を行ってください。
項目 | 値 |
Board manager URL
|
https://dl.espressif.com/dl/package_esp32_index.json |
Board manager
|
esp32 by Espressif Systems 2.0.6
|
Board
|
M5Stack-FIRE
|
Library manager |
M5Stack by M5Stack version 0.4.3
|
IoT Agentの設定
IoT Agent を設定するコマンドを GitHub から取得します。
一連のコマンドは次のディレクトリにあります。
script/sensor
環境変数の設定
スクリプトの実行には、次の環境変数の設定が必要です。FIWARE Big Bang をインストールしたディレクトリに、.env ファイルがあります。このファイルのスクリプトのディレクトリにコピーしてください。
ORION=orion.big-bang.letsfiware.jp
IOTAGENT_UL=iotagent-ul.big-bang.letsfiware.jp
IOTA_UL_DEFAULT_RESOURCE=/iot/ul
MOSQUITTO=mosquitto.big-bang.letsfiware.jp
MQTT_USERNAME=fiware
MQTT_PASSWORD=OHUvmoB7ai7e5QDq
MQTT_1883=true
MQTT_TLS=true
MQTT_PORT=1883
MQTT_TLS_PORT=8883
IoT Agent の正常性を確認
IoT Agent のバージョン取得を実行して、正しくデプロイされたことを確認します。IoT Agent の場合、以下のクエリで正常性を確認できます。
GET /iot/about
次のコマンドを実行して、レスポンスが返ってくることを確認してください。
./01.version.sh
結果
1 2 3 4 5 6 |
{ "libVersion": "2.24.0", "port": "4041", "baseRoot": "/", "version": "1.24.0" } |
サービス・グループのプロビジョニング
IoT 対応デバイスを IoT Agent に登録します。このため、最初にサービス・グループをプロビジョニングし、次にデバイスをプロビジョニングします。次のようなクエリを IoT Agent に POST することで、サービス・グループのプロビジョニングができます。
POST /services
1 2 3 4 5 |
ngsi services --host "${IOTAGENT_UL}" \ create --apikey izqetq603ovjcqpx627e4eib1u \ --type Thing \ --resource "${IOTA_UL_DEFAULT_RESOURCE}" \ --cbroker http://orion:1026 |
のコマンドを実行して、サービス・グループをプロビジョニングしてください。プロビジョニングされたサービス・グループの一覧が表示できます。
./02.create-service.sh
デバイスのプロビジョニング
サービス・グループのプロビジョニング後に、デバイスのプロビジョニングを行います。デバイスが複数台ある場合は、デバイスごとに実施します。次のようなクエリで、動的な属性値として、温度、湿度、気圧、取得時刻を、静的な属性値として位置情報をもつデバイスとして、Ultralight 2.0-MQTT 対応デバイスをプロビジョニングできます。
POST /iot/devices
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/bin/sh ngsi devices --host "${IOTAGENT_UL}" create --data '{ "devices": [ { "device_id": "sensor001", "entity_name": "urn:ngsi-ld:WeatherObserved:sensor001", "entity_type": "Sensor", "timezone": "Asia/Tokyo", "protocol": "PDI-IoTA-UltraLight", "transport": "MQTT", "attributes": [ { "object_id": "d", "name": "dateObserved", "type": "DateTime" }, { "object_id": "t", "name": "temperature", "type": "Number" }, { "object_id": "h", "name": "relativeHumidity", "type": "Number" }, { "object_id": "p", "name": "atmosphericPressure", "type": "Number" } ], "static_attributes": [ { "name":"location", "type": "geo:json", "value" : { "type": "Point", "coordinates" : [ 139.7671, 35.68117 ] } } ] } ] }' |
次のコマンドを実行して、Ultralight 2.0-MQTT 対応デバイスをプロビジョニングしてください。
./03.create-deivce.sh
センサデータの送信
サーバ環境の作成、サービスとデバイスのプロビジョニングが完了したら、M5Stack を起動してください。2秒ことに、クラウドにある FIWARE 基盤に温湿度と気圧情報を送信します。
エンティティの確認
Orion に対して次のようなクエリを実行して、エンティティ urn:ngsi-ld:WeatherObserved:sensor001 のコンテキスト情報が更新されているかを確認します。
GET /v2/entities/urn:ngsi-ld:WeatherObserved:sensor001
次のコマンドを実行して、コンテキスト情報を確認します。
./06.get-entity.sh
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
{ "id": "urn:ngsi-ld:WeatherObserved:sensor001", "type": "Sensor", "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z", "metadata": {} }, "atmosphericPressure": { "type": "Number", "value": 999.8, "metadata": { "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z" } } }, "dateObserved": { "type": "DateTime", "value": "2023-01-14T11:38:03.000Z", "metadata": { "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z" } } }, "location": { "type": "geo:json", "value": { "type": "Point", "coordinates": [ 139.7671, 35.68117 ] }, "metadata": { "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z" } } }, "relativeHumidity": { "type": "Number", "value": 42.6, "metadata": { "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z" } } }, "temperature": { "type": "Number", "value": 21.3, "metadata": { "TimeInstant": { "type": "DateTime", "value": "2023-01-14T02:38:03.875Z" } } } } |
次のステップ
次のステップでは、アクチュエータとなる IoT デバイスを作成して、クラウドの FIWARE 基盤からデバイスを制御します。