01.M5StickC+で簡易熱中症計
01.M5StickC+で簡易熱中症計
M5StickC Plusの仕様(一部)
M5StickC Plus (M5StickC Plus2)・価格:4037円 (4147円)
・画面:240x135 (同じ)
・バッテリー:120mAh (200mAh)
・SoC:ESP32-PICO-D4 (ESP32-PICO-V3-02)
・Flash:4MB (8MB)
・SRAM:520kB (PSRAM:2MB)
・ボタン:x2 (x3)
・バッテリ管理IC:AXP192 (無し)
* ブザー,IR送信機,赤色LED,マイク,6軸IMU,RTCは両方にあります。2024/7/26に、在庫限りから通常販売になりましたが、これから購入なら2の方が良いでしょう。
WBGT(暑さ指数)レベル
ここでの区分は以下にしました。35以上(黒) 熱中症特別警戒アラートレベル *1
33以上(紫) 極めて危険(非常に危険)熱中症警戒アラートレベル *2
31以上(赤) 危険
28以上(橙) 厳重警戒
25以上(黄) 警戒
21以上(水) 注意
21未満(青) ほぼ安全 *3
*1と*2は、環境省 熱中症予防情報サイト
https://www.wbgt.env.go.jp/about_alert.php
https://www.wbgt.env.go.jp/about_special_alert.php
*3は、環境省 熱中症予防情報サイト 運動に関する指針
https://www.wbgt.env.go.jp/wbgt.php
それ以外は、日本生気象学会 日常生活における熱中症予防指針
https://seikishou.jp/cms/wp-content/uploads/20220523-v4.pdf
気温(21~40℃で1℃刻み)と湿度(20~100%で5%刻み)で整数で表示。
によります。
不快指数
THI (Temperature-Humidity Index)https://ja.wikipedia.org/wiki/%E4%B8%8D%E5%BF%AB%E6%8C%87%E6%95%B0
夏の蒸し暑さを数量的に表した指数で、温熱指標の一つです。
乾球温度と湿球温度を使用する場合
THI=0.72*(tmp1+tmp2)+40.6
tmp1:乾球温度(℃)
tmp2:湿球温度(℃)
気温と湿度を使用する場合
THI=0.81*tmp+0.01*hum*(0.99*tmp-14.3)+46.3
tmp:乾球温度,気温(℃)
hum:湿度(%)
例)気温27℃,湿度55%で不快指数75
気温29℃,湿度70%で不快指数80
THIと体感
〜49 寒くてたまらない
50〜54 寒い
55〜59 肌寒い
60〜64 何も感じない
65〜69 快適
70〜74 不快感を持つ人が出始める
75〜79 半数以上が不快に感じる
80〜84 全員が不快に感じる
85〜 暑くてたまらない
気温(25~45℃で1℃刻み)と湿度(0~100%で5%刻み)の表では不快指数は整数で表示されています。
表示内容
バッテリー残量
(1行目右側)Lang-ship M5StickCバッテリーライフ検証 その1
https://lang-ship.com/blog/work/m5stickc-battery-life-1/
にて、バッテリー駆動時間(分)とバッテリー電圧(V)のグラフ
"M5StickC Battery Test(液晶明るさ別)"より
0分目が約4.0V、止まる3分前ぐらいの電圧が約3.3Vとなっているので
・100%は4.0V
・0%は3.3V
・その間は直線変化
とし、バッテリ電圧から残量(%)を計算しました。
暑さ指数
(1行目左側,2行目)1行目左側に計算値と、2行目に内容を表示します。1~4行目の地の色は暑さ指数の項目に書いた色にしました。
不快指数
(3行目左側,4行目)3行目左側に計算値と、4行目に体感を表示します。
センサー測定値
(5行目)温湿度・気圧センサーであるENV2の測定値を表示します。
本当は、M5StickC ENV Hatの方が線が無くかっこ良いです。
Ver3 (SHT30/QMP6988)は、1848円
Ver2(SHT30/BMP280/BMM150)は、売切れ 1430円 磁界も測定
Ver1 (DHT12/BMP280/BMM150)は、販売終了 814円 磁界も測定
表示残り秒
(3行目右側)動作時間を持たせるため30秒で自動に電源offします。測定と表示は、5秒ごとなので飛び飛びの秒数になります。
スケッチ
// 温湿度・気圧・室内簡易暑さ指数・不快指数の表示 M5StickC+ 240x135 10字5行
// 暑さ指数:(温度:四捨五入で整数,湿度:切上げで5の倍数の整数)
// 不快指数:式は測定値そのもので計算
// 電源on:電源ボタンを2秒, 電源off:6秒
// Adafruit BMP280 Library と Adafruit SHT31 Library が必要
// 30秒で電源が切れるプログラムなので、更新中に電源onか注意必要
#include <M5StickCPlus.h> // M5StickCPlusを使用
#include <AXP192.h> // 電源管理ICを使用
#define LGFX_AUTODETECT // LovyanGFX自動認識
#define LGFX_USE_V1 // LovyanGFX Ver1を使用
#include <LGFX_AUTODETECT.hpp> // クラス"LGFX"を用意
static LGFX lcd; // LGFXのインスタンスを作成
#include <Wire.h> // I2Cのセンサーを使用
#include <Adafruit_SHT31.h> // 温湿度センサを使用
#include <Adafruit_BMP280.h> // 気圧センサを使用
Adafruit_SHT31 sht = Adafruit_SHT31(&Wire); // sht定義
Adafruit_BMP280 bme = Adafruit_BMP280(&Wire); // bmp定義だがbmeとする
unsigned long startTime, currentTime; // 開始時間,現在時間 mS
unsigned long period = 30 * 1000; // 目標経過時間 mS
float batV; // 電池電圧
int16_t tmp, pre; // 10倍の温度,気圧 -32768~32767
int8_t hum, thi, wbgt, batP; // 湿度,不快指数,暑さ指数,電池容量 -128~127
int8_t tmpIndex, humIndex, RemainingT; // 温度配列,湿度配列.残り秒
// ℃ % 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100% 暑さ指数表ver4
int8_t wbgtT[20][17] = { { 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21 }, //21℃
{ 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22 }, //22
{ 15, 16, 16, 17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 23, 23 }, //23
{ 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24 }, //24
{ 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25 }, //25
{ 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26 }, //26
{ 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27 }, //27
{ 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28 }, //28
{ 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29 }, //29
{ 21, 21, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 29, 30, 30 }, //30
{ 21, 22, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 30, 31, 31 }, //31
{ 22, 23, 24, 24, 25, 26, 26, 27, 28, 28, 29, 29, 30, 31, 31, 32, 32 }, //32
{ 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30, 30, 31, 31, 32, 33, 33 }, //33
{ 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 31, 32, 32, 33, 34, 34 }, //34
{ 24, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 33, 34, 34, 35 }, //35
{ 25, 26, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 34, 35, 35, 36 }, //36
{ 26, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37 }, //37
{ 27, 28, 29, 29, 30, 31, 32, 33, 33, 34, 35, 35, 36, 36, 37, 37, 38 }, //38
{ 27, 28, 29, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 37, 38, 38, 39 }, //39
{ 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 36, 37, 38, 38, 39, 39, 40 } }; //40
void LCDset() { // 初期画面設定関数
lcd.init(); // 画面初期化
lcd.setRotation(1); // 回転方向(0-3)
lcd.setBrightness(100); // バックライト輝度(0-255)実際は数段階
//lcd.setColorDepth(24); // RGB888 24bit (16=RGB565 16bit)
lcd.setCursor(0, 0); // 表示位置(x,y)
lcd.setFont(&fonts::lgfxJapanGothic_24); // ゴシック(8,12,16,20,24,28,32,36,40)
lcd.fillScreen(TFT_BLACK); // 画面クリア(色)
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // 色設定(文字色[,背景色])
}
void setup() {
M5.begin(); // M5初期化
LCDset(); // 初期画面設定関数へ
while (!sht.begin(0x44)) { // shtのアドレスで開始できない時
M5.lcd.println("エラー SHT3X未接続"); // 表示
}
while (!bme.begin(0x76)) { // BMP280のアドレスで開始できない時
M5.lcd.println("エラー BMP280未接続"); // 表示
}
startTime = millis(); // 開始時間
}
void loop() {
currentTime = millis(); // 現在時間
if (currentTime - startTime < period) { // 指定表示時間以内なら
tmp = int16_t(sht.readTemperature() * 10.0 + 0.5); // センサーで10倍の温度を読取る
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色{,背景色})
lcd.setCursor(0, 108); // 表示位置(x,y) 5行目
lcd.printf("%5.1f℃", tmp / 10.0); // 表示 温度
hum = int8_t(sht.readHumidity() + 0.5); // センサーで湿度を読取る
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (字,地)
lcd.printf("%3d%%", hum); // 表示 湿度
pre = int16_t(bme.readPressure() / 100.0 + 0.5); // センサーで気圧を読取る
lcd.setTextColor(TFT_PINK, TFT_BLACK); // (字,地)
lcd.printf("%5dhPa\n", pre); // 表示 気圧
tmpIndex = int8_t(tmp / 10.0 + 0.5) - 21; // 四捨五入で整数 配列温度番号
humIndex = (hum - 16) / 5; // 配列湿度番号
wbgt = wbgtT[tmpIndex][humIndex]; // wbgtを表から読む
lcd.setCursor(2, 28); // 表示位置(x,y) 2行目
if (wbgt < 21) {
lcd.fillRect(0, 0, 240, 106, TFT_BLUE); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_WHITE, TFT_BLUE); // (字,地)
lcd.println("ほぼ安全"); // 表示
} else if (wbgt < 25) {
lcd.fillRect(0, 0, 240, 106, TFT_CYAN); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_BLACK, TFT_CYAN); // (字,地)
lcd.println("注意"); // 表示
} else if (wbgt < 28) {
lcd.fillRect(0, 0, 240, 106, TFT_YELLOW); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_BLACK, TFT_YELLOW); // (字,地)
lcd.println("警戒"); // 表示
} else if (wbgt < 31) {
lcd.fillRect(0, 0, 240, 106, TFT_ORANGE); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_BLACK, TFT_ORANGE); // (字,地)
lcd.println("厳重警戒"); // 表示
} else if (wbgt < 33) {
lcd.fillRect(0, 0, 240, 106, TFT_RED); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_WHITE, TFT_RED); // (字,地)
lcd.println("危険"); // 表示
} else if (wbgt < 35) {
lcd.fillRect(0, 0, 240, 106, TFT_VIOLET); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_WHITE, TFT_VIOLET); // (字,地)
lcd.println("警戒アラートレベル"); // 表示
} else {
lcd.fillRect(0, 0, 240, 106, TFT_BLACK); // 四角塗潰(x,y,w,h,色)
lcd.setTextColor(TFT_WHITE, TFT_BLACK); // (字,地)
lcd.println("特別警戒アラートレベル"); // 表示
}
lcd.setCursor(0, 2); // 表示位置(x,y) 1行目
lcd.printf("(暑さ指数%d)\n", wbgt); // 表示 wbgt
// 不快指数
thi = int8_t(0.081 * tmp + 0.01 * hum * (0.099 * tmp - 14.3) + 46.3 + 0.5);
lcd.setCursor(0, 55); // 表示位置(x,y) 3行目
lcd.printf("(不快指数%2d)\n", thi); // 表示 不快指数
lcd.setCursor(2, 81); // 表示位置(x,y) 4行目
if (thi < 50) { // 不快指数の感じ方
lcd.println("寒くてたまらない");
} else if (thi < 55) {
lcd.println("寒い");
} else if (thi < 60) {
lcd.println("肌寒い");
} else if (thi < 65) {
lcd.println("何も感じない");
} else if (thi < 70) {
lcd.println("快適");
} else if (thi < 75) {
lcd.println("不快感の人がいる");
} else if (thi < 80) {
lcd.println("半数以上が不快感");
} else if (thi < 85) {
lcd.println("93%が不快感");
} else {
lcd.println("暑くてたまらない");
}
batV = M5.Axp.GetBatVoltage(); // バッテリ電圧を読取る
batP = int8_t((batV - 3.3) / (4.0 - 3.3) * 100); // バッテリ残量計算
// 100%は4.0V,0%は3.3Vで間は直線としました
if (batP > 100) batP = 100; // 100%以上は100%
if (batP < 0) batP = 0; // 0%以下は0%
lcd.setCursor(165, 2); // 表示位置(x,y) 1行目
lcd.printf("BT%3d%%", batP); // 表示 バッテリ残量
RemainingT = (startTime + period - currentTime) / 1000; // 残り秒数
lcd.setCursor(200, 55); // 表示位置(x,y) 3行目
lcd.printf("%3d", RemainingT); // 電源offまでの秒数
lcd.drawFastHLine(0, 54, 240, TFT_BLACK); // 水平線(x,y,w,色)不快指数の上
lcd.drawRect(165, 1, 73, 26, TFT_BLACK); // 四角枠 (x,y,w,h,色) バッテリー枠
lcd.drawRect(198, 56, 40, 21, TFT_BLACK); // 四角枠 (x,y,w,h,色) 残秒枠
delay(5000); // 5秒待つ
} else {
M5.Axp.PowerOff(); // 電源off
}
}
* flash memory(3.1Mbyte)のうち、スケッチが22%使用。RAM(328kbyte)のうち、global変数が7%使用、local変数で304kbyte使用可能。(1000byte=1kbyteで計算)