M5Stack Tab5 を SwitchBot 温湿度計の常設モニタにするファームウェアです。
BLE のブロードキャストを受信して温度・湿度・CO2・電池残量をタイル表示し、履歴を microSD に記録して、機器ごとのグラフを描きます。Grove 端子の環境センサと、本体カメラで測った部屋の明るさも同じように扱えます。SwitchBot のクラウドも公式アプリも経由しません。SwitchBot 機器側の設定変更やペアリングも不要です。電池残量を読むために BLE のスキャン要求(規格上の定型の問い合わせ)は送りますが、接続もコマンド送信もしないため、機器の設定は一切変わりません。
- タイル表示 — 登録した機器の現在値を一覧。温度・湿度・CO2・電池残量を色分け表示し、閾値を超えると警告色になります
- タグで絞り込み — 機器にタグを付けて部屋別などに切り替え。「警告閾値越え」だけを並べることもできます
- 履歴グラフ — 10分 / 時 / 日 / 週 / 月 / 年。週・月・年は日ごとの最低・最高を帯で表示します
- グラフの深掘り — 気になるところをタップすると、そこを含む1つ下の期間が開きます。月 → 週 → 日 → 時と辿れます
- スマホから設定 — 同じ Wi-Fi につないだスマホのブラウザで、機器の登録・命名・タグ付け・並び替えができます
- 縦横自動回転 — 加速度センサで画面の向きを判定します(手動固定も可)
- Grove 端子のセンサ — M5Stack UNIT ENV III をつなぐと、温度・湿度・気圧が機器の1台として並びます
- 離れた場所のセンサ — M5StickC や M5AtomS3 にセンサをつないだものを、SwitchBot 機器と同じように受信できます。ENV PRO なら温度・湿度・気圧に加えて空気質・CO2相当値・呼気VOC相当値(EnvProBeacon)、MH-Z19B/C・SCD30・SCD40 なら実測のCO2が分かります(Co2Beacon)
- 部屋の明るさ — 本体のカメラを照度計として使い、明るさを記録します。暗くなると画面を消し、触れると点きます
- 時刻の保持 — 本体のRTCとスーパーキャパシタで、電源を切っている間も時刻を保ちます
- 異常再起動の記録 — パニックやウォッチドッグによる再起動を本体に記録し、設定画面で確認できます
ハードウェア
- M5Stack Tab5(ESP32-P4 + ESP32-C6、16MB Flash / 32MB PSRAM)
- microSD カード(履歴記録用。無くても動作しますが履歴は RAM 上の24時間分のみになります)
- SwitchBot 温湿度計(Meter / Outdoor Meter / Meter Pro CO2 で動作確認)
- M5Stack UNIT ENV Ⅲ(任意。Grove 端子に接続)
- M5StickC 系 / M5AtomS3 系 + M5Stack UNIT ENV PRO(任意。離れた場所の温湿度・気圧・空気質を BLE で送ります。EnvProBeacon を書き込んで使います)
- M5StickC(無印 / Plus / Plus2)+ MH-Z19B/C・SCD30・SCD40 のいずれか(任意。離れた場所の CO2 を BLE で送ります。Co2Beacon を書き込んで使います。SCD40 は Grove 接続なので M5AtomS3 系でも使えます。M5StickS3 は HAT 端子にセンサを挿せないため対象外です)
- 2.4GHz の Wi-Fi(時刻同期とスマホ設定に必要。5GHz 専用の SSID には接続できません)
ソフトウェア
- Arduino IDE 2.x
- M5Stack ボードパッケージ 3.3.8(ボード選択は「M5Tab5」)
- ライブラリ(括弧内は検証時のバージョン)
- M5Unified(0.2.20)
- M5GFX(0.2.27)
- LVGL(9.5.0)
- ArduinoJson(7.4.3)
- M5Unit-ENV(1.7.1)— Grove 端子の ENV III を使う場合のみ
BLE・Wi-Fi・microSD・LittleFS・mDNS・NVS はいずれもボードパッケージ同梱のため、追加のインストールは不要です。
BLE はコア同梱の
BLEDevice.h(libraries/BLE)を使います。
日本語表示に BIZ UDゴシックを使います。ライセンスの都合でリポジトリには含めていないので、各自で用意してください。この手順を飛ばすと日本語が表示されません。
-
BIZ UDGothic のリリース ZIP をダウンロード(Google Fonts からでも同じものが入手できます)
-
ZIP の中の
BIZUDGothic-Regular.ttf(約4.6MB)だけを、スケッチフォルダ内にdataフォルダを作ってリネームせずに置くSwitchBotSync/ └ data/ └ BIZUDGothic-Regular.ttf -
LittleFS へアップロードするプラグインを導入する(Arduino IDE 2.x には標準の「Sketch Data Upload」がありません)
- arduino-littlefs-upload から
.vsixをダウンロード %USERPROFILE%\.arduinoIDE\plugins\に置く(フォルダが無ければ作成)- Arduino IDE を再起動
- arduino-littlefs-upload から
-
スケッチを開いた状態で
Ctrl+Shift+P→Upload LittleFSを実行
別のフォントに変えたい場合は、data に置いて Config.h の FONT_FILE_PATH をそのファイル名に書き換えてください。
partitions.csv をスケッチフォルダに同梱しています。スケッチフォルダ内の partitions.csv は「Partition Scheme」の設定より優先されるため、IDE 側の設定は何を選んでも構いません。意図を明確にする意味で「Custom」を選んでおくことを推奨します。
| 領域 | サイズ | 用途 |
|---|---|---|
| factory | 4MB | プログラム本体 |
| littlefs | 6MB | フォント・Web設定の画面データ |
| coredump | 64KB | クラッシュ時の解析情報 |
| nvs | 20KB | 設定値・機器登録・異常再起動の記録 |
lv_conf.h と build_opt.h をスケッチフォルダに同梱しています。LVGL の設定がこのスケッチ内で完結するようにしてあるので、他の LVGL プロジェクトと干渉しません。
初回だけ、ビルド前に Arduino IDE を再起動してください。 build_opt.h は IDE がキャッシュする都合上、追加直後の一度だけ再起動が必要です。
M5Stack ボードパッケージ 3.3.8 には、Tab5 向けビルドでスケッチの内容に関わらず必ず発生するコンパイルエラーがあります。
esp32-hal-spi.c:299:32: error: 'BOARD_SDMMC_POWER_CHANNEL' undeclared
Arduino コア本体が、Tab5 のピン定義に存在しないマクロを #ifdef 無しで参照しているためです。次のファイルを開いてください。
%LOCALAPPDATA%\Arduino15\packages\m5stack\hardware\esp32\3.3.8\cores\esp32\esp32-hal-spi.c
299行目付近のブロックを #ifdef で囲みます。
#ifdef BOARD_SDMMC_POWER_CHANNEL // ← この行を追加
sd_pwr_ctrl_ldo_config_t ldo_config;
ldo_config.ldo_chan_id = BOARD_SDMMC_POWER_CHANNEL;
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
if (sd_pwr_ctrl_set_io_voltage(pwr_ctrl_handle, 3300)) {
log_e("Unable to set power control to 3V3");
return;
}
#endif // ← この行を追加
break;同じ関数内で BOARD_SDMMC_POWER_PIN に対して既に使われているのと同じ書き方です。この箇所は SOC_SDMMC_IO_POWER_EXTERNAL(ESP32-P4 でのみ定義)のブロック内にあるため、他の M5Stack 製品向けのビルドには影響しません。
ボードパッケージを更新・再インストールすると修正は失われます。コンパイルエラーが出る場合はその都度やり直してください。
ボードに「M5Tab5」を選び、通常どおり書き込みます。
M5StickC や M5AtomS3 にセンサをつないだものを、SwitchBot 機器と同じように受信できます。本体側の設定は不要で、Tab5 の Web 設定から普通に機器登録するだけです。
送信側のプログラムは用途で選びます。手順はそれぞれの README にあります。
| プログラム | センサ | 送るもの |
|---|---|---|
| EnvProBeacon | M5Stack UNIT ENV PRO | 温度・湿度・気圧・空気質・CO2相当値・呼気VOC相当値 |
| Co2Beacon | MH-Z19B/C・SCD30・SCD40 | CO2(実測値)、SCD は温度・湿度も |
機器の登録・名前付け・タグ・並び順は、本体の画面ではなくスマホのブラウザから行います。設定画面(⚙)の下のほうに、開始用のボタンが2つあります。
| ボタン | 動作 |
|---|---|
| Web設定を開始 | 保存済みの Wi-Fi に本機が参加します(STAモード)。同じ Wi-Fi につないだスマホからアクセスします。Wi-Fi が未設定のときや、参加に失敗したときは、自動的に下の APモードになります |
| APモード(Tab5-Setup)で開始 | 本機自身が Tab5-Setup という Wi-Fi アクセスポイントになります(パスワード無し)。スマホをそこにつなぎ替えてアクセスします |
いずれの場合も、接続先の URL は本体の画面に大きく表示されます。
Tab5 の無線は ESP32-C6 が担当していますが、この石は Wi-Fi の子機として通信しながら BLE を受信するのは安定して行える一方で、自らアクセスポイントになりながら BLE を受信するのは不安定です。そのため、可能なかぎり既存の Wi-Fi に参加する側(STAモード)を優先します。
- STAモード — Web設定を開いている間も BLE の受信が続きます。「検出」タブに新しい機器が実時間で出てきます。スマホ側の接続先を変える必要もありません
- APモード — Web設定を閉じるまで BLE の受信を止めます。「検出」タブには、Web設定を開く前に受信済みの機器だけが並びます
普段は「Web設定を開始」だけで済みます。APモードのボタンは、初回設定と、Wi-Fi の設定を保存したあとで STA 側につながらなくなった場合の逃げ道として用意しています(後者が無いと、Web設定を開く手段が完全に失われてしまいます)。
書き込み直後は Wi-Fi が未設定なので、最初は必ず APモードになります。
- 電源を入れると、まだ機器が登録されていないので空のタイル画面が出ます
- 右上の ⚙ → 「Web設定を開始」(Wi-Fi 未設定のため、自動的に APモードになります)
- スマホの Wi-Fi 設定で
Tab5-Setupに接続し、ブラウザでhttp://192.168.4.1/を開く - 「Wi-Fi / SD」タブで自宅の Wi-Fi を登録する
- 設定画面でいったん Web設定を止め、もう一度 「Web設定を開始」。今度は自宅の Wi-Fi に参加します(STAモード)
- スマホを自宅の Wi-Fi に戻し、本体画面に出た URL(
http://tab5.local/または IP アドレス)を開く - 「検出」タブに近くの SwitchBot 機器が並ぶので、名前を付けて登録
- 「登録済み」タブでタグ付け、「レイアウト」タブで並び順を変更
手順 4 まで済ませてしまえば、次回からは 2 と 6〜8 だけです。
登録内容は本体に保存されます。CSV で書き出し・取り込みもできるので、ファームウェア更新のたびに登録し直す必要はありません。
| 操作 | 動作 |
|---|---|
| タイルをタップ | その機器のグラフを開く |
| タイル画面を上下左右にスワイプ | ページ送り |
| 下部のタグをタップ | 表示する機器を絞り込む |
グラフ上部の ‹ › |
前後の期間へ移動 |
| グラフをタップ | タップした日時を含む、1つ下の期間へ移動(年 → 月 → 週 → 日 → 時 → 10分) |
| グラフ下部の期間タブ | その細かさへ切り替え。見ていた日時はそのまま |
| 選んでいる期間タブをもう一度タップ | 現在の期間へ戻る |
| 右上の ⚙ | 設定画面 |
画面の明るさ、画面の向き、microSD への書き込み間隔、警告閾値(温度・湿度・CO2・電池残量)を変更できます。Grove 端子につないだENV Ⅲ UNITを使うかもここで選びます。最下部に異常再起動の記録があり、いつ・どの理由で再起動したかを後から確認できます。
「自動」にすると、部屋が暗くなったときだけ画面を消します。明るいときはスライダーで選んだ明るさに戻ります。
消えている画面に触れると点灯します。このときのタッチは操作として扱いません。 何が表示されているか見えない状態での操作は、ほぼ確実に誤操作になるためです。点灯してから 0.5 秒は同じく受け付けず、その後は通常どおりに操作できます。30 秒何もしなければまた消えます。
「暗いと判断する明るさ」で境目を決めます。同じ画面に今の明るさが出るので、実際の値を見ながら選んでください。「手動」にすると、明るさはスライダーの値に固定されます。
- 初回起動時は、時刻同期が済むまでグラフを開けません。 NTP 同期(起動後10秒程度)を待ってください。同期は12時間ごとに繰り返されます。2回目以降は本体のRTCから時刻を復元するので、起動直後から開けます。
- 電池残量の取得にはアクティブスキャンが必要です。 SwitchBot は電池残量だけをスキャン応答に載せているためです。本機から各機器へスキャン要求を送り、その応答を受け取ります。そのぶん SwitchBot 機器の電池をわずかに余分に消費します。(対象は電波の届く範囲にある SwitchBot 機器すべてで、本機への登録の有無は問いません) 尚、rev0.2.0では電池残量を読むためのアクティブスキャンを間欠化し、SwitchBot 機器の電池消費を抑制しました。
- 5分以上受信できない機器は「未受信」になります。 電波が届く範囲に設置してください。
- 月・年グラフは対象機器の記録全体を読み込みます。 記録が数ヶ月分たまると描画に時間がかかり始めます。(そのときは「データ読み込み中…」と表示されます)
- microSD が無くても動作しますが、履歴は RAM 上の24時間分のみで、電源を切ると消えます。
- 異常再起動の記録に、まれに電源の切/入が混ざります。 Tab5 では USB の抜き差しによる電源断が、ウォッチドッグによる再起動と同じ理由コードで返ります。区別できないため、この理由は記録しないようにしています。(本物の異常はパニックとタスク/割り込みウォッチドッグで拾えます) ただし電源の落ち方によっては「電圧低下」として返ることがあり、その場合は記録に残ります。
- 明るさはルクスではありません。 カメラが受け取った光の量を、露出とゲインで割った相対的な数値です。基準になる照度計を持っていないため換算していません。同じ部屋なら同じ値になりますが、他の照度計の数値とは比べられません。
- 明るさはカメラが向いている方向の明るさです。 画面と同じ側を向いているので、本体の置き方で値が変わります。真上を向けて置くと天井の照明を見ることになり、実際より明るく出ます。
- Grove 端子に挿せるセンサは1つだけです。 現在対応しているのは ENV Ⅲ UNIT です。
- CO2 の意味は機種で違います。 ENV PRO の CO2相当値はガス抵抗値からの推定で、MH-Z19B/C・SCD30・SCD40 の CO2 は実測です。グラフの項目名を出し分けていますが、同じグラフに並べて比べることはできません。
- ENV PRO は Tab5 の Grove 端子では使えません。 ガス抵抗値を空気質に換算する Bosch の BSEC2 ライブラリに、ESP32-P4 版が無いためです。ESP32 / ESP32-S3 版はあるので、M5StickC や M5AtomS3 に繋いで BLE で送る形(EnvProBeacon)で対応しています。
- CO2 センサも Tab5 の Grove 端子には対応していません。 Co2Beacon を書き込んだ M5StickC / M5AtomS3 から BLE で受け取る形になります。
- CO2 センサの校正には外気が要ります。 自己校正は既定で無効です(換気の少ない部屋では基準が狂うため)。半年〜1年に一度、屋外で手動校正してください。手順は Co2Beacon の README にあります。
- 空気質は電源投入直後には出ません。 ガスセンサの較正が済むまで、送信側が値を送らないためです。較正は時間の経過だけでは進みません。 きれいな空気と汚れた空気の両方に、それぞれ30分程度さらされる必要があります(Bosch の資料による)。進み具合は送信側の画面で分かります。
- Rev 0.1.0 の履歴は読めません。 記録の形式が変わったため、Rev 0.1.0 から更新した場合は、設定画面の「履歴データを消去」で消してから使ってください。
SwitchBot のブロードキャストデータの解析位置(温度・湿度・CO2・電池残量が何バイト目にあるか)は、Theengs decoder のデバイス定義を仕様情報として参照しました。解析コードそのものは本プロジェクトで独自に実装しています。
MIT License. 詳細は LICENSE を参照してください。
同梱の lv_conf.h は LVGL(MIT)付属のテンプレートを本プロジェクト用に改変したものです。
フォントファイル(BIZ UDゴシック、SIL Open Font License 1.1)はリポジトリに含めていません。
カメラのセンサ(SC202CS)を動かすための初期化レジスタ表と、露出・ゲインの設定値は、Espressif の esp-cam-sensor(Apache License 2.0)に含まれる同センサ用ドライバから取得しています。該当箇所は CameraSensor.cpp と Config.h にコメントで示してあります。
外部ライブラリは同梱していません。 本体・送信側ともに、利用者が Arduino IDE のライブラリマネージャで導入する形です。使用しているライブラリは各 README の「準備」に一覧があります。送信側が使う BSEC2(Bosch Sensortec)と M5Unit-ENV(MIT)も同様で、それぞれのライセンスに従います。
グラフ
- グラフをタップすると、その日時を含む1つ下の期間へ移動します。(年 → 月 → 週 → 日 → 時 → 10分)
- 期間タブで細かさを変えても、見ていた日時を保ちます。選んでいるタブをもう一度タップすると現在へ戻ります。
- 項目に空気質と呼気VOC相当値を追加。並びは温度・湿度・気圧・空気質・CO2・VOC です。
- 空気質のグラフには、最下部に学習状態(確からしさ)を色の帯で重ねます。項目のボタンを増やさずに、その区間の値がどれくらい確かかが分かります。
離れた場所のセンサ(独自 BLE ビーコン)
- M5StickC / M5AtomS3 に測定を任せ、その値を BLE で受け取れるようになりました。送信側のプログラムは2つあります。
- EnvProBeacon — ENV PRO(BME688)。温度・湿度・気圧・空気質・CO2相当値・呼気VOC相当値
- Co2Beacon — MH-Z19B/C・SCD30・SCD40。CO2 は実測値(SCD は温度・湿度も)
- どちらもボタン A 長押しで Web 設定に入り、加速度センサで画面の向きを自動調整します。BLE 送信を切れば単体の表示器としても使えます(送信中は画面右上に緑の丸)。
- Web 設定を抜けても再起動しません。測定と送信が途切れず、MH-Z19 の予熱や空気質の学習をやり直さずに済みます。(「全設定の初期化」のときだけ再起動します)
- CO2 センサの自己校正は既定で無効です。換気の少ない部屋では、その部屋の濃度を外気とみなして基準が下がるためです。手動校正の手順と基準の濃度は、センサごとのデータシートの条件に従います。
表示
- 独自ビーコンのタイルとグラフの項目は、機種が分かった時点で確定します。値が届く前でも並びは変わりません。空気質の較正中は
(0)のように学習状態だけが出ます。 - 空気質・CO2相当値・呼気VOC相当値を持つ機器のタイルは、温度・湿度を出さず、その3つを2段で表示します。位置は他の2段タイル(CO2計・ENV III)と同じ高さです。
- CO2 を持つ機器は、実測か推定かでグラフの項目名を出し分けます(
CO2/CO2相当)。 - グラフ画面の機種の欄には、独自ビーコンだけ読める名前(
ENV PRO/MH-Z19B/C/SCD30/SCD40)が出ます。記録の中では機種を表す1文字のままです。
記録
- 空気質・CO2相当値・呼気VOC相当値を履歴に追加。記録の形式は変えていないので、Rev 0.2.0 の履歴はそのまま読めます。
- 本体のRTC(RX8130CE)に対応。電源を切っている間も時刻を保持。
- Grove 端子の M5Stack UNIT ENV III に対応。(温度・湿度・気圧)
- 本体カメラを照度計として使い、部屋の明るさを記録。(映像記録はしていません)
- 部屋が暗いときに画面を消し、触れると点く動作を追加。
- バックライト輝度をスライダーで変更できるように。
- 電池残量を読むためのアクティブスキャンを間欠化し、SwitchBot 機器の電池消費を抑制。
- 電源の切/入が異常再起動として記録されないよう修正。
- 履歴の記録形式を変更。(形式のバージョンを持たせ、湿度を 0.1% 刻みに、気圧と明るさの枠を追加)
- 記録を「受信した項目だけ」に変更。受信していない値を古いまま書き続けないように。
- グラフの線が細切れになる問題を修正。(記録の間隔が長い項目は前後の実データを結ぶ)
- 1日グラフの最低・最高が時グラフと食い違う問題を修正。
- 初版リリース
作者: @rin_ofumi



