リード|結論先出し
我が家の自作ソーラー(3.55kW + バッテリー① 5.12kWh + バッテリー② 5.12kWh、24V系LiFePO4)は、いま手動切替から自動切替への過渡期にいる。
何をやってるかというと:
- TP-Link Tapo C200(ネットワークカメラ)で、家の中に置いた外付けデジタル電圧計を常時撮影
- 撮影した映像をPython + OpenCVでフレーム抽出して、電圧の数字を読み取る
- 読み取り結果が24.8V以下になったら、SwitchBot ボットが充電器の物理スイッチを「指のように」押して充電開始
- チェック時刻は0:00 と 3:00 の深夜2回
正直に言っとくと、24.8VはLiFePO4 24V系でSOC約30〜40%にあたる閾値(電圧計の実感ベース)で、バッテリー保護と夜間の稼働時間のバランスを取った設定。寿命を最優先するなら、もうちょい保守的に25.0V以上(SOC約40〜50%)に上げてもいい。詳しくは後述する。
なんでこんな面倒な仕組みを組んだかというと、メーカー純正の監視システム(SmartESS)が我が家では使えなかったから(5記事目で書いたとおり)。「自分で組むしかない」状況で、ありもののIoT機材で何とかしてる感じ。
現在はMacで稼働中だけど、24時間運用と消費電力を考えるとMacを専有させるのはもったいないので、Windowsミニ PCへの移行を検討中。同じくDIYソーラーやってる人の参考になればと思って、今の構成と引っかかったポイント、ハマりどころをまとめておく。
なぜ自動化が必要だったか
手動運用の苦労
うちは2バッテリー構成で、片方が減ってきたらもう片方に切替えて充電する、というのを夜中に起きて電圧確認しながらやってた時期がある。
これがマジでしんどい。
- 寝る前にチェック → まだ余裕あり
- 朝起きたら過放電寸前 → 「やっちまった」
- 出張中だと家族に頼むしかない(無理)
- 切替忘れ=過放電 → LiFePO4の寿命が縮む
LiFePO4は過放電に強い化学ではあるけど、それでもSOC0%付近まで使い切るとサイクル寿命が露骨に減る。一晩の油断でン万円のバッテリーをすり減らすのは精神衛生上よくない。
メーカー純正監視(SmartESS)が使えない事情
詳しくは5記事目で書いたけど、うちのインバータ・ハイブリッド機の純正アプリ(SmartESS)は色々あって我が家の運用に合わなかった。
そうなると、「電圧を見る」「切替を制御する」のどっちも自分で組むしかない。
結果として「自分で組む」しかなかった
ありものでなんとかする発想で組んだのが今回のシステム。Tapo C200(約4,000円)+ SwitchBot ボット(約4,000円) + Pythonで、合わせて1万円ちょい。専用機材を買い足すよりはるかに安い。
システム全体構成|カメラ→画像処理→SwitchBot
ざっくり全体の流れはこう:
[ デジタル電圧計(外付け) ]
↓ (常時表示)
[ Tapo C200(カメラ)]
↓ RTSP(ローカルストリーム)
[ Python + OpenCV ]
↓ frame[130:175, 320:390] で電圧計部分を切り出し
↓ 7セグの数字をOCR
[ 数値判定(24.8V以下?)]
↓ Yes
[ SwitchBot ボット ]
↓ (物理的にスイッチを押す)
[ 充電器スイッチON ]
補足:なぜ「外付け電圧計」なのか
うちのインバータ本体にもLCDで電圧表示はあるんだけど、設置場所が家の中から見えにくい場所にあるので、家の見やすい位置に外付けのデジタル電圧計を別途設置してる。Tapo C200はその電圧計を撮影してる。
「インバータの画面を直接撮ればいいじゃん」と思うかもしれないけど、設置レイアウトの都合で別途電圧計を立てるほうが楽だった。同じ問題抱えてる人は多いと思う。
チェックタイミング:0:00 と 3:00
なぜ深夜2回かというと:
- 負荷が小さいタイミングで電圧を読みたい(後述:負荷時の電圧降下リスク)
- 0:00で1回、3:00でもう1回 → 1回目で24.8V割ってたら3時間後に再確認、それでも割ってたら切替実行
- ちょうど「深夜の安静電圧」に近い数値が読める
Tapo C200 でローカルストリーム取得
Tapo C200の特徴
- 解像度:1080p(フルHD)
- 首振り:水平360°/垂直114°
- 価格:日本でも4,000円前後で買える
- RTSP対応:あり(ポート554)→ ローカルネットワークから直接映像取得できるのが強み
「クラウド経由じゃない」っていうのが地味に重要で、深夜に外部サーバーが落ちてても自分のスクリプトは動く。安心感が違う。
RTSP接続のコツ
ハマりやすいポイントを2つ:
- 「カメラアカウント」を別途作成する必要がある
Tapoアプリでログインに使ってるアカウントとは別物。アプリ内で「Advanced Settings → Camera Account」みたいな画面から作る。これを作らないとRTSPで401 Unauthorizedが返ってくる。 - stream1 と stream2 の使い分け
rtsp://username:password@<IP>:554/stream1… 高画質(1080p)rtsp://username:password@<IP>:554/stream2… 標準画質(VGA相当)
電圧計の数字を読み取るだけならstream2で十分。むしろstream1だと帯域もCPUも食うので、深夜短時間用途では標準画質推奨。
Pythonからフレームを取り出す
OpenCVだけで普通に取れる。
import cv2
rtsp_url = "rtsp://camera_user:camera_pass@192.168.1.172:554/stream2"
cap = cv2.VideoCapture(rtsp_url)
ret, frame = cap.read()
cap.release()
# 電圧計部分だけ切り出し(ユーザー実構成)
voltage_area = frame[130:175, 320:390]
座標 [130:175, 320:390] は自分のカメラの設置位置で電圧計が映る位置を試行錯誤で決めた値。読者は自分の設置に合わせて調整が必要。
TIP:座標決めの時は一度フレームを保存してプレビューで切り抜き範囲を確認すると早い。
pytapo ライブラリも便利
カメラ自体の設定(ナイトモードON/OFF、首振り制御など)をプログラムからやりたい時はpytapo(非公式)が便利。映像取得自体はOpenCVで足りる。
OpenCV で7セグの数字を読み取る
7セグLEDのOCRが難しい理由
7セグメントLEDの数字は、見た目シンプルなくせにTesseract(標準OCR)だと結構誤認識する。セグメントの隙間のせいで「8がBに」「6がGに」「0がDに」読まれがち。
我が家のアプローチ:前処理を頑張る
うちはOpenCV前処理 + テンプレートマッチングにした。理由は学習データ管理が要らないし、7セグなら数字フォントが固定だから。
前処理の流れ:
import cv2
# 1. グレースケール
gray = cv2.cvtColor(voltage_area, cv2.COLOR_BGR2GRAY)
# 2. リサイズ(小さいので2〜3倍に拡大)
resized = cv2.resize(gray, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC)
# 3. ガウシアンブラーでノイズ除去
blurred = cv2.GaussianBlur(resized, (5, 5), 0)
# 4. 二値化(Otsu)
_, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 5. (必要なら)モルフォロジーでセグメントを連結
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
processed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
テンプレートマッチング派 vs ssocr派 vs Tesseract派
| 方法 | 学習データ | メリット | デメリット |
|---|---|---|---|
| テンプレートマッチング | 0〜9の参照画像を1回作る | 軽い・誤読率が読みやすい | 表示位置がズレると弱い |
| ssocr(線プロファイル) | 不要 | 学習なし・軽い | 桁切り出しの調整が要る |
| Tesseract + 7セグ用traineddata | あり(letsgodigital等) | 汎用性高い | サイズ小さいと厳しい |
うちはテンプレマッチングで安定してる。frame[130:175, 320:390](縦45×横70px)はかなり小さい領域なので、Tesseractに食わせる前にリサイズと前処理が必須。
誤認識リスクと対策
- 同じフレームで3回読んで中央値を採用:たまに変な値が混ざっても多数決で正解に倒せる
- 読み取り値が前回値から極端に離れていたら無視:例えば前回25.6Vで今回12.3Vなら明らかにOCRエラー
- 赤外線ナイトモードはOFF推奨:電圧計のバックライト光だけで撮るほうが7セグの輪郭がきれい
- ログを必ず残す:読取値・判定結果・切替実行有無を毎回ファイル出力
正直なところ:OCRが100%当たることはない。「3回連続で24.8V以下なら切替」みたいな連続判定にするのは誤動作対策としても効く。詳しくは閾値運用のセクションで。
SwitchBot ボットで物理的に充電器スイッチを押す
SwitchBot ボットとは
物理ボタンを「指で押す」ように動かせる小型デバイス。両面テープでスイッチに貼り付けて、Bluetooth or Wi-Fi(Hub経由)で制御する。
- 価格:3,000〜4,000円程度
- 電池寿命:約600日(公式)
- 制御方式:
- Bluetooth Direct(BLE):SwitchBot Hub不要、ローカルから直接押下
- Cloud API(v1.1):SwitchBot Hubが必要、外出先からも操作可能
Hub の有無で実装が分岐する
| Hub あり | Hub なし |
|---|---|
| Cloud API使用可、外出先からも操作可、ただしSwitchBotサーバーが落ちてると動かない | BLE直接、ローカルだけで完結、深夜の自動制御に向いてる |
うちの用途(深夜0時/3時の家庭内自動切替)はローカル完結のBLE Direct がオススメ。SwitchBotのクラウド障害が起きても自分の家で動き続ける。
Python サンプル:BLE Direct(Hubなし)
switchbotpy(RoButton/switchbotpy)を使う例:
from switchbotpy import Bot
# bot_mac は SwitchBot アプリで確認できる
bot = Bot(id=0, mac="XX:XX:XX:XX:XX:XX", name="charger_bot")
bot.press() # 1回押下
Python サンプル:Cloud API(Hubあり)
OpenWonderLabs公式API を使う場合:
import requests, time, hashlib, hmac, base64, uuid
token = "YOUR_TOKEN"
secret = "YOUR_SECRET"
device_id = "YOUR_DEVICE_ID"
# 認証ヘッダー作成(v1.1)
nonce = str(uuid.uuid4())
t = str(int(round(time.time() * 1000)))
sign = base64.b64encode(
hmac.new(secret.encode(), f"{token}{t}{nonce}".encode(), hashlib.sha256).digest()
).decode()
headers = {
"Authorization": token,
"sign": sign,
"t": t,
"nonce": nonce,
"Content-Type": "application/json"
}
requests.post(
f"https://api.switch-bot.com/v1.1/devices/{device_id}/commands",
headers=headers,
json={"command": "press", "parameter": "default", "commandType": "command"}
)
API のトークン取得は SwitchBotアプリ → プロフィール → 設定 → アプリバージョンを10回タップ → Developer Options から。
レートリミット:Cloud API は 1トークンあたり1日10,000リクエストまで。今回の用途なら1日2回以内なので心配無用。
充電制御用途の注意
充電器のスイッチがプッシュ式(押すたびにON/OFFトグル)だと、状態管理が必要。「押した結果ONになったか?」を電圧計の上昇で確認するのが堅実。ロッカー式(ON位置で固定)ならON押下だけ実装すればよくて楽。
我が家の閾値運用|24.8Vで切替
なぜ24.8V?
うちは充電開始の閾値を24.8Vにしてる。24V系LiFePO4で、これがSOC約30〜40%にあたる(うちの電圧計で読んだ実感ベース。負荷のかかり方や個体差で多少ズレる)。
理由は、バッテリー保護と、夜間にバッテリーで家電を動かせる時間のバランス。深く使いすぎると寿命に響くし、早めに充電しすぎると夜間の自給時間が短くなる。その妥協点が24.8V。
🚨 寿命を最優先するなら 25.0V以上(SOC約40〜50%)に
LiFePO4は SOC 20〜80% で運用するのがサイクル寿命的に一番優しい。深掘りを避けたいなら閾値を上げる。24V割れまで毎日使うのはNG(SOC10%以下まで深掘りすると劣化が早まる)。
バッテリーのSOC・電圧の詳しい話はバッテリー選びの記事にまとめてる。
連続判定の重要性(負荷時電圧降下対策)
24.8Vを「1回読んだだけ」で切替するのは危険。理由:
- 家電が動いた瞬間に負荷時の電圧降下で一瞬24.8Vを下回ることがある
- OCRがたまたまミスって「24.8V」と誤読することもある
なので実装上は:
- 3回連続で24.8V以下なら切替(多数決方式)
- 0:00と3:00の両方で割ってたら切替(時間軸での連続判定)
これがあるとないとで、誤動作率がぜんぜん違う。
鉛バッテリー使ってる人へ
LiFePO4と鉛は電圧カーブが全然違う。鉛24V系は電圧の落ち方や満充電電圧が違うので、24.8Vをそのまま流用せず、自分のバッテリー化学に合わせて閾値を再設定してください。
⚠️ 自動化失敗時のリスク|物理スイッチを残す重要性
起こりうる失敗
| 失敗パターン | 結果 |
|---|---|
| Wi-Fi断 → カメラに接続できない | OCRに進めない=切替不発 |
| OCR誤認識 | 必要ないのに切替実行 / 必要なのに不発 |
| SwitchBot電池切れ | 押下不発 |
| Python スクリプトのバグ | 任意のおかしな挙動 |
| Mac/PC自体がスリープ | スケジュール時刻に起きてない |
| 停電 → スクリプト動かず | 切替不発 |
必須の安全装置
- 物理スイッチを残置する:SwitchBotを物理的に取り外せば即手動運用に戻れる構造を保つ。SwitchBotを「貼り付ける」だけにしておけば、手動操作も並行してできる
- ハードウェアBMSを必ず併用:ソフト制御を信用しすぎない。最終防衛ラインはバッテリー側のBMSによる過放電カットオフ
- ログを毎回ファイル出力:成功/失敗/読取値を残す。後で何が起きたか追える
- エラー時に通知:LINE Notify 後継 や Discord Webhook、Pushover などで「OCR失敗した」「切替実行した」を通知
半自動+保険の発想で組むのが正解。「完全自動化」を目指すと一発失敗で痛い目見る。
「自動化は補助、最終防衛はBMSと手動」
これが我が家の哲学。SwitchBotとPython は便利だが信頼性100%じゃない。LiFePO4のBMSは過放電になればハードウェアレベルで遮断してくれるので、ソフトが死んでもバッテリーは守られる。BMS付きパックを買うこと、これは絶対。
Mac → Windows ミニPC への移行検討
現状:Macで稼働中
いまはMac(普段使い兼用)で cron で 0:00/3:00 にスクリプトを叩いてる。動いてはいるけど:
- Macは普段の作業や動画編集にも使うから専有させるのはもったいない
- スリープに入っちゃうとスケジュール実行されない(
pmsetで対策可だけど面倒) - 24時間稼働だと電気代もそこそこ(Mac mini ですら月数百円〜千円)
Windows ミニPC へ移行のメリット
- 省電力:10W前後のN100ミニPCなら24時間稼働でも月100円程度
- 専用機:他の用途に取られないので安定運用
- タスクスケジューラ:Windows標準の機能で 0:00/3:00 自動起動が簡単
移行時の課題
| 課題 | 対策 |
|---|---|
| Python環境再構築 | venv作ってrequirements.txt から pip install -r |
| OpenCV のインストール | Windows なら pip install opencv-python でほぼOK |
| 自動起動方法の違い | Mac の cron → Windows の タスクスケジューラ へ概念切替 |
| GUI窓を出さず実行 | python.exe ではなく pythonw.exe を使う |
Windows タスクスケジューラの典型構造
run_check.bat:
@echo off
cd /d C:\path\to\script
pythonw.exe main.py
これをタスクスケジューラの「タスクの作成」→ トリガー「毎日 0:00」と「毎日 3:00」を2つ作る → アクションでこの .bat を呼ぶ。
ハマりポイントとして、「最上位の特権で実行する」にチェックを入れないとデバイスアクセスがコケることがある。BLE経由でSwitchBotを操作する場合は特に。
⚠️ 自作ソーラーDIY の安全注意
これは毎回どの記事でも書いてる。
- LiFePO4 は過放電に比較的強いが、深く使うと寿命は縮む。火災リスクは小さいけど、サイクル寿命の観点では避けたい
- 自動切替の閾値は保守的にが原則。うちは24.8V(SOC約30〜40%)にしてるが、寿命優先なら25.0V以上に上げてもいい。24V割れまでの深掘りは避ける
- 電気的な配線は電気工事士資格者推奨。自分で配線するなら直流側だけにとどめて、交流側は触らない
- メーカー保証外の自己責任DIY。バッテリー破損・火災・感電は自己責任、誰も助けてくれない
- BMS必須:ソフト制御を最終防衛ラインにしてはいけない
まとめ|手動から半自動、そして完全自動へ
我が家の現在地:半自動
- 監視と切替は自動化済み(Python + Tapo + SwitchBot)
- でもMacに依存してるので「専用機」とは言えない
- 物理スイッチも残してるので、何かあれば手動運用に戻せる
次の段階:Windowsミニ PCで完全自動化
- 専用機での24時間運用
- 普段使いの環境から切り離して安定性UP
- 消費電力も月100円程度
DIY IoTとして同じ問題抱えてる人へ
- 電圧計 + カメラ + OpenCV + SwitchBotという組み合わせは、日本語圏の自作ソーラー界隈ではほぼ前例がない(リサーチ範囲では)
- 専用機材に頼らず1万円ちょいで組めるのは個人勢には大きい
- ただし安全マージン(保守的閾値、BMS併用、物理スイッチ残置)は絶対外さない
同じく自作ソーラーやってて「監視と切替を自動化したい」と思ってる人の参考になれば嬉しい。


コメント