壁のスイッチプレートに入る「照明制御付き 24 時間カレンダータイマー」を作る
M5Stack 版を ESP32-S3 基板へ完全移植し、四季の色温度タイマーを足すまで
限定公開・noindex の開発記録。数値には〔仕様〕〔実測〕〔推定〕を付けている。
1. 何を作ったか
これまで M5Stack Core2 で動かしていた「カレンダーダイマー」(季節×時間帯で照明シーンを自動で切り替えるタイマー) を、壁のスイッチプレートに収まる自作基板 SW6LCD_RTC に移した。
- CPU 基板: S3DmxRj1 v4 (ESP32-S3-WROOM-1-N8、DMX は SN75179B 全二重)
- パネル: 1.3 インチ 240×240 IPS 液晶 (ST7789)、RTC は DS3231MZ+ (温度補償つき、CR1220 バックアップ)、押しボタン 6 個 (S4〜S9)
- ファーム: M5 版のタイマー・DMX シーンエンジン・Web 画面をほぼそのまま移し、四季の色温度タイマーを新しく足した
2. 移植の方針: 「書き直さない」
M5 版のファームは約 1 万 4 千行。DMX のシーン計算だけで 3,600 行ある。これを新しく書き直すと、現場で動いている M5 版と挙動がずれる。そこで M5 のコードをそのまま持ってきて、ハードに触る部分だけ差し替える 方針にした。
| 部分 | M5 版 | SW6 版 |
|---|---|---|
| DMX シーンエンジン (Scene0〜20、1/f ゆらぎ・RGBW パターン・フェード) | dmx_scene_controller.cpp | ほぼ無改変。DMX を送り出す 2 か所だけ差し替え |
| 季節タイマー・時刻表・保存 (EEPROM) | schedule_manager.cpp | 無改変 (読み込むヘッダだけ変更) |
| Web 画面 (時刻表・シーンの編集) | LittleFS の index.html + WebSocket | 同じ index.html をファームに埋め込み (書込みは 1 回で済む) |
| コマンド (RUN / SET / DMX / SCENE / PARAM …) | BLE (WebBT) の中に組み込み | BLE から切り離して、シリアル・WebSocket・HTTP 共通に |
| 画面 | 320×240 (左に時計とカレンダー、右に DMX モニター) | 240×240 に左パネルを同じ座標・フォント・色で配置、右端は色温度バー |
| 操作 | タッチ + A/B/C ボタン | 押しボタン 6 個 (2 段 × 3 列。右の列 = 色温度/シーンの +/−、左下 = TIME ON/OFF、中下 = 時刻表どおりに戻す、中上長押し = 時刻表の編集、左上 = 時刻合わせ。LED は押したボタンだけ光る) |
M5 の DMX 出力は esp_dmx ライブラリだったが、SW6 は同じ ESP32-S3 系の他の機種で実績のある「UART2 を直接たたく」方式にした。フレームの中身と送る間隔 (変化時 25ms・変化なし 100ms) は M5 のまま。
3. 新機能: 四季の色温度タイマー
M5 版でも DMX の CH11・CH12 は「色温度」のチャンネルで、時間帯ごとに値が決まっていた (朝 180 / 昼 255 / 夕 120 / 夜 10)。ただし 4 季節とも同じ値 だった。
SW6 版ではこれを 季節 × 時間帯の表 にして、Web から編集できるようにした。値は 0 = 2700K (電球色) 〜 255 = 6500K (昼光色)。初期値は、体内時計に合わせる一般的な考え方 (朝はやや白、昼は白、夕方は暖色、夜は電球色。夏は全体に白寄り、冬は暖色寄り) で次のようにした。
| 季節 | 朝 | 昼 | 夕 | 夜 |
|---|---|---|---|---|
| 春 | 5000K | 6000K | 3500K | 2700K |
| 夏 | 5500K | 6500K | 4000K | 3000K |
| 秋 | 5000K | 5500K | 3500K | 2700K |
| 冬 | 4500K | 5000K | 3000K | 2700K |
| 切替時間 | 15 分 | 10 分 | 15 分 | 15 分 |
- 時間帯が変わるとき、表の「切替時間」をかけてゆっくり色が変わる (直線フェード)。停電から戻ったときは待たずにすぐ今の色にする。
- 2 系統 (CH11・CH12) は別々の値にできる (例: 居室と廊下で色温度を変える)。
- M5 版の全シーン動作 (以前の機能) にも Web で切り替えられる。
Web の設定画面 (/ct)
スマホやパソコンのブラウザで本体の IP を開くと、M5 と同じ画面の右上に「色温度タイマー設定」が出る。設定画面では次のことができる。
- 今の色温度 (2 系統の色見本と K)
- 動作モード (色温度タイマー / M5 全シーン) と外部時刻同期 (NTP) の ON/OFF
- 四季 × 時間帯の表: セルを押すとスライダーで K と切替時間を変えられる。「試す」で今すぐその色にし、「時刻表どおりに戻す」で元に戻る
4. 時刻の正確さ
| M5 Core2 版 | SW6 版 | |
|---|---|---|
| RTC | BM8563 + 水晶、温度補償なし (精度規定は未確認。一般的な水晶なら月 ±52 秒〔推定〕) | DS3231MZ+、温度補償つき ±5ppm = 月 ±13 秒〔仕様〕 |
| 時刻合わせ | 起動時に NTP、その後 WiFi を切る。毎日 0:00:59 に再起動 | NTP を 1 時間ごと。設定でいつでも OFF にでき、OFF なら RTC だけで動く |
| 実測 | NTP より約 1 秒遅れ (2026-10-10 に 1 回測定)〔実測〕 | NTP 同期直後の補正量 0 秒〔実測〕。長期のずれは測定中 |
参考: 同種の市販デジタルタイムスイッチ (オムロン 24 時間式) の月差は ±15 秒 (25℃)。SW6 は NTP なしでも同等以上、NTP ありなら常に 1 秒未満。
コードを読み比べて分かったこととして、M5 版の「毎日 0:00:59 の再起動」と「起動するたびに RTC を 1 秒進める補正」が組み合わさると、NTP がない環境では毎日 1 秒ずつ進む作りになっていた (月 +30 秒〔推定〕)。SW6 版ではこの 2 つを外した。再起動しないので、深夜に DMX が一瞬途切れることもなくなった。
5. 移植でつまずいたところ
- 時計の色が水色になった: 液晶ライブラリ (LovyanGFX) は、色の値を 32 ビットの変数で渡すと 24 ビット色として解釈する。16 ビット色の黄緑を 32 ビット変数に入れていたため水色になった。色は必ず 16 ビット型で持つ。
- Web 画面が空で返ってきた: 115KB の HTML を、ライブラリが文字列として丸ごとメモリにコピーしようとして失敗していた (応答は 200 なのに 0 バイト)。フラッシュから直接送る形に変えて解決。
- 時刻表の一部が 0 になった: M5 版は「編集画面を開いたときに 4 季節分を読み込む」作り。SW6 には編集画面がないため読み込みが抜け、閉じる操作で他の季節を 0 で保存してしまった。起動時と編集開始時に 4 季節を読むようにして解決し、値も元に戻した。
- 色温度の表示が 3510K になった: 0〜255 の 1 段は約 15K なので、10K 単位で表示すると設定値 (3500K) と合わない。50K 単位にして、設定した K と表示が一致するようにした。
- 起動後、NTP が数分同期しないことがあった: WiFi がつながる前に NTP を始めていたため、最初の問い合わせが失敗すると再試行まで待たされた。WiFi がつながった時点で開始し、60 秒同期しなければやり直すようにしたところ、接続から約 2 秒で同期するようになった。
どれも実機の写真・ログで見つけて直した。
6. これから
- RTC のバックアップ電池 (CR1220) の確認: 試験機は電源を切ると時刻を失った。電池の有無・電圧・向きを確認する。
- DMX 波形を PicoScope で測る (M5 版と送り方が違うため)。
- NTP を切った状態で、M5 版と並べて 1〜4 週間の時刻のずれを測る。
- 照明器具をつないでの実地確認 (色温度 2 系統の器具)。