↓メインコンテンツへスキップ

PowerSAGMonitor 第3部 運用開始編 ── Home Assistant 連携とチューニング

この記事について

この記事の内容および実装は Claude Code を使用して開発・記述し、人間が検証・修正しています。文中で 「私」 は人間であり、 「Claude」 は AI が主語であることを表しています。

本 blog には コメント機能があります。GitHub アカウントで投稿できます。

はじめに #

この記事は、家の分電盤で停電・瞬停 (ごく短い停電)・電圧の低下 (サグ) を記録する計測器 PowerSAGMonitor の3部作の第3部である。 第1部 (概要編) で装置の全体像を、 第2部 (制作編) で設計から設置までを紹介した。ここでは、Home Assistant (以下 HA。家の機器の値を集めてグラフや通知を作るソフト) との連携、ファームウェア (マイコンで動くソフト。以下ファーム) のチューニング、苦労した不具合、そして現在の運用状況を紹介する。

Zigbee2MQTT への参加 #

Zigbee は、消費電力の小さい近距離無線の規格で、照明やセンサーなどのスマートホーム機器で使われている。ここでは、この記事に必要な要点だけを書く。

Zigbee の機器は、網の目 (メッシュ) のようにつながってネットワークを作る。中心にはコーディネータ (Zigbee の親機。私の家ではサーバに挿した USB ドングル) がいて、コンセントから給電されている Zigbee の機器はルーターとして電波を中継する。ボックス (装置の樹脂ケース全体) は子機として参加し、近くのルーターかコーディネータのどれか 1 台を親にして、親を通して通信する。

コーディネータが受け取ったデータは、Zigbee2MQTT (Zigbee の機器を HA につなぐソフト) が MQTT (機器とソフトの間で値をやり取りする仕組み) で HA に渡す。

ボックスから Home Assistant までの通信の経路。ボックスは Zigbee の無線でルーター経由、または直接コーディネータにつながる。コーディネータは USB で Zigbee2MQTT に、Zigbee2MQTT は MQTT で Home Assistant につながるボックスZigbee の子機ルーター中継する機器コーディネータUSB ドングルZigbee2MQTT変換スクリプトHome Assistant記録・グラフ直接つながることもUSBMQTTZigbee の無線 (メッシュ)サーバの上のソフト

標準の電力測定の仕組み (クラスタ。Zigbee で機能ごとに決められたデータの型) は使わず、メーカー独自のクラスタを 1 つ作って、4 種類のデータをバイト列で載せた。標準のクラスタは 1 つの相しか表せず、L1・L2 の値が別々のフレームに分かれてしまうこと、イベントの記録が標準には無いことが理由である。バイト列は、Zigbee2MQTT の変換スクリプト (external converter) が名前の付いた値に直す。

標準のクラスタとメーカー独自のクラスタの比較。標準のクラスタは 1 つのエンドポイントに 1 相ぶんで、L1・L2 の電圧・電流・有効電力・電力量がそれぞれ別のフレームになる。独自のクラスタでは、状態・電圧・電流・有効電力・電力量・無効電力を 54 バイトのバイト列 1 つにまとめて 1 フレームで送り、変換スクリプトが名前の付いた値に直す標準のクラスタElectrical Measurement (0x0B04)・Metering (0x0702)1 つのエンドポイントに 1 相ぶん。L1・L2 で 2 つ立てるエンドポイント 1 (L1)電圧1 フレーム電流1 フレーム有効電力1 フレーム電力量1 フレームエンドポイント 2 (L2)電圧1 フレーム電流1 フレーム有効電力1 フレーム電力量1 フレーム値ごとにフレームが分かれ、同じ 1 分の値が別々に届く。イベントの記録は標準に無いメーカー独自のクラスタ番号 0xFC80 (メーカー独自の範囲から選んだ)1 分ぶんのサマリ (summary) を、54 バイトのバイト列 1 つにまとめて 1 フレームで送る状態・番号など電圧平均・最小・最大電流L1・L2有効電力L1・L2電力量L1・L2・積算無効電力L1・L2012242836445254バイト同じクラスタに、イベント (38 バイト)・起動の記録 (21 バイト)・診断 (50 バイト) のバイト列も置く変換スクリプトZigbee2MQTT の external converter名前の付いた値に直して HA へvoltage_l1・voltage_min_l1・current_l1・power_l1・energy_l1 …

報告は受領の確認つきで送る。イベントは確認が返るまでボックスの中に残し、つながったときに古い順に送り直す。1 分ごとのサマリは送り直さないが、電力量は積算値なので、次の値で追いつく。

イベントの送り直しの仕組み。つながらない間は、終わったイベントをフラッシュメモリの列に足していき、確認が返らない件は消さずに残す。つながったら、古い順に 1 件ずつ送り、受領の確認が返った件を列から外して次の件へ進むつながらない間ボックス (フラッシュメモリ)#5#6#7古い新しい未送のイベント終わった件×送っても確認が返らない→ 消さずに残すコーディネータ→ Zigbee2MQTT→ HAつながったらボックス (フラッシュメモリ)#5#6#7古い新しい未送のイベント古い順に 1 件ずつ送る (#5 から)受領の確認 (ACK)確認が返ったら、その件を列から外して次の件 (#6) へコーディネータ→ Zigbee2MQTT→ HA1 分ごとのサマリは送り直さない。電力量は積算値なので、次に届いた値で追いつく

Home Assistant での活用 #

取得値 #

いつ届くか主な値
1 分ごとL1・L2 の電圧 (平均 voltage_l1・最小 voltage_min_l1・最大 voltage_max_l1)、電流、有効電力、無効電力、電力量 (積算)、周波数、AC が来ているか、自己診断、時刻合わせ
イベントが終わったとき種類 (event_type)、始まりの時刻、長さ、L1・L2 の最小と最大の電圧、直前の平常の電圧、電流の最大、通し番号 (event_seq)
起動したあと前の起動の記録 (動いた時間・止まった理由など)
10 分ごと診断 (電波の質・送れた数と送れなかった数・ファームの更新の様子)
Home Assistant の PowerSAGMonitor のデバイス画面の一部。左にデバイス情報 (接続元 Zigbee2MQTT Bridge・ファームウェア 1.0.0)、右にセンサーの値の一覧 (AC が来ているか・起動の通し番号・前の起動の記録など) が並ぶ

HA のデバイス画面 (一部)。ボックスから届いた値が並ぶ

電圧の最小を見る #

ボックスは、半サイクル (50Hz の交流の波の半分。10ms) ごとに求めた電圧を、2 段階でまとめて送る。まず 1 秒ぶん (100 個) から平均・最小・最大を出し、次にそれを 1 分ぶん (60 個) まとめる。最小は「1 秒ごとの最小」のさらに最小なので、1 分ごとの「電圧の最小」には、その 1 分でいちばん低かった半サイクルの値が入る。

電圧の値のまとめ方。半サイクル (10ms) ごとの電圧の実効値が 1 秒に 100 個あり、1 秒ごとに平均・最小・最大にまとめる。それを 1 分ぶん 60 個集めて、平均の平均・最小の最小・最大の最大を 1 分ごとに送る。半サイクルごとの値は、別にイベントの判定にも使う半サイクル (10ms)電圧の実効値を 1 秒に 100 個いちばん低い 1 個 ↑1 秒ごと平均100 個の平均最小100 個の最小最大100 個の最大1 分ごとに送る平均60 個の平均最小60 個の最小最大60 個の最大voltage_l1・_min_l1・_max_l1イベントの判定1 個ずつ、しきい値と比べる

イベントの判定は、このまとめとは別に、半サイクルごとの値を 1 個ずつしきい値と比べて行う。1 分ごとの最小を見れば、イベントのしきい値に届かない浅い電圧の下がりも、グラフで見える。

10 月 25 日の L1 の電圧の 1 日分のグラフ。平均・最小・最大の 3 本が 101〜104V 付近を動き、21 時台に最小が 97V 台まで下がっている

10 月 25 日の L1 の電圧。青が平均、黄が最小、赤が最大。21:41 に最小が 97.25V まで下がった

この日の 21:41 の下がりは、ふだんの約 102V に対して約 95% で、イベントのしきい値 (90%) には届いていない。1 分ごとの平均だけを見ていたら気づかない動きである。

エネルギー画面 #

電力量は減らない積算値なので、HA の「エネルギー」画面に L1・L2 をそのまま登録できる。

Home Assistant のエネルギー画面。11 月 2 日の 1 時間ごとの電力量の棒グラフと、L1 7.9kWh・L2 7.77kWh の合計の表

HA のエネルギー画面 (11 月 2 日)。L1 と L2 を別々の電力量として登録してある

停電の通知 #

停電のイベントは、図のタイミングとデータ構成で HA に届く。停電の間は送らず、復電して再参加したあとに 1 件にまとめて送る。

停電のときに、いつ何が届くかの模式図。停電が始まるとボックスは始まりを記録し、EDLC で約 1 分動いたあと止まる。停電中はルーターも止まるので送らない。復電すると起動して再参加し、種類・始まりの時刻・長さ・通し番号・L1 と L2 の最小と最大の電圧・直前の平常の電圧・電流の最大を 1 件 38 バイトにまとめて送る。HA では届いて記録に残るが、通知を送る部分は未実装① 停電始まりを記録② 復電起動して再参加③ 送る1 件にまとめるAC (100V)あり停電ありボックス測定中EDLC で約 1 分止まる起動・再参加測定中停電中は送らない (ルーターも止まる)Home Assistant届いて記録に残る通知を送る (未実装)時間の長さは模式的③ で送る 1 件 (38 バイト) の中身種類 (停電・サグ・スウェル)始まりの時刻長さ通し番号 (event_seq)L1・L2 の最小と最大の電圧直前の平常の電圧電流の最大

HA では、イベントの通し番号 (event_seq) が変わったら通知を送る仕様を検討中だが、未実装である。いまはイベントが記録と画面に残るだけで、通知は飛ばない。

ファームの構成 #

ファームは ESP-IDF (ESP32 の公式の開発環境) で作った。受け持つことは次の 5 つ。

ファームの流れ: 測る、計算する、見分ける、記録する、送る測る5ch毎秒 5,000 回計算する半サイクルごと実効値・電力見分けるサグ・スウェル停電 → 1 件に記録するイベント 32 件電力量送るZigbee でサマリ・イベント
  1. 測る: 5 つのチャンネル (電圧 2・電流 2・中点 1) を、それぞれ 1 秒に 5,000 回読む
  2. 計算する: 電圧が 0V を横切る点で区切って、半サイクルごとに電圧と電流の実効値を求める。瞬時値を掛け合わせて有効電力・無効電力・電力量を出す
  3. 見分ける: 半サイクルごとの電圧を平常時の基準と比べ、サグ・スウェル (電圧の上昇)・停電の始まりと終わりを決めて 1 件にまとめる
  4. 記録する: イベント (直近 32 件)・電力量・起動ごとの記録を、フラッシュメモリの専用の区画に置く
  5. 送る: サマリ・イベント・起動の記録・診断を Zigbee で送る
起動時の自己診断

ボックスは、起動するたびに、計算と判定の処理が正しく動くかを自分で確かめる。センサーの値の代わりに、ファームの中で作った 50Hz の作り物の波形 (大きさがわかっているもの) を処理に通し、出てきた電圧が想定どおり (誤差 ±0.5% 以内) かを見る。

結果は 1 分ごとのサマリに載せて HA に送り、だめならマイコンの LED を赤く点ける。この結果は、次に書く OTA (Over-The-Air の略。無線でのファームウェア更新) の合格の条件にも使う。

なお、この作り物の波形が 50Hz なのは、ボックスを 50Hz の地域 (東日本) で使う前提で作ったからである。半サイクルの区切りは電圧が 0V を横切る点で決めるので、60Hz にも追従する作りにはなっているが、電力の計算の補正などに 50Hz を前提にした値が残っていて、60Hz では試していない。

ファームは、ボックスを開けずに Zigbee 経由で書き換えられる (OTA)。書き込み先を 2 つ用意して動いていない方へ書き、新しいファームは「仮」で起動する。自己診断に通り、サマリが 1 通届いたら合格で、10 分で合格しなければ前のファームに戻る。

判定が動くことの確認 #

サグなどを見分ける判定が動くことは、分電盤に付ける前の 10 月 4 日に机の上で確かめた。基板と同じ電源タップにドライヤー (1200W) をつなぎ、強で約 10 秒ずつ 2 回入れた。

アクリル板に取り付けた基板と、電源タップにつないだ測定治具

10 月 4 日の机の上での測定

ドライヤーを 2 回入り切りしたときの電圧と電流のグラフ。電流が約 11.3A 流れる間、電圧は約 102V から約 97.4V に下がる

ドライヤーの入り切りと電圧・電流。V_L1・I_L2 はチャンネルの名前で、実際の相ではない

ドライヤーを入れると、約 11.3A が流れて電圧は約 102V から約 97.4V に下がる。ただ、これは約 95% なので、本番のしきい値 (平常時の 90%) には届かず、イベントにはならない。

そこで、しきい値を 97% にした試験用のファームで測ると、サグが 2 件 (10.68 秒・11.35 秒) 記録された。97% はこの試験のときだけの値で、本番は 90% である。

しきい値 97% の試験で、電圧が下がった 2 回の区間がサグとして判定されたグラフ

確認用のしきい値 97% でのサグの判定。網掛けの区間が記録されたサグ

チューニング #

OTA を 47 分から 3 分へ #

ボックスは分電盤の横で蓋を閉じて使うので、ファームは無線で書き換えたい。ところが、最初に動いた Zigbee の OTA では、1 回の書き換えに約 47 分かかった。

ファームはこれからも直していく。書き換えて試し、だめならまた直す、というくり返しのたびに 47 分待つのでは長すぎる。書き換えに失敗したときの手戻りも考えると、できるだけ短くしておきたかった。試行錯誤の結果、約 3 分まで縮められた。経緯は次のとおり。

段階やったこと結果
1Wi-Fi で書き換える仕組みを作った動かない (後述)。Zigbee の標準の OTA に切り替え
2Zigbee の OTA (圧縮なし・1 ブロック 50 バイト)584KB に約 47 分 (207 バイト/秒)
3中身を zstd で圧縮し、受け取りながら展開約 56% に縮んで約 28 分
4配る側の待ち時間と、受け取り中の問い合わせの間隔を短くほとんど変わらない。診断の値を足して測ると、1 ブロックの往復が 241ms で一定だった
51 ブロックを 64 バイトに約 23 分。1 ブロックずつ頼む方式ではここが頭打ち
6「ページ要求」(1 回の要求でまとまった量を続けて送らせる) を自前で実装Zigbee2MQTT の中身のソースを読んで癖に合わせ、PC の上に作った相手で試験した
7本番で試すと1 ブロックも届かないログを詳しくすると、コーディネータ (Zigbee の親機) が 64 バイトのブロックを「長すぎる」と断っていた。中継の経路しだいで載せられる長さが変わる
850 バイトに戻した184 秒 (約 3 分)

教訓は 2 つある。速くする手を試す前に、どこで時間を使っているかを測る仕組みを先に入れること。そして、ログに何も出ない失敗は、ログを詳しくするまでわからないこと。

停電の終わり際の起動ループと、58 秒への延長 #

ボックスは、停電の始まりをフラッシュメモリに記録するため、EDLC (電気二重層コンデンサ) にためた電気で、停電のあとも 1 分ほど動き続けるように作ってある。EDLC は電池と違い、電気を使うにつれて電圧がだんだん下がっていく。電圧がマイコンの動ける下限を切ると、マイコンはリセットされる。

停電の試験のあと、起動の通し番号が 1 つでなく 5〜7 進んでいた。USB をつながない本番の形ではログが見えないので、Claude は、起動ごとの記録 (始まりの理由・動いた時間・終わりの理由) をフラッシュに残し、復電後に Zigbee で送る仕組みを足した。復電後にその記録を見ると、停電から約 39 秒で最初の電圧低下が起き、そのあと「起動 → 5 秒で電圧低下」を 5〜6 回くり返していた。下限ぎりぎりの電圧で、マイコンが起動しては止まっていたことになる。

停電からの秒数と電源の電圧の概念図。改善前は約 39 秒で動作の下限に達し、そのあと起動と停止を 5〜6 回くり返す。改善後は電圧の下がり方がゆるやかになって約 58 秒まで動き、そのあとは眠って待つ改善前最後に起動と停止をくり返す電源の電圧0204060停電からの秒数動作の下限起動と停止を 5〜6 回約 39 秒改善後停電中の送信を減らし、最後は眠って待つ電源の電圧0204060停電からの秒数動作の下限眠って待つ約 58 秒

Claude は 2 つの手を打った。1 つは、電圧低下のリセットから起きたときは、無線もフラッシュも触る前に AC が来ているかを確かめ、来ていなければ 5 秒ずつ眠って待つようにしたことである。これで起動のくり返しは消え、復電後の通し番号は 1 つだけ進むようになった。この時点で、停電中に動ける時間は約 42 秒になった。

もう 1 つは、停電中は毎分のサマリを送らず、親への問い合わせも 30 秒ごとに間引いて、電気の消費を減らしたことである。これで、停電中に動ける時間は約 58 秒に延びた。

分電盤の横だと Zigbee に再参加できない #

ボックスは、起動のたびに Zigbee のネットワークに参加し直す (再参加)。このとき、近くのルーターやコーディネータの電波を聞き、親にする相手を自動で選ぶ。ところが、机の上では再参加できるのに、分電盤の横で起動すると再参加できなかった。

原因は LQI (受信した電波の質を 0〜255 で表した値。おおまかには電波の強さの目安で、大きいほどよい) の下限である。ESP の Zigbee ライブラリは、LQI が既定の下限 (32) に届かない相手を、親の候補から外す。分電盤の横では、親になれる相手の電波は聞こえていたものの、LQI が 9〜10 と低く、すべて候補から外れていた。

Claude は下限を 0 にして、電波の弱い相手でも親に選べるようにした。つながったあとは、この弱さでも通信は返る。電源を入れ直して起動した 59 回のうち 59 回、約 5.8 秒で再参加できた。

再参加の流れと LQI の下限。起動する、近くのルーターやコーディネータの電波を聞く、LQI が下限以上の相手から親の候補を選ぶ、選んだ親を通して再参加する、の 4 段階のうち、親の候補を選ぶ段階の下限を直した。直す前は下限が 32 で、LQI 9〜10 の相手はすべて候補から外れて再参加できなかった。下限を 0 にすると候補になり、59 回中 59 回、約 5.8 秒で再参加できた① 起動するネットワークに戻る② 電波を聞くルーター・コーディネータ③ 親の候補を選ぶLQI が下限以上の相手④ 再参加する選んだ親を通す↑ ここの下限を直した直す前下限 32 (ライブラリの既定)候補から外す範囲下限 32聞こえた相手 (LQI 9〜10)→ 候補なし。再参加できない016324864… 255LQI直したあと下限 0下限 0聞こえた相手 (LQI 9〜10)→ 候補になり、再参加できる59 回中 59 回、約 5.8 秒016324864… 255LQILQI: 受信した電波の質 (0〜255、大きいほどよい)。図は 0〜64 を拡大している

苦労したこと #

Wi-Fi が使えなかった原因は水晶のずれ #

Zigbee はセンサー向けの規格で、通信の速さは Wi-Fi よりずっと遅い。そこで、ファームの書き換え (OTA) は、はじめは Wi-Fi で行うつもりで、その仕組みを作った (「OTA を 47 分から 3 分へ」の表の 1 段目)。

ところが試すと、ボックスから Wi-Fi のアクセスポイントが 1 台も見えなかった。すぐそばに置いたスマホのテザリングも見えない。nanoESP32-C6 の純正のサンプルでも同じで、送信も受信もできない。一方で、同じ無線の回路・同じアンテナを使う Zigbee は通る。

Claude は、マイコンの時計を 1 秒ごとに出力させ、NTP (時刻合わせの仕組み) で合わせた Raspberry Pi の時計と 325 秒比べた。すると、マイコンの水晶 (時計の基準になる部品) が −202ppm ずれていた (2.44GHz で約 −490kHz)。Wi-Fi が受かるのは ±20ppm 前後までである。Zigbee の変調はずれに強いので通っていた。

nanoESP32-C6 は、仕様の上では Wi-Fi 6 に対応している。水晶のずれがここまで大きいのは、今回買った個体の初期不良だった可能性がある。今回は Wi-Fi の利用はあきらめ、送るものも書き換えもすべて Zigbee で進めることにした。OTA を Zigbee のまま縮める工夫をしたのは、このためである。

毎分 54 バイトのメモリ書きつぶし #

圧縮した OTA (「OTA を 47 分から 3 分へ」の表の 3 段目) を試していたとき、書き換えが 98% まで進んだところで、マイコンが落ちた (異常を検出してリセットした)。本来は最後まで受け取り、新しいファームで起動するはずであった。新しく入れた展開の処理を疑ったが、落ちた場所はメモリの点検の処理で、メモリはその前から壊れていた。

原因は、ESP の Zigbee ライブラリの使い方にあった。このライブラリは、文字列の値を入れるメモリ空間を「登録したときの長さ + 1」バイトしか割り当てない。毎分のサマリ (54 バイト) の値を長さ 0 で登録していたので、1 バイトのメモリ空間に、毎分 54 バイトを書いていた。はみ出した分は、となりにあるメモリの管理領域まで書きつぶしていた。これは分電盤に取り付けた日から続いていた。

メモリの書きつぶしの概念図。改善前は、割り当てられた 1 バイトに 54 バイトを書き、となりの管理領域まで書きつぶしている。改善後は、65 バイトを割り当て、54 バイトがその中に収まる改善前管理領域管理領域ほかのデータ毎分 54 バイトを書く↑ 割り当てた 1 バイトはみ出して、となりの管理領域まで書きつぶす改善後管理領域割り当てた 65 バイト管理領域ほか毎分 54 バイトを書く割り当てたメモリ空間の中に収まる

Claude は、64 バイトで登録してから長さを 0 に戻すように直した。実機で OTA を流す再現を作り、直す前は約 60 秒で壊れ、直したあとは最後まで通ることを確かめた。落ちた場所が原因とは限らない。大きな処理 (展開) が、前からある小さな壊れを表に出しただけであった。

中点の電圧が 0.3V 高かった #

第2部で紹介したように、交流の信号は 1.65V の中点を中心に振れるようにして ADC に渡している。中点は 3.3V を抵抗 2 本で半分にして作り、その電圧をマイコンのピン (GPIO6) でも読んでいる。ところが、基板を組んでマイコンを挿すと、1.65V のはずの中点が 1.92V あった。中点がずれると、信号が 0〜3.3V の範囲の片側に寄り、測れる範囲が狭くなる。

マイコンのピンのプルアップ (入力を電源側へ弱く引く抵抗) が中点を押し上げていると考えたが、プルアップを外す命令では直らない。Claude がピンの設定のレジスタを 1 つずつ戻して確かめると、このプルアップは、ふつうのプルアップの設定ではなく、そのピンの JTAG の機能に付いていた。ピンを普通の入出力の機能に切り替えると外れる。

中点の電圧とマイコンのピンの内部の概念図。JTAG の機能のままだと内部のプルアップがつながり、ピンから中点へ電流が流れ込んで 1.92V になる。普通の入出力の機能に切り替えるとプルアップが外れ、1.65V になるJTAG の機能のまま電源を入れた直後の既定3.3VGND中点 1.92VESP32-C6GPIO63.3VプルアップON電流が流れ込む普通の入出力の機能ファームが切り替えたあと3.3VGND中点 1.65VESP32-C6GPIO63.3VプルアップOFF

ただし、リセット直後の約 0.1 秒は、ファームが動き出す前なので外せない。そこで、中点の値も測り続け、計算で差し引いている。

JTAG とマイコンのピンの初期状態

JTAG は、マイコンの中を外から調べたり、書き換えたりするためのデバッグ用の規格である。専用の信号線を 4 本使う。

ESP32-C6 では、GPIO4〜7 の 4 本のピンが JTAG の信号線を兼ねていて、電源を入れた直後は JTAG の機能になっている。そのうち GPIO6 (JTAG の MTCK) は、JTAG の機能のときに内部でプルアップされる。このプルアップは、ピンを普通の入出力 (GPIO) の機能に切り替えるまで外れない (ESP32-C6 のデータシートのピンの一覧による)。中点を読むピンに、たまたまこの GPIO6 を割り当てていた。

USB の詰まりで測定が止まっていた #

これは本番の運用ではなく、開発中の話。ファームを作っている間は、マイコンを USB で PC や Raspberry Pi につなぎ、測定しながら、1 秒ごとの値などのログを USB で送って画面で見ていた。ログを読むプログラムを閉じている間も、測定は止まらずに進むはずであった。

ところが、PC がログを読んでいない間は、40 秒のうち経過秒 (読んだ測定値の数から数えた秒数) が 13 秒しか進まなかった。

USB の速さが足りなかったわけではない。USB では、PC の側が「データをください」と取りに来たときにだけ、マイコンはデータを送れる。PC でログを読むプログラムを閉じると、PC はデータを取りに来なくなる。するとマイコンの USB の送り口 (送るデータを置いておく小さなメモリ) がいっぱいのまま空かず、ログを書く処理は空くのを待たされる。当時のファームは、測定とログの出力を同じループの中で順番に行っていたので、ログを書くたびに待たされ、測定も止まっていた。止まっている間の測定値は捨てられていた。

USB の詰まりの直す前と直したあと。直す前は、測定のループの中でログを書く処理が、いっぱいになった USB の送り口を待ち、測定も止まる。直したあとは、測定のループはログを 4KB の置き場にためるだけで、ログ係が USB に送る。置き場があふれたら捨てるので、測定は止まらない直す前測定のループ読む計算ログを書くログを書けるまで待つ → 測定も止まるUSB の送り口いっぱい取りに来ないPC読む画面を閉じた直したあと測定のループ読む計算測定は止まらないためる4KBあふれたら捨てるログ係優先度は低い待つのはここだけUSB の送り口いっぱい取りに来ないPC読む画面を閉じた

Claude は、ログの出力を測定とは別の処理 (ログ係) に分けた。測定のループは、ログを置き場 (4KB) にためるだけで待たない。USB に送るのは、測定より優先度の低いログ係である。置き場があふれたら、その行は捨てる。直したあとは、45 秒ログを読まなくても、経過秒は 46 秒進んだ。

Claude との協働 #

ファームウェアの構築・デバッグ時には、ボックスをつないだ Raspberry Pi で Claude Code を 24 時間稼働させた。開発のメインである Windows PC の Claude との連携は、Git リポジトリの HANDOFF.md (申し送り) ファイルで行い、作業の区切りごとに書き直して push された。完成前のチューニング期間には、私の留守の間も Claude が「ファームを直す → PC で試験 → OTA → 10 分たって戻っていないことを確かめる」を回した。帰宅後に Windows PC の Claude → Raspberry Pi 越しにボックスの状態を確認した。

本番の Home Assistant と Zigbee2MQTT に Claude が触るのは、私が了解した範囲 (参加・変換スクリプト・OTA) だけで、毎回バックアップを取ってからにした。

Claude も失敗することがある。第2部で紹介した電源モジュールの誤診、外形図の左右反転のほかに、本番の設定ファイルを書き換えるスクリプトの誤りで、OTA の目録を約 1 分空にしたこともあった。この際は Claude が自分で気づいてリカバリした。

Claude だけでは見つけられなかったこともある。第2部で紹介した「動く短絡」、ストレートの USB-C ケーブルが挿さらないことは、現物を前にした私が気づいた。詳細な設計はほぼ Claude に任せられたが、現物を見て触る役はまだ人間が必要である。

現在の運用状況 #

2026 年 11 月 1 日時点の状況を記録しておく。

サグは観測中 #

10 月 17 日の運用開始から 11 月 1 日までに記録したイベントは 6 件で、すべて私が試験や作業でブレーカーを切ったものである。試験以外の停電・瞬停・サグ・スウェルは、まだ 1 件も記録していない。厳密にはボックスが再起動している間 (OTA など) は判定していないので、「一度も起きていない」とまでは言えない。判定そのものが動くことは、前に書いたドライヤーの試験で確かめてある。

しきい値には届かなかったが、1 分ごとの最小と最大には動きが残っている。10 月 20 日夜以降で最も低かったのは L1 の 97.25V (ふだんの約 102V の約 95%) で、最も高かったのは L1 の 108.94V (約 106%) である。原因は確認できていない。

受け側が止まっても #

Home Assistant (受け側) 自体の更新や物理サーバのアップデートによる再起動を何度か実施したが、ボックス自体は 10 月 25 日に起動してから 11 月 1 日までの約 7 日 8 時間、一度も再起動せず、Zigbee への再参加もしていない。

10 月 27 日以降、毎分の報告が抜けたのは 4 回・計 23 通で、すべて受け側が止まっていた時間に重なる。うち 2 回は、サーバの再起動のあとに Zigbee のドングルが応答せず、私が抜き差しして復帰させた。これはボックスとは関係のない、受け側の問題である。

10 月 20 日からの通算で、サマリは 17,658 通の受領応答が返り、14 通は返らなかった。この 14 通は、ドングルが止まっていた 2 回の分である。

電力量測定は順調 #

電力量は順調に測れている。データの妥当性を確認するため、電力会社のスマートメーターの値と比較した。東京電力エナジーパートナーの会員サイト「くらしTEPCO web」では、スマートメーターが測った 1 日ごとの使用量 (0.1kWh 単位) を参照することができる。

スマートメーターとは

スマートメーターは、家の電気の使用量をデジタルで測り、通信の機能を持つ電力量計 (電力メーター) である。私の住む地域では、送配電を受け持つ東京電力パワーグリッドが設置している。従来のメーターは月 1 回の検針で 1 か月の使用量を出していたが、スマートメーターは 30 分ごとの使用量を測る。電力量計は、法令にもとづいて国の定める機関で正しく測れているかを確かめる決まりがあり、有効期間 (5〜10 年) が切れる前に取り替えられる。

測った値は、通信で電力会社のメーターデータ管理システム (MDMS) に送られる。住宅の多い地域では、となりのスマートメーター同士がバケツリレーのように値を中継し、電柱などに付けた集約装置 (コンセントレーター) まで届ける (無線マルチホップ方式)。郊外や山間部では、携帯電話の基地局へ直接送る (携帯方式)。電力線を通信に使う方式 (PLC) も組み合わせるとされている。この電力会社への経路を A ルートと呼ぶ。経済産業省 (資源エネルギー庁) の資料によると、いまのスマートメーターの仕様では、30 分ごとの使用量 (有効電力量) を 30 分ごとに集め、60 分以内に小売の電力会社などへ渡す。

このほか、家の中の機器 (HEMS。家で使うエネルギーを管理する機器) へ値を渡す経路 (B ルート) もある。申し込めば、30 分ごとの使用量に加えて、いまの電流の値なども家の中で受け取れる。

次の世代のスマートメーターでは、使用量に加えて電圧などの 5 分ごとの値も、一部の家 (1 割程度以上) から集める仕様が示されている (2022 年の検討会の取りまとめ)。集めた値は、停電やその復旧を知ることにも使うとされている。

くらしTEPCO web の日別の画面。2026 年 10 月の 1 日ごとの使用量の棒グラフで、10 月 31 日は 15.4kWh

くらしTEPCO web の 10 月の日別の使用量

電力会社のスマートメーター測定値と、ボックスの L1 と L2 の電力量の和 (HA の記録から 1 日ごとに出した値) を、日ごとに比較した。どちらも分電盤の主幹を通った電力量なので、本来はほぼ同じ値になるはずである。

10 月 21〜31 日の 1 日ごとの電力量の比較。上はスマートメーターとボックス (L1+L2) の棒グラフで、毎日ほぼ同じ高さ。下は差の割合で、OTA を 3 回行った 10 月 21 日の −1.2% を除いて ±1% の範囲に収まり、11 日の合計の差は −0.61%1 日の電力量スマートメーターボックス (L1+L2)05101520kWh差 (ボックス − スマートメーター) ÷ スマートメーター±1% の範囲+1%0%−1%11 日の合計 −0.61%−1.210/21OTA 3 回−0.510/22−0.110/23−0.710/24−0.910/25OTA 1 回+0.210/26−0.610/27−0.510/28−0.910/29受け側の再起動−0.410/30−0.610/31

10 月 21〜31 日の 11 日間の合計は、スマートメーターの 168.2kWh に対してボックスは 167.18kWh で、差は −0.61% であった。ファームの更新が落ち着いた 10 月 22 日以降の 1 日の差は +0.2〜−0.9% で、±1% の範囲に収まっている。ボックスがほぼ毎日わずかに少ない理由は、調査していない。報告が抜けた日 (10 月 29 日) も差は広がっておらず、積算値で追いつく作りが効いている。ただし、ファームウェアの更新で再起動が多かった日は差が大きく (10 月 18 日は −11.5%)、当然だがボックス停止中の値は測れない。

まとめ #

自宅サーバの不定期な再起動をきっかけに、サグを記録する装置を Claude と約 2 ヶ月掛けて作ってきた。 第1部の経緯 で触れたとおり、サーバの不定期再起動は別方面からおそらく解決してしまったが、副産物として電子工作体験と実用的な製品が完成したのは素直に嬉しい。

この装置の主目的であった肝心のサグは、10 月後半の完成後、残念ながら一度も検出できていない。7〜8 月頃は数日に一回は気づくほど頻発していたのには、猛暑で近所の供給電力が逼迫していたなど、理由があったのかもしれない。障害を検出する装置を作ったら、障害が解消してしまったとは皮肉である。

今回の装置のコンセプトを詰める中で、Home Assistant と Zigbee という標準に乗ることで、「見える化」のゴールがイメージできたのは大きい。少なくとも我が家の消費電力分析には活躍し始めている。仮に、オリジナルセンサー → オリジナル通信プロトコル → オリジナル UI でも AI があれば実現はできるだろうが、その先の応用が全く利かない一発物になってしまう。これではしばらくすると陳腐化して使わなくなるだろう。

私の電気知識が乏しい中でも完成に漕ぎつけることができたが、一旦立ち戻って電子回路の基礎を学んでみようかと思っている。もう少し理解を深めた上で、別の何かを作れたらと思う。

参考 #