自宅のコンセントの電圧・周波数を計測してリアルタイム表示できるようにしてみた

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/d0c44372-8902-f266-f3e5-3c40f06e83d0.jpeg)

**コンセントからどんな電気が出ているんでしょう？**

もともと趣味で電子工作や基板設計をしており、[商用電源の周波数](https://ja.wikipedia.org/wiki/%E5%95%86%E7%94%A8%E9%9B%BB%E6%BA%90%E5%91%A8%E6%B3%A2%E6%95%B0) の計測回路や基板を [製作して観察する](https://zenn.dev/nanase_t/articles/87b71ad5c414ef) などのことは行なっていました。電圧まで安全に計測する方法についていくつか検討していましたが、[**M5AtomS3R**](https://www.switch-science.com/products/9915) の発売を機にリアルタイム表示までできるシステムを構築することにしました。









## システム概要

今回作ったものは大きく3つの部分に分類できます：

![システム構成図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/eaa474bd-d3a1-bbe3-f553-565420ce10a5.png)

1. **ハードウェア**:
  AC100Vの電圧と周波数を計測値を [**BLE** (Bluetooth Low Energy)](https://ja.wikipedia.org/wiki/Bluetooth_Low_Energy) を使って外部に送信する
2. **ソフト側バックエンド**:
  BLEで受信したデータをデータベースに投入する。REST APIでデータのリクエストがあったらそれを読み出す
3. **ソフト側フロントエンド**:
  REST APIで取得した計測データをWebブラウザ上に表示し、リアルタイムにグラフで表示させる

ご覧のように、ハードウェアからソフトウェアまで幅広く取り扱うため広範な知識が要求されるタスクになりました。利用技術は以下のようになりました：

| ドメイン | 言語 | フレームワーク | その他ライブラリ |
|----|----|----|----|
| ハードウェア | C++ | Arduino | n/a |
| ソフト側バックエンド | Python | FastAPI | SQLAlchemy, Alembic, SQLite, Bleak |
| ソフト側フロントエンド | TypeScript | Vue | Vuetify, Chart.js |


## ハードウェア

まず、以下の特徴を持つ基板を作ることにしました。

- 使用MCU: [M5AtomS3R](https://www.switch-science.com/products/9915)
  - WiFi/Bluetooth、LCD などを備えており、基板に組み込んで使うのが容易
- 電源は計測するAC入力から供給
  - ただしデバッグ時は M5AtomS3R の Type-C 端子からの供給が可能
- 周波数計測
- 電圧計測: [HLW8032](https://shop.m5stack.com/products/ac-measure-unit-hlw8032) 使用
  - オプションで電流と電力の計測も可能
- AC領域とDC領域の絶縁、ヒューズとバリスタの使用


### 回路図

以下が今回制作した回路図になります。[KiCad](https://www.kicad.org/) 8.0 を使用しました。

https://drive.google.com/file/d/19In-Q8Ik4TGUhQ2y3EuApdYYL7Y0oT8E/view?usp=drive_link

部分ごとに詳しく見ていきます。

#### 周波数計測回路

![周波数計測回路の回路図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/529cc9d2-3178-4359-daa0-de3385a0ae0c.png)

この回路に関しては [過去すでに製作実績](https://zenn.dev/nanase_t/articles/87b71ad5c414ef) があり、その回路をベースにしています。

![2024-12-2016.41.57-ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/d8126500-ae33-1dda-617e-50af78b63328.gif)

ただし、今回は上図のように [フォトカプラ](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A9%E3%83%88%E3%82%AB%E3%83%97%E3%83%A9) を1個だけにし、さらに [555 タイマIC](https://ja.wikipedia.org/wiki/555_%E3%82%BF%E3%82%A4%E3%83%9E%E3%83%BC) を用いた [シュミットトリガ](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%A5%E3%83%9F%E3%83%83%E3%83%88%E3%83%88%E3%83%AA%E3%82%AC) を使ってノイズ耐性[^noize_from_m5atoms3r]を上げています。

[^noize_from_m5atoms3r]: 理由は様々ですが、M5StackおよびM5Atomシリーズから供給される3.3Vにはかなり大きいノイズが混入します。シュミットトリガを使わない場合、パルスのダブルカウント等が頻繁に発生してしまい、計測が安定しません。


#### 電圧計測回路

![電圧計測回路の回路図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/2b0528df-167e-08a6-7e06-3d27dcec7816.png)

電圧計測については [M5Stack から発売されている電源監視モジュール](https://www.switch-science.com/products/9183) の回路をほとんどそのまま使っています。そのため、回路上は電流と電力の計測もできます。しかし、使用した計測IC HLW8032 はゼロ負荷付近での計測精度が非常に悪く[^hlw8032_precision]、さらに今回の目的には必須ではないので未使用となっています。

[^hlw8032_precision]: この問題はデータシートには詳しい記載がなく、GitHubのHLW8032のArduinoライブラリリポジトリのIssuesや[海外コミュニティ](https://www.eevblog.com/forum/projects/hlw8032-based-energy-meter-circuit-showing-power-usage-at-no-load/)でも頻繁に議論されています。


#### ACアダプタと逆流防止ダイオード

![ACアダプタと逆流防止ダイオード付近の回路図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/fc0702ef-3c91-327d-7cc2-cc2b39d0946d.png)

AC電源の計測をせっかく行うのに、それとは別の場所からわざわざ電源を用意するのはもったいないです。秋月電子から [基板に組み込めるタイプのACアダプタ](https://akizukidenshi.com/catalog/g/g118212/) が販売されており、今回はそれを使います。少々お高いですが、ACアダプタを自分で設計するよりはるかに楽で確実な上に安全です。

![ダイオードによる逆流防止](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/84910d18-3e05-820a-a5d6-68ea9642c154.png)


ところで、ACアダプタを使いながら Type-C で M5AtomS3R と接続すると、場合によっては電流が電源方向に逆流することがあります。本来ならばショットキーバリアダイオードなどを電源の数だけ用いて逆流を防止します。しかしM5AtomS3R内部でVBUS（USBからの電源供給）と5Vピンの間にはダイオードが入っていません。

![2024-12-2016.55.05-ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/20d5c1da-a583-90dd-4a8a-a9f1d76e3c30.gif)

今回は理想ダイオード [CH213K](https://akizukidenshi.com/catalog/g/g129462/) をACアダプタの直後に入れ、さらにACアダプタからの電源供給を切断するためのジャンパピンを配置しました。デバッグ時のみACアダプタからの供給を切断するという運用でカバーすることにしました。






### HLW8032用のライブラリ

計測IC HLW8032 からはシリアル通信で一方的に計測データが送られてきます。これをデコードするライブラリは複数存在するのですが、次の問題がありました:

- データシート記載の計算式と明らかに異なる定数を使っている
- 特定のボード（ハードウェア）に強く依存したコードがある
- コメントが中国語で（個人的に）そのまま読めない

コーディングスタイルにおいても様々思うことがあり憤慨してしまったため、既存の最もマシなライブラリをベースにして [**新たなライブラリ**](https://github.com/nanase/HLW8032) を作りました。データシート通りの定数を使い、特定のボードに依存しないコード、英語でコメントとドキュメントは整備しました。ついでに PlatformIO でライブラリとして認識できるように [設定ファイル](https://github.com/nanase/HLW8032/blob/main/platformio.ini) も作成しました。

https://github.com/nanase/HLW8032








### BLEのプログラム
 
以前、[ESP32DevKit-C](https://akizukidenshi.com/catalog/g/g115673/) を使って[BLEのスキャンを行いました](https://zenn.dev/nanase_t/articles/a97dd951a4dc39)。この時はスキャンのみで受信専門だったのですが、今回はアドバタイジング（広告）をする必要があります。基板のファームウェアを作り始める前に、M5AtomS3Rにおいてアドバタイジングデータの送信とPC側からのスキャンを調査しました。

https://zenn.dev/nanase_t/articles/d06f69c513d001

調査時と異なり、今回の実戦ではアドバタイジングはあくまでデバイスの存在を知らせるために使い、その後デバイスと接続処理を行なって notify として電圧と周波数のデータを送信することにしました。

今回のプログラム：

https://github.com/nanase/ACObservator-firmware/blob/c1b09168aede2769c1b43ff9dcc9051a02999e8c/src/main.cpp#L87-L95










### どうしてWiFiを使わないのか？

M5AtomS3R は WiFi を使用できますが、以下の明確な理由により BLE を選択しました：

- たかだか2種類16バイトのデータしか送らない
- 暗号化すべきデータがない
- アクセスポイントの用意や接続パスワードを M5AtomS3R に置きたくない
- IPアドレスの管理や M5AtomS3R に HTTP サーバを立てるのが面倒

以前の ESP32-DevKitC での開発の経験上、WiFi を用いて HTTP サーバを立てると、ファームウェアのサイズやビルド時間が大幅に増加します。そのコストを払っても2種類の数値しか送らないのは、明らかに割に合いません。


### BLEのアドバタイズとコネクションフロー

```mermaid
sequenceDiagram
    participant D as BLEデバイス
    participant C as セントラル
    participant DB as データベース
    D-->>C: アドバタイズ
    D-->>C: アドバタイズ
    Note over D, C: BLEデバイス発見
    C->>+D: 接続要求
    Note over D, C: 接続開始<br>アドバタイズ停止
    D-->>C: notify（通知）
    C->>DB: データ格納
    D-->>C: notify（通知）
    C->>DB: データ格納
    D-->>-C: 接続終了
    Note over D, C: アドバタイズ再開
    D-->>C: アドバタイズ
    D-->>C: アドバタイズ
```

センサデバイスでは BLE の **アドバタイズ（広告）** を行うことでデバイスの存在を周囲に知らせます。アドバタイズパケットを受信するのがセントラルデバイスで、アドバタイズパケットを能動的に探索することを **スキャン** といいます。アドバタイズパケットにはセンサデバイスのアドレスも含まれています。

接続すべきデバイスを発見した場合、セントラルはセンサデバイスに対してコネクションを要求します。コネクションが成功すると、センサデバイスはアドバタイズを停止し、セントラルデバイスに対して計測データを断続的かつ一方的に **notify（通知）** します。

計測したデータサイズが小さいためアドバタイズパケットそのものに載せることもできます（コネクションレス通信）。しかし今回は通信が切断されたことを検知したり、標準的な再送処理が実行されることを期待しコネクションを行うことにしました。


### 基板設計

|設計画面|出来上がりイメージ|
|:---:|:---:|
| ![設計画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/9da9fdb2-159b-5732-0085-326b0a0849aa.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/ad1bb706-f330-74e5-7328-b762ddcea7b9.png)|

回路設計と同じく [KiCad](https://www.kicad.org/) 8.0 で行いました。製造上の推奨目標サイズは 100x100mm、実際のサイズは 84x84mm となりました。高圧部分があるため、実際の運用では [貼り付けボス](https://akizukidenshi.com/catalog/g/g109538/) を使って絶縁体の筐体に入れて固定して使います。













### 基板製造・部品実装

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/3e31d42e-3366-304f-f579-318b6b4b5760.jpeg" width="540">

今回も以前から利用している [JLCPCB](https://jlcpcb.com/jp/) にお願いしました。個人的な利用なので5枚で発注しました。しかし一度目の製造の結果、複数のフットプリント（部品の外形やピンの配置）に誤りがあり、結局2回目の発注を行いました。

今回は表面実装部品を避けてリード部品を選んだため部品実装（はんだ付け）は簡単でした。しかしACアダプタのピンが細い上になかなか [濡れず](https://www.asahimekki.com/faq/4148.html)、はんだ付けに苦労しました。














### 動作チェック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/559d0349-a3b2-ffac-560b-393287da624e.jpeg" width="480">

火入れ作業です。基板を組み立てて初めて電源を投入する瞬間が最も緊張し、勇気が必要になります。特に今回は AC100V を直接入力するので慎重に、一つずつ確認しながら電源を投入しました。結果的には全く問題がなく、発煙や故障することもありませんでした。

M5AtomS3R の画面上にも電圧、周波数、BLE の接続状況を表示するようにしました。


#### （余談）コンセントを逆にしたらどうなる？

日本のコンセントには **N極** と **L極** があり、N極 は地面と等電位（≒ 0V）とされ、L極 が活線（100Vrms）となっています。万が一を考え、今回の基板ではヒューズは L極側 についています。原理上はコンセントを逆にしても動作には何の影響もありません。しかしその場合、回路図上では GND と想定していた箇所に 100Vrms の電圧がかかるため、回路設計で考慮されていないと感電のリスクが高まります。そのため、今回は [検電ドライバー](https://www.vessel.co.jp/btob/knowledge/633.html) を使って事前に L極 と N極 をその都度調べ、接続しています。











## ソフト側バックエンド

いよいよソフトウェア側です。今回はフロントエンドを別で作りたいのと、Python と [FastAPI](https://fastapi.tiangolo.com/ja/) を使ってみたかったのでこの2つを用いました。BLEのデータ受信については Bleak を使い、FastAPI とは別のスレッドで並列処理させることにしました。

https://github.com/hbldh/bleak

今回は簡略化のため SQLite を使って受信したデータ全てを格納しています。ただしデータ取得のユースケースを考えると、将来的には直近24時間のみ Redis などで記憶させておき、順次永続化ストレージに書き出して記録する、という方法が安全かつ高速かもしれません。

今回のプログラム：

https://github.com/nanase/ACObservator-fluxLynx/blob/0e30a8c66f7cf13a37c29ee757a842d153126984/app/background/bleScanTask.py#L105-L142



## ソフト側フロントエンド

今回は Vue を使ってグラフ表示させました。[Chart.js](https://www.chartjs.org/) を使ってグラフ表示をしています。右上に「ソフト側バックエンド」と「ハードウェア」との接続状況がわかるアイコンをつけました。今回の場合、FastAPI で最新値を取得できたとしても実際にはそれが数十秒前の観測データという可能性もあるため、接続状況がすぐに把握できると便利です。

ハードウェア側で1秒ごとに計測して送信し、ソフト側バックエンドにてデータ格納、フロントエンドで1秒ごとにポーリングを行なっています。その都合上、どんなに速くとも計測から表示までには1〜2秒程度の遅延が生じます。

今回のプログラム：

https://github.com/nanase/ACObservator-dashboard/blob/22d83278fbb11ee1c3f0bbfa7271c5d5a6d09149/src/IndexApp.vue


### 動作風景

![ACObservatorDashboard-GoogleChrome2024-12-2210-47-39-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/11875c8f-10ec-b7b7-d9d1-109f329457fb.gif)

こちらが実際の動作画面になります。

ダッシュボードページをブラウザで開くと電圧と周波数が表示され、グラフでその変化も観察できます。実際は1秒ごとにグラフ表示は更新されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/7cac0420-4a7d-86ad-af3b-9ffebaa9f99d.png)


さらに右上にはフロント側バックエンド（DBアイコン）とハードウェア側（コンセントアイコン）との通信状況を表示しています。フロント側バックエンドと REST API で正常に通信できたとしても、BLE でハードウェアと接続できているとは限らないのです。









## モノコトフェス \#1 にて展示発表

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/0a6d6239-8a70-8717-c250-d2cc46165b89.jpeg)

完成した基板、フロントエンドを [モノコトフェス \#1](https://few-wood-2b2.notion.site/1-10fc4727cabe804bb8bbe19bfa7bd08d)（2024年12月8日 県立長野図書館）にて展示発表を行いました。

当日、ディスプレイで使用したスライド（後半に技術資料あり）：

https://docs.google.com/presentation/d/1fy6XTtJfNM4oc2LDl37gVqfNyXpI_Xe5KT3MLFKTwlE/edit?usp=sharing

AC100V を直接扱う都合上、基板を来場者の皆さんの手にとってもらうことはできませんでした。その代わり、なぜこのような作品を作ったかという背景、そしてコンセントからどのような電気が出てくるのか、という説明資料を作って発表しました。技術的内容よりも意図を説明する側に重きを置いた資料になります。

会場の声としては、そもそもコンセントの電源がどうなっているかを知らなかったという声、日本の周波数が2種類あるということ、AC100V は実は最大 100V ではないという説明に非常に驚かれた方もいらっしゃいました。

![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/862aad42-ea45-f857-6e2d-d40920cb36c6.jpeg)


来場者には親子連れも多くおり、説明資料をもってしても小学生低学年向けには理解が難しいだろうと考えていました。そのため会場には電池と豆電球を持参し、子どもたちがそれを触っている間、ご両親に説明するという作戦を採用しました。

しかし展示内容として「体験」するというものではなかったので、素通りしてしまう方も多かったように見えます。次回参加の機会があれば「安全に体験」できるモノを考えてみたいと思います。








## これから

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/17c32767-7376-22c4-ba4d-6596d0e2ab8f.jpeg)


数年温めていた回路がついに実現し、自宅コンセントの電圧・周波数がリアルタイムに知ることができるようになりました。

ソフトウェア側バックエンドについて、データの永続化方法には大きな課題を感じています。センサデータという時系列かつ変更の必要がない大量のデータをどう効率よく保管し、取り出すかは今後の大きな課題です。