05.Basicのデータをweb表示
05.Basicのデータをweb表示
M5Stack Basicで測定した温湿度,気圧データを、同じwifiに接続しているPCのhttp://m5stack.local/env に測定No.,時刻付で表示します。
・webの画面再読込みで数秒たってからデータ更新されます。
・USBバッテリーからの電源供給では3H(データ数180)以上の動作を確認しました。しかし、長時間ではHTML表示用の配列がオーバーになるはずです。
・M5の電源がoffになるとwebで 「このサイトにアクセスできません」 と表示されます。
・Arduino IDE > ファイル > スケッチ例 > (M5Stack-Core-ESP32用のスケッチ例) WebServer > HelloServer.ino を参考にしています。
・webServerオブジェクトを作り、on関数で指定したURLにアクセスされた時の処理を設定します。
・loop関数の中でhandleClient関数を実行してon関数で指定したURLにブラウザからのアクセスがあると、登録した処理関数が呼ばれます。
・WEBサーバとは、クライアントの指示に応じて静的画面などをWebブラウザーに送り返してくれるサーバーの事です。
HTML の説明
<!DOCTYPE html> <!-- HTML5を使用 -->
<html lang="ja"> <!-- 日本語 -->
<head> <!-- 文書情報 -->
<meta charset=\"utf-8\"> <!-- 文字コード -->
<title>M5測定</title> <!-- 頁タイトル(上のタブ) -->
</head>
<body style="line-height:0.1";> <!-- 行間を狭くする -->
<h3>M5Stack Basic測定データ</h3> <!-- 見出し(1-6) -->
<p>No.____年/月/日,__時:分:秒,__℃,\%RH,_hPa</p> <!-- 段落 -->
<p>000.2021/08/29, 16:36:54, 27.9, 58, 1013</p> <!-- 例 -->
<p>001.2021/08/29, 16:37:00, 27.9, 58, 1013</p> <!-- 例 -->
<p>002.2021/08/29, 16:38:00, 27.9, 58, 1013</p> <!-- 例 -->
<!-- No.,時刻,温湿度,気圧を埋込んだ文字列。ここに追加していきます -->
</body> <!-- 表示内容 -->
</html>
スケッチ
2つの"*****"は、自分のssidとそのパスワードを記入してください。buf,buf2の配列要素数が23kだとエラーが発生します。
// M5Stack Basicのデータを、同じwifiに接続しているPCの
// http://m5stack.local/env にNo.,時刻,温湿度,気圧を表示します。
// web画面再読込みで数秒たってからデータ更新。USBバッテリーで3H以上の動作確認
// M5がoffになると"このサイトにアクセスできません"とweb表示
// buf,buf2が23kだとエラーが発生
#include <M5Stack.h> // M5Stack Basicを使用
#include <WiFi.h> // wifiを使用
#include <WebServer.h> // M5が送信
#include <ESPmDNS.h> // 名前(m5stack.local)をIPアドレスに変換
#include <Adafruit_BMP280.h> //気圧センサを使用(300-1100)±1hPa
#include <Adafruit_SHT31.h> //温湿度センサ(0-60)±0.2℃,(10-90)±2%RH
const char* ssid = "*****"; // 自分のssid 時刻取得の為
const char* password = "*****"; // そのパスワード
WebServer server(80); //WebServerオブジェクトを作る,80はHTTP通信の一般的ポート
Adafruit_SHT31 sht3x = Adafruit_SHT31(&Wire); // 定義
Adafruit_BMP280 bme = Adafruit_BMP280(&Wire); // 定義
char buf[22000], buf2[22000]; // html文字列(NG 23k)
int count, printI; // データ数count,countの表示する行
const int n = 1000; // データ数max 0-999
int sokutei[n][9]; // 0測定年,1月,2日,3時,4分,5秒,6温度,7湿度,8気圧
int maeT = 99; // 前回のsokutei[][]時刻の値
void handleRoot() { // "/"(ルート)にアクセスされた時の処理関数
String message = "/envへ移動してください。\n"; //表示文字
server.send(200, "text/plain", message);//(ok,ファイルの分類/種類,web表示文字)
Serial.println("ルートにアクセスされました"); // シリアルモニタに表示
}
void handleEnv() { // "/env"にアクセスされた時の処理関数
memset(buf2, '\0', sizeof(buf2));
// 配列全体をヌル文字でクリア (メモリのポインタ,セット値,セットサイズ)
printI = 0; // 最初のデータから
while (printI <= count) { // データの最後まで
sprintf(buf,
"<p>%03d, %4d/%02d/%02d, %02d:%02d:%02d, %4.1f, %3d, %4d</p>",
printI, sokutei[printI][0], sokutei[printI][1], sokutei[printI][2],
sokutei[printI][3], sokutei[printI][4], sokutei[printI][5],
(float)sokutei[printI][6] / 10.0, sokutei[printI][7],
sokutei[printI][8]); // HTML用にNo.,温湿度,気圧を埋込んだ文字列
strcat(buf2, buf); // buf2にbufを結合
printI++; // 次のデータNo.
}
sprintf(buf, "%s%s%s",
"<!DOCTYPE html><html lang=\"ja\">"
"<head><meta charset=\"utf-8\"><title>M5測定</title></head>"
"<body style=\"line-height:0.1\";>"
"<h3>M5Stack Basic測定データ</h3>"
"<p>No.____年/月/日,__時:分:秒,__℃,\%RH,_hPa</p>",
buf2,
"</body>"
"</html>");
//Serial.println(buf);
server.send(200, "text/html", buf); // ブラウザに送る
}
void handleNotFound() { // ファイルが見つからない時の関数
String message = "File Not Found\n\n"; // 表示文字
server.send(404, "text/plain", message);
// (404=見つからない,ファイルの分類/種類,web表示文字)
Serial.println("ファイルが見つかりません");//シリアルモニタに表示
}
void printGyou() { // 1行表示関数
M5.Lcd.setTextColor(WHITE, BLACK); // 黒地(前の字を消す)に白文字
M5.Lcd.printf("%02d/%02d", sokutei[printI][1], sokutei[printI][2]); // 月日
Serial.printf("%03d %02d/%02d", printI, sokutei[printI][1], sokutei[printI][2]);
M5.Lcd.printf(" %02d:%02d:%02d", sokutei[printI][3],
sokutei[printI][4], sokutei[printI][5]); // 時分秒
Serial.printf(" %02d:%02d:%02d", sokutei[printI][3],
sokutei[printI][4], sokutei[printI][5]); // シリアルモニタに表示
M5.Lcd.setTextColor(GREEN, BLACK); // 黒地(前の字を消す)に緑文字
M5.Lcd.printf(" %4.1f", (float)sokutei[printI][6] / 10.0); // 温度を表示
Serial.printf(" %4.1f℃", (float)sokutei[printI][6] / 10.0); // シリアルモニタに表示
M5.Lcd.setTextColor(CYAN, BLACK); // 黒地(前の字を消す)にほぼ黄文字
M5.Lcd.printf("%3d", sokutei[printI][7]); // 湿度を表示
Serial.printf(" %3d%%", sokutei[printI][7]); // シリアルモニタに表示
M5.Lcd.setTextColor(PINK, BLACK); // 黒地(前の字を消す)にピンク文字
M5.Lcd.printf("%4d", sokutei[printI][8]); // 気圧を表示
Serial.printf(" %4dhPa\n", sokutei[printI][8]); // シリアルモニタに表示
}
void setup() {
M5.begin(); // M5stack初期化
M5.Lcd.setTextColor(GREEN); // 色変更(文字色[,背景色])
M5.Lcd.setTextSize(2); // 文字サイズ1~7
M5.Lcd.setCursor(0, 0); // 表示位置(x,y)
Serial.println(); // シリアルモニタ 改行
while (!bme.begin(0x76)) { // I2Cアドレスが違っていたら
M5.Lcd.println("エラー BMP280"); // 気圧センサー
}
while (!sht3x.begin(0x44)) { // I2Cアドレスが違っていたら
M5.Lcd.println("エラー SHT3X"); // 温湿度センサー
}
WiFi.begin(ssid, password); // wifi接続開始(Webサーバを起動)
Serial.print("wifi接続開始"); // シリアルモニタに表示
while (WiFi.status() != WL_CONNECTED) { // wifi接続完待ち
delay(500); // 0.5秒待つ
Serial.print("."); // シリアルモニタに表示
}
Serial.print("\n接続中 "); // シリアルモニタに表示
Serial.println(ssid); // ssid表示
Serial.print("IPアドレス "); // シリアルモニタに表示
Serial.println(WiFi.localIP()); // IPアドレス表示
configTime(3600L * 9, 0, "ntp.nict.jp",
"time.google.com", "ntp.jst.mfeed.ad.jp");
// 時刻の同期(GMTとローカル時刻との差(秒),夏時間で進める秒,NTPサーバ)
if (MDNS.begin("m5stack")) { // マルチキャストDNSにホスト名m5stackを
// 登録し成功したら http://m5stack.local でこのWebサーバにアクセスできる
Serial.println("MDNSレスポンダー開始"); // シリアルモニタに表示
}
server.on("/", handleRoot); // ルートアクセス時に実行する関数を設定
server.on("/env", handleEnv); // envフォルダアクセス時に実行する関数を設定
server.onNotFound(handleNotFound); // 見つからない時に実行する関数を設定
server.begin(); // Webサーバ開始
Serial.println("HTTPサーバー起動"); // シリアルモニタに表示
for (int i = 0; i <= 999; i++) { // i=0-999
for (int j = 0; j <= 8; j++) { // j=0-8
sokutei[i][j] = 0; // 測定データクリア
}
}
count = 0; // データNo.
}
void loop() {
struct tm tm; // 時計用
if (getLocalTime(&tm)) { // 現在時刻を取得
sokutei[count][0] = tm.tm_year + 1900; // 年
sokutei[count][1] = tm.tm_mon + 1; // 月
sokutei[count][2] = tm.tm_mday; // 日
sokutei[count][3] = tm.tm_hour; // 時
sokutei[count][4] = tm.tm_min; // 分
sokutei[count][5] = tm.tm_sec; // 秒
if (maeT != sokutei[count][4]) { // 前と分が違ったら
maeT = sokutei[count][4]; // 今の値を前の値とする
sokutei[count][6] = (int)(sht3x.readTemperature() * 10.0 + 0.5); // センサーの温度x10を読取る
sokutei[count][7] = (int)(sht3x.readHumidity() + 0.5); // センサーの湿度を読取る
sokutei[count][8] = (int)(bme.readPressure() / 100.0 + 0.5); // センサーの圧力を読取る
if (count < 15) { // 1画面(15行)埋まっていなければ
printI = count; printGyou(); // 下の行に表示
} else { // 1画面埋まったら
M5.Lcd.setCursor(0, 0); // 表示位置(x,y)
for (printI = count - 14; printI <= count; printI++) { // スクロール
printGyou(); // 1行表示
}
}
count++; // 次のデータ
}
}
server.handleClient(); // クライアントからのアクセスの処理(ブラウザからのリクエストを処理)
delay(1000); // 1秒待つ
}