IoTサービスのラベル取得 (M5Stamp PICO + CAT-M Module)
サンプルソースコード
概要
IIJ IoTの「ラベル機能」を使用してみます。
前回のサンプル に対して、ラベル機能を使用するような機能追加をしています。
特定のラベルが設定されていた場合は、そのラベルの値を取得し、その数値を使ってデータ送信間隔を変更します。
つまり、ラベル機能を使ってサーバーからクライアント側に向けて指示を出すようなイメージです。
ソースコード
m5stamp_iijiot_label.ino
#define TINY_GSM_MODEM_SIM7080 //#define TINY_GSM_DEBUG Serial #define SerialMon Serial #define SerialAT Serial1 #include <TinyGsmClient.h> #include <ArduinoHttpClient.h> #include <ArduinoJson.h> //--- TODO: 使用するSIMのAPN情報に書き換えてください。 const char apn[] = "iot.iijmobile.jp"; // "h.iijmobile.biz"; const char lte_user[] = "mobile@iot"; const char lte_pass[] = "iot"; //--- const int rx_pin = 18; const int tx_pin = 19; const char* iij_iot_host = "gw.iot.iij.jp"; const int iij_iot_port = 80; const char* iij_iot_path = "/v1"; const char* iij_iot_label_path = "/v1/dvc-state/json/label-contents"; const char* sec_label_name = "delay_sec"; //Global TinyGsm modem(SerialAT); TinyGsmClient client(modem); int sleep_sec = 60; /* setup関数 */ void setup() { delay(500); SerialMon.begin(115200); SerialAT.begin(115200, SERIAL_8N1, rx_pin, tx_pin); delay(3000); SerialMon.println("Wait..."); //モデム初期化 SerialMon.println("Initializing modem..."); modem.init(); String modemInfo = modem.getModemInfo(); SerialMon.println("Modem Info: " + modemInfo); //接続 SerialMon.println("Connecting to "+ String(apn)); while (!modem.gprsConnect(apn, lte_user, lte_pass)) { SerialMon.println("NG."); delay(10000); SerialMon.println("retry"); } SerialMon.println("OK."); //接続まち SerialMon.print("Waiting for network..."); if (!modem.waitForNetwork()) { SerialMon.println(" fail"); delay(10000); return; } SerialMon.println(" success"); bool res = modem.isGprsConnected(); SerialMon.printf("GPRS status: %s\n", res ? "connected" : "not connected"); //各種情報を出力 String ccid = modem.getSimCCID(); SerialMon.println("CCID: "+ ccid); String imei = modem.getIMEI(); SerialMon.println("IMEI: "+ imei); String cop = modem.getOperator(); SerialMon.println("Operator: "+ cop); IPAddress local = modem.localIP(); SerialMon.print("Local IP: "); SerialMon.println(local); int csq = modem.getSignalQuality(); SerialMon.print("Signal quality: "); SerialMon.println(csq); //乱数を初期化 randomSeed(analogRead(25)); } /* 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); SerialMon.println("POST: " + body_string); //JSON文字列をIIJ IoTサービスにPOST HttpClient http(client, iij_iot_host, iij_iot_port); http.beginRequest(); http.post(iij_iot_path); http.sendHeader("Content-type", "application/json"); http.sendHeader("Content-length", body_string.length()); http.beginBody(); http.print(body_string); http.endRequest(); int status_code = http.responseStatusCode(); return status_code >= 200 && status_code < 300; } /* IIJ IoTサービスに設定されているラベルのJSON文字列を取得する 引数 String& labels : 取得したラベル文字列を格納するString参照 戻り値 String labelsを返す */ String get_label_string(String& labels) { HttpClient http(client, iij_iot_host, iij_iot_port); http.get(iij_iot_label_path); int status_code = http.responseStatusCode(); if(status_code == 200) { labels = http.responseBody(); } else { labels = "{}"; } 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() { //乱数を生成する int value = random(10000); //データ送信する bool ok = send_data("m5stamp", "test", value); SerialMon.println(ok ? "OK" : "NG"); //ラベル取得 char label_value[32]; get_label(sec_label_name, label_value, sizeof(label_value)); int sec = String(label_value).toInt(); //"delay_sec"のラベルが存在したら、送信間隔の時間をそのラベル値の数値に変更する if (sec > 0 && sec != sleep_sec ) { sleep_sec = sec; SerialMon.printf("update sleep sec: %d sec.\n", sleep_sec); } //待つ delay(sleep_sec * 1000L); }
実行結果
IoTサービスのコントロールパネルから、ラベルを設定することで、送信間隔を変更することができます。
コントロールパネルの左側メニューから「デバイス」を選択し、続いて一覧の中から使用しているSIMを選択し、画面上の「編集」ボタンをクリックします。
表示された画面から、ラベル名に delay_sec
、値に適当な数値を入力し、保存します。
M5Stamp 側で、設定したラベル値が読み込まれ、送信間隔が変更されます。
ラベル値に 30 と設定した場合は、下記の通りシリアルモニタに「update sleep sec: 30 sec」と表示され、次回以降は30秒間隔でデータ送信されます。
Wait... Initializing modem... Modem Info: R1951.04 Connecting to iot.iijmobile.jp OK. Waiting for network... success GPRS status: connected CCID: XXXXXXXXXXXXXXXXXXXXXX IMEI: YYYYYYYYYYYYYYYY Operator: NTT DOCOMO Local IP: 10.ZZZ.ZZZ.ZZZ Signal quality: 15 POST: {"namespace":"m5stamp","name":"test","value":4637} OK update sleep sec: 30 sec. POST: {"namespace":"m5stamp","name":"test","value":3907} OK
各種情報へのリンク
IIJ IoTサービスマニュアル
M5Stamp
TinyGSM
Arduino_JSON
ArduinoHttpClient