M5PaperS3で、充電を忘れられる週間天気表示を作った

毎朝、天気予報を見るためだけにスマートフォンを開くのが少し面倒でした。知りたいのは、今日とこの先数日の気温、雨の可能性、傘が必要そうかどうかです。そこで、M5Paper / M5PaperS3 の電子ペーパー画面を使って、壁に掛けっぱなしにできる週間天気表示システムを作りました。

いまは M5PaperS3 で運用していて、数週間単位で充電せずに動いています。壁への取り付けには、別途公開している M5PaperS3WallMountを使っています。電子ペーパーなので表示が紙のように落ち着いていて、普段の生活空間に置いても違和感が少ないのが気に入っています。

ソースコードはこちらです。

何を表示しているか

表示しているのは OpenWeather の One Call API から取得した 7 日分の予報です。

  • 天気アイコン
  • 最高気温、最低気温
  • 降水確率
  • 降水量
  • 更新時刻
  • NTP 同期状態
  • バッテリー残量と電圧

画面は横向きに使い、上部に天気アイコンと気温の折れ線、下部に降水確率と降水量のバーを置いています。スマートフォンの天気アプリほど細かい情報は載せず、朝に一目で判断できる情報だけに絞りました。

更新間隔は include/secrets.hUPDATE_INTERVAL_SECONDS で指定します。私の環境では 6 時間ごとの更新で十分でした。更新時だけ Wi-Fi に接続し、天気データと NTP 時刻を取得し、描画したら Wi-Fi を切ってスリープに入ります。

構成

開発環境は PlatformIO + Arduino framework です。ライブラリは主に M5Unified と ArduinoJson を使っています。

platformio.ini には、M5Paper と M5PaperS3 の両方の環境を用意しました。

  • m5paper
  • m5paper-lightsleep
  • PaperS3

M5Paper は PlatformIO に専用 board 定義がないため、ESP32 + PSRAM が使える m5stack-fire をベースにしています。M5PaperS3 は esp32-s3-devkitm-1 を使い、PSRAM や USB CDC まわりの build flag を追加しています。

天気アイコンは data/icons/ に PNG を置く方式です。リポジトリにはアイコン画像そのものは含めず、data/icons/README.mdに必要なファイル名だけを記録しています。第三者素材をそのまま再配布しないためです。PNG がない場合でも、コード内の簡易ベクター描画にフォールバックするようにしてあります。

Codexを使った開発がかなりうまくいった

今回の開発では Codex が非常に役に立ちました。特によかったのは、組み込み機器の細かい試行錯誤を、コードとログを見ながら小さく前進させられたことです。

最初に欲しかったのは「電子ペーパーに天気を表示して、しばらく寝る」だけでした。しかし実際に動かすと、すぐに細かい課題が出てきます。

  • M5Paper と M5PaperS3 で初期化や電源管理の挙動が違う
  • Deep Sleep から期待通りに起きない個体や構成がある
  • Wi-Fi 起動後にバッテリー電圧の読み取りが不安定になる
  • 日本語フォント、曜日表示、ラベル位置の調整が必要
  • OpenWeather API の JSON が大きく、メモリ確保に余裕が必要
  • PaperS3 の Arduino-ESP32 3.0.5 では HTTPClient の HTTPS begin() が通らない構成がある

こうした問題は、ひとつひとつは小さいのですが、手で調べながら直すとかなり時間を使います。Codex には、実装を読ませて、ビルド設定やコードコメント、エラー時の表示、スリープの分岐を少しずつ整理してもらいました。

特に助かったのは、M5Paper では通常 Deep Sleep を使い、必要な場合だけ PAPER_FORCE_LIGHTSLEEP で Light Sleep に切り替える構成にしたところです。Light Sleep から戻った後は ESP.restart() して、アプリ全体を setup()から再実行する形にしています。これにより、通常動作のコードパスを単純に保てました。

また、失敗時の扱いも実用上は重要でした。Wi-Fi 接続や天気取得に失敗した場合、通常の 6 時間待ちではなく 10 分後に再試行するようにしています。画面にもエラー内容と再試行予定を表示するので、設置後に何が起きているか分かります。

難しかった点

一番難しかったのは、低消費電力動作と復帰の安定性です。電子ペーパー表示は、画面を書き換えない限り電力をほとんど使わないので、天気表示には非常に向いています。一方で、実用的に「壁に掛けっぱなし」にするには、Wi-Fi、RTC、バッテリー読み取り、スリープ復帰の順序をかなり気にする必要がありました。

現在の実装では、起動直後にバッテリー情報を読み、次に Wi-Fi 接続と NTP 同期を行い、OpenWeather から予報を取得し、画面描画後に Wi-Fi を切ってスリープします。バッテリー残量が API から取れない場合は、電圧から簡易推定します。

もうひとつの難所は HTTPS でした。PaperS3 の一部構成では HTTPClient が HTTPS の begin()を受け付けないため、現時点では OpenWeather API への接続を http:// にしています。これは README にも注意事項として書いてあります。家庭内の壁掛け天気表示としては許容していますが、将来的には Arduino-ESP32 側の更新や証明書処理を見直して HTTPS に戻したいところです。

使い方

使うには、まずリポジトリを取得します。

git clone https://github.com/mokjpn/M5PaperWeatherU.git
cd M5PaperWeatherU

次に include/secrets.h-exampleを参考にして、include/secrets.h を作成します。

設定するのは以下です。

  • Wi-Fi SSID
  • Wi-Fi パスワード
  • OpenWeather API キー
  • 緯度、経度
  • 表示用の都市名
  • 更新間隔

天気アイコンを使う場合は、data/icons/README.mdに書かれている名前で PNG を用意し、PlatformIO の uploadfsで LittleFS に書き込みます。

M5PaperS3 に書き込む場合は、PlatformIO の環境として PaperS3 を選びます。M5Paper の場合は m5paper、Deep Sleep 復帰に問題がある個体では m5paper-lightsleep を試せるようにしてあります。

しばらく運用してみて

M5PaperS3 での運用はかなり良好です。更新頻度を数時間おきにすれば、画面は常時見えているのに、消費電力はかなり低く抑えられます。スマートフォンやスマートディスプレイと違って、通知も光も音もなく、ただ天気だけがそこにあるのがよいです。

壁マウントと組み合わせると、実験基板っぽさがかなり減ります。M5PaperS3WallMount は 3D プリント前提の簡単なマウントですが、壁に固定してしまうと「家電」らしい見た目になります。

今回のような小さな実用品は、Codex との相性がかなりよいと感じました。最初から完璧な設計を考えるより、動かして、ログを見て、気になるところを直していく。その反復を速く回せるのが大きいです。結果として、日常的に使えるものになりました。

リポジトリはこちらです。