IoTサービスのラベル取得(VPN) (M5Stack)
サンプルソースコード
概要
IIJ IoTの「ラベル機能」を使用してみます。
前回のサンプル に対して、ラベル機能を使用するような機能追加をしています。
特定のラベルが設定されていた場合は、そのラベルの値を取得し、その数値を使ってデータ送信間隔を変更します。
つまり、ラベル機能を使ってサーバーからクライアント側に向けて指示を出すようなイメージです。
ソースコード
m5stack_iijiot_vpn_label.ino
#include <M5Stack.h> #include <WiFi.h> #include <HTTPClient.h> #include <ArduinoJson.h> #include <WireGuard-ESP32.h> #include "lwip/dns.h" //--- TODO: WI-Fiルーターの SSIDとパスワードを指定してください const char* ssid = "YOUR_SSID"; const char* pass = "YOUR_PASSWORD"; //--- //--- TODO: 自身のVPNアクセスの設定に書き換えてください。 const IPAddress local_ip(10, 10, 10, 10); //IPアドレス const char public_key[] = "YOUR PUBLIC KEY"; //公開鍵 const char private_key[] = "YOUR PRIVATE KEY"; //秘密鍵 const char endpoint_address[] = "vgw001.to.iot.iij.jp"; //接続先アドレス const int endpoint_port = 9999; //接続先ポート番号 //--- const char* iij_iot_uri = "http://gw.iot.iij.jp/v1"; const char* iij_iot_label_uri = "http://gw.iot.iij.jp/v1/dvc-state/json/label-contents"; const char* sec_label_name = "delay_sec"; int delay_sec = 60; static WireGuard wg; /* setup関数 */ void setup() { //M5Stackを初期化 M5.begin(); M5.Power.begin(); //Wi-Fi接続 WiFi.begin(ssid, pass); M5.Lcd.printf("Waiting connect to WiFi: %s ", ssid); while(WiFi.status() != WL_CONNECTED) { //接続完了まで待つ delay(1000); M5.Lcd.print("."); } //接続完了したらIPアドレスとMacアドレスを表示する M5.Lcd.println("\nWiFi connected"); M5.Lcd.print("IP address: "); M5.Lcd.println(WiFi.localIP()); M5.Lcd.print("MAC address:"); M5.Lcd.println(WiFi.macAddress()); delay(500); //現在時刻をセット M5.Lcd.println("Adjusting system time..."); configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); delay(2000); //WireGuardでVPN接続する M5.Lcd.println("Initializing WireGuard..."); if (wg.begin( local_ip, private_key, endpoint_address, public_key, endpoint_port)) { M5.Lcd.println("VPN connected."); //--- DNS参照先をVPN側に向ける ip_addr_t dnsserver = IPADDR4_INIT_BYTES(10, 64, 2, 11); dns_setserver(0, &dnsserver); } else { M5.Lcd.println("WireGuard initializing Failed."); } delay(3000); } /* IIJ IoTサービスにデータ送信する 引数 const char* ns : 送信する namespace値 const char* name : 送信する name値 const double value : 送信する value値 戻り値 bool true:送信成功 false:送信失敗 */ bool send_data(const char* ns, const char* name, const double value) { //JSONオブジェクトを作成 StaticJsonDocument<JSON_OBJECT_SIZE(3)> body; if (ns != nullptr && strlen(ns) > 0) { body["namespace"] = ns; } body["name"] = name; body["value"] = value; //JSONを文字列に変換 String body_string; serializeJson(body, body_string); //JSON文字列をIIJ IoTサービスにPOST HTTPClient http; http.begin(iij_iot_uri); http.addHeader("Content-type", "application/json"); int status_code = http.POST(body_string); http.end(); return status_code >= 200 && status_code < 300; } /* IIJ IoTサービスに設定されているラベルのJSON文字列を取得する 引数 String& labels : 取得したラベル文字列を格納するString参照 戻り値 String labelsを返す */ String get_label_string(String& labels) { HTTPClient c; c.begin(iij_iot_label_uri); int status_code = c.GET(); if(status_code == 200) { labels = c.getString(); } else { labels = "{}"; } c.end(); return labels; } /* ラベルJSON文字列内から、keyに対応する値を返す 引数 const String& labels : 取得したラベル文字列を格納するString参照 const char* key : 値を取得するkey char* value : 取得した値(文字列)を格納する変数 size_t size : value配列のサイズ 戻り値 char* valueを返す */ char* get_label(const String& labels, const char* key, char* value, size_t size) { //ラベルのJSON文字列を解析する DynamicJsonDocument root(labels.length() * 3); deserializeJson(root, labels); //ラベルJSON内から、keyの値を取得する(keyが存在しない場合は空文字列) const char* src = root[key]; memset(value, '\0', size); if(src != nullptr) { strncpy(value, src, size-1); } //value値を返す return value; } /* IIJ IoTからラベルを取得し、keyに対応する値を返す 引数 const char* key : 値を取得するkey char* value : 取得した値(文字列)を格納する変数 size_t size : value配列のサイズ 戻り値 char* valueを返す */ char* get_label(const char* key, char* value, size_t size) { // IIJ IoTからラベルを取得する String labels; get_label_string(labels); // 値を取得する return get_label(labels, key, value, size); } /* loop関数 */ void loop() { //CPU温度を取得 float temp = temperatureRead(); //データ送信 if (send_data("M5Stack", "temperature", temp)) { M5.Lcd.printf("data send OK: temp=%f \n", temp); } else { M5.Lcd.println("data send NG."); } //ラベル取得 char value[32]; get_label(sec_label_name, value, sizeof(value)); int sec = String(value).toInt(); //"delay_sec"のラベルが存在したら、送信間隔の時間をそのラベル値の数値に変更する if (sec > 0 && sec != delay_sec ) { delay_sec = sec; M5.Lcd.printf("update delay: %d sec.\n", delay_sec); } //待つ delay(delay_sec * 1000); }
実行結果
IoTサービスのコントロールパネルから、ラベルを設定することで、送信間隔を変更することができます。
コントロールパネルの左側メニューから「デバイス」を選択し、続いて一覧の中から使用している「VPN」を選択し、画面上の「編集」ボタンをクリックします。
表示された画面から、ラベル名に delay_sec
、値に適当な数値を入力し、保存します。
M5Stack側で、設定したラベル値が読み込まれ、送信間隔が変更されます。
ラベル値に 30 と設定した場合は、下記の写真の通り「update delay: 30 sec」と表示され、次回以降は30秒間隔でデータ送信されます。
各種情報へのリンク
IIJ IoTサービスマニュアル
M5Stack
WireGuard-ESP32-Arduino
ArduinoJson