本記事では、クラウド上の 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 基盤からデバイスを制御します。

 
											 
							
							
							
															 
							
							
							
															 
										
					


