現時点での情報です。最新情報はM5StickC非公式日本語リファレンスを確認してください。
概要
ENV HAT(気温、湿度、気圧)の情報を1分ごとにMachinistにアップしました。また基礎編をベースにしていますので、基礎部分の解説は省いています。
Machinistとは?
IIJが提供するデータ収集サービスです。日本の会社が運営しているので、日本語で利用することができ、有料プランも用意されています。
比較的あたらしいサービスのため、情報量は他に比べると少ないです。
事前作業
Machinistにてあらかじめエージェントを作成する必要があります。エージェント名とエージェントIDが必要になります。その他データを保存するネームスペース名や、端末などを識別するタグの設定をESP32内部のpreferencesに保存しておいてください。
スケッチ(ライブラリ利用版)
/*
note: need add library Adafruit_BMP280 from library manage
Github: https://github.com/adafruit/Adafruit_BMP280_Library
note: need add library IIJMachinistClient from library manage
Github: https://github.com/nara256/IIJMachinistClient
*/
#include <M5StickC.h>
#include <Preferences.h>
#include <WiFi.h>
#include "DHT12.h"
#include <Adafruit_BMP280.h>
#include "IIJMachinistClient.h"
Preferences preferences;
char wifi_ssid[33];
char wifi_key[65];
DHT12 dht12;
Adafruit_BMP280 bme280;
unsigned long nextUpdate = 0;
char machinist_apiKey[40];
char machinist_agentName[40];
char machinist_namespace[40];
char machinist_tagName[40];
char machinist_tagValue[40];
IIJMachinistClient *machinist;
void setup() {
// M5StickC初期化
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println("ENV TEST");
// Wi-Fiアクセスポイント情報取得
preferences.begin("Wi-Fi", true);
preferences.getString("ssid", wifi_ssid, sizeof(wifi_ssid));
preferences.getString("key", wifi_key, sizeof(wifi_key));
preferences.end();
// Wi-Fi接続
Serial.printf("接続中 - %s ", wifi_ssid);
WiFi.begin(wifi_ssid, wifi_key);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" 接続完了");
// I2C初期化
Wire.begin(0, 26);
// BME280初期化
if (!bme280.begin(0x76)) {
Serial.println("BME280センサーが見つかりません");
while (1);
}
// Machinist情報取得
preferences.begin("Machinist", true);
preferences.getString("apiKey", machinist_apiKey, sizeof(machinist_apiKey));
preferences.getString("agentName", machinist_agentName, sizeof(machinist_agentName));
preferences.getString("namespace", machinist_namespace, sizeof(machinist_namespace));
preferences.getString("tagName", machinist_tagName, sizeof(machinist_tagName));
preferences.getString("tagValue", machinist_tagValue, sizeof(machinist_tagValue));
preferences.end();
// API KEYを指定してMachinistの初期化
machinist = new IIJMachinistClient(machinist_apiKey);
}
void loop() {
// 気温
float tmp = dht12.readTemperature();
M5.Lcd.setCursor(0, 20, 2);
M5.Lcd.printf("Temp: %2.1f C", tmp);
// 湿度
float hum = dht12.readHumidity();
M5.Lcd.setCursor(0, 40, 2);
M5.Lcd.printf("Humi: %2.0f %%", hum);
// 気圧
float pressure = bme280.readPressure() / 100.0F;
M5.Lcd.setCursor(0, 60, 2);
M5.Lcd.printf("pressure: %6.1f hPa", pressure);
// 1分に1度データ送信
if ( nextUpdate < millis() ) {
// シリアル出力
Serial.printf("Temp: %2.1f C\n", tmp);
Serial.printf("Humi: %2.0f %%\n", hum);
Serial.printf("pressure: %6.1f hPa\n", pressure);
// Machinist送信
machinist->post(machinist_agentName, machinist_namespace, "Temp", tmp, machinist_tagName, machinist_tagValue);
machinist->post(machinist_agentName, machinist_namespace, "Humi", hum, machinist_tagName, machinist_tagValue);
machinist->post(machinist_agentName, machinist_namespace, "Pressure", pressure, machinist_tagName, machinist_tagValue);
// 時間更新(60秒後)
nextUpdate = millis() + 60000;
}
// 1秒待機
delay(1000);
}
Machinistオフィシャルのライブラリは提供されていません。そのためIIJMachinistClientライブラリを利用しました。
このライブラリはSSLのRoot CAを内部に保存していますが、本日ためしたところサーバー側が更新されていたようで、エラーがでて通信できませんでした。
新しいRoot CAを取得して、プルリクエストを送っておきましたが、今後も変わる可能性があります。そのためRoot CAを利用しないバージョンも作成してみました。
スケッチ(自作関数利用版)
/*
note: need add library Adafruit_BMP280 from library manage
Github: https://github.com/adafruit/Adafruit_BMP280_Library
*/
#include <M5StickC.h>
#include <Preferences.h>
#include <WiFi.h>
#include "DHT12.h"
#include <Adafruit_BMP280.h>
#include <HTTPClient.h>
Preferences preferences;
char wifi_ssid[33];
char wifi_key[65];
DHT12 dht12;
Adafruit_BMP280 bme280;
unsigned long nextUpdate = 0;
char machinist_apiKey[40];
char machinist_agentName[40];
char machinist_namespace[40];
char machinist_tagName[40];
char machinist_tagValue[40];
void sendMachinist(const char *apiKey, const char *agentName, const char *nameSpace, const char *name, double value , const char *tagName, const char *tagValue) {
HTTPClient http;
http.begin("https://gw.machinist.iij.jp/endpoint");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + String(apiKey));
char json[1024];
sprintf( json,
"{\n"\
" \"agent\": \"%s\",\n"\
" \"metrics\": [\n"\
" {\n"\
" \"namespace\": \"%s\",\n"\
" \"name\": \"%s\",\n"\
" \"tags\": {\n"\
" \"%s\": \"%s\"\n"\
" },\n"\
" \"data_point\": {\n"\
" \"value\": %f\n"\
" }\n"
" }\n"
" ]\n"
"}\n"
, agentName
, nameSpace
, name
, tagName
, tagValue
, value
);
Serial.println(json);
http.POST(json);
}
void setup() {
// M5StickC初期化
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println("ENV TEST");
// Wi-Fiアクセスポイント情報取得
preferences.begin("Wi-Fi", true);
preferences.getString("ssid", wifi_ssid, sizeof(wifi_ssid));
preferences.getString("key", wifi_key, sizeof(wifi_key));
preferences.end();
// Wi-Fi接続
Serial.printf("接続中 - %s ", wifi_ssid);
WiFi.begin(wifi_ssid, wifi_key);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" 接続完了");
// I2C初期化
Wire.begin(0, 26);
// BME280初期化
if (!bme280.begin(0x76)) {
Serial.println("BME280センサーが見つかりません");
while (1);
}
// Machinist情報取得
preferences.begin("Machinist", true);
preferences.getString("apiKey", machinist_apiKey, sizeof(machinist_apiKey));
preferences.getString("agentName", machinist_agentName, sizeof(machinist_agentName));
preferences.getString("namespace", machinist_namespace, sizeof(machinist_namespace));
preferences.getString("tagName", machinist_tagName, sizeof(machinist_tagName));
preferences.getString("tagValue", machinist_tagValue, sizeof(machinist_tagValue));
preferences.end();
}
void loop() {
// 気温
float tmp = dht12.readTemperature();
M5.Lcd.setCursor(0, 20, 2);
M5.Lcd.printf("Temp: %2.1f C", tmp);
// 湿度
float hum = dht12.readHumidity();
M5.Lcd.setCursor(0, 40, 2);
M5.Lcd.printf("Humi: %2.0f %%", hum);
// 気圧
float pressure = bme280.readPressure() / 100.0F;
M5.Lcd.setCursor(0, 60, 2);
M5.Lcd.printf("pressure: %6.1f hPa", pressure);
// 1分に1度データ送信
if ( nextUpdate < millis() ) {
// シリアル出力
Serial.printf("Temp: %2.1f C\n", tmp);
Serial.printf("Humi: %2.0f %%\n", hum);
Serial.printf("pressure: %6.1f hPa\n", pressure);
// Machinist送信
sendMachinist(machinist_apiKey, machinist_agentName, machinist_namespace, "Temp", tmp, machinist_tagName, machinist_tagValue);
sendMachinist(machinist_apiKey, machinist_agentName, machinist_namespace, "Humi", hum, machinist_tagName, machinist_tagValue);
sendMachinist(machinist_apiKey, machinist_agentName, machinist_namespace, "Pressure", pressure, machinist_tagName, machinist_tagValue);
// 時間更新(60秒後)
nextUpdate = millis() + 60000;
}
// 1秒待機
delay(1000);
}
エラー処理をしていない、簡易版です。自分でJSONを作ってPOSTしています。HTTPS接続時に証明書の確認はしていません。HTTPSには、通信の内容を暗号化する機能と、そのサーバーが本物かを認証する機能があります。
Root CAを利用しないということは、サーバーが本物かを認証していません。そのため、Wi-Fiルーターなどに細工されると、違うサーバーにデータを送信していても、気がつくことができません。
まあ、実際のところそこまでのセキュリティーが必要無いことが多いのと、他のサービスもHTTPで送信していたりするので、Root CAを利用していない危険性を理解した上で利用してください。

グラフはちょっと扱いにくくて、特定範囲だけキレイにレポーティングする用途には使いにくいかもしれません。複数のグラフをダッシュボードとして表示するのではなく、1つのグラフを拡大とかしながら確認する用途向きだと感じました。
まとめ
サービス自体はJSONで送信するだけなので単純なのですが、ESP32からだとオフィシャルライブラリがあったほうが良かったなと思います。




コメント