PR

ラズベリーパイで電力量をリアルタイム計測 → グラフ化|PZEM-004T + Raspberry Pi ZERO

ラズパイで電圧グラフ ベランダ太陽光 接続&設置
当サイトはアフィリエイトプログラムに参加しています。記事内容は公平・素直を心がけています。

ラズパイを活用して、DIY太陽光発電の使用電力量を可視化したい

自宅アパートのベランダに設置している、わずか300WのDIY太陽光発電システム。
太陽光で作った電力をリチウムイオンバッテリーに貯めながら、1000WのインバーターでAC電源を作り出し、各種電化製品の充電やモニターの表示、扇風機などちょっとした家電に使用している。

設置してから既に10年経っているので、各機器が古い。
バッテリーに貯めた電力が減ってきたら、商用電源に切り替えるための装置があるのだが、購入当時の手動で切り替える方式。

切り替えるタイミングを知るために、ラズベリーパイを使って、バッテリーの電圧をリアルタイム計測し、しきい値を超えたら、音声で、
「12.8Vを下回りました。商用電源に切り替えてください」
「13.3Vを超えました。電気を使ってください」

なんていうアナウンスが流れるようにしてある。アナウンスが聞こえたら、手動で切り替えるのだが(苦笑)
電圧の推移はグラフ化して外出先でも見れるようにしてある。

さて、貧弱な太陽光発電システムだけど、実際にインバーターから使用している太陽光で作った電力はどれくらいの電力量になるのかを調べたくなった。

そこで、ラズパイをフル活用して、使用電力量もグラフ化して、バッテリー電圧同様に外出先でもスマホで見れるようにしてみたい。

さて、楽しい電子工作DIYの始まりだ。(私的備忘録なのでご了承ください。。)

基本手順

現在、バッテリー電圧測定に使用しているINA260というモジュールを使って、電圧を取得している。
実はこのモジュール、電流値も取得可能。そのため、最初はこのINA260で電流値を取得して、電力量を計算しようと考えた。

しかしながら、INA260は直流の電流を計測するので、チャージコントローラー ―― バッテリー ―― インバーター のいずれかの間のケーブルに直列に組み込む必要がある。許容電流量にも問題がありそう。

ということで、INA260を使っての電力量取得は現実的に厳しそう。これは、バッテリー電圧を計測するだけに使用しよう。

ではどうするかというと、CTを使って、交流の電流を計測できる通信モジュール(PZEM-004T)がある事が分かった。このPZEM-004Tとラズパイを使って、交流に切り替わったインバーターからの出力のケーブルから値を取得しようと思う。

問題点としては、インバーターからの出力用にACコンセントが2口あり、どちらも使っている。
そのため、2系統分の電力量を計測しないといけないので、PZEM-004Tが2つ必要、ということ。

まぁ、モジュール自体はそんなに高価なものでもないので、2系統分の電力量の取得、やってみましょう。
取得した値を合計すれば、インバーターからの出力電力量が分かるのでね。

準備したもの

名称価格備考
Raspberry Pi ZERO WH購入当時約¥2,000既に、バッテリー電圧測定で使用しているもの
PZEM-004T v3¥2,200×2個Amazonで。2個のうち1個は、UART→USB変換ケーブルが必要。
PZEM計測用コンセント治具約¥1,000×2本プラグ等を購入して自作。VVFケーブルは余りものを活用
電子工作関連工具や配線、端子類精密圧着ペンチとかQIコネクタとか・・・

PZEM-004T設定手順

通信方式について

設定していると、色々と通信方式の名称が出てきて混乱したので、以下にまとめておく。

※「TTL」「Modbus-RTU」「UART」「minimalmodbus」のそれぞれの違い

用語意味例えるなら
TTL
(Transistor-Transistor Logic)
電気信号の電圧レベル
Raspberry Piは 3.3Vロジック、PZEMは 5Vロジック の場合が多い
声の大きさ(3.3V or 5V)
UART
(Universal Asynchronous Receiver/Transmitter)
シリアル通信の仕組みそのもの。1本の線で1ビットずつ送受信する通信方式。
Raspberry PiではGPIO14 (TxD) と GPIO15 (RxD) がUARTポート。
声を出して話す方法
Modbus-RTUUARTの上で動く「通信プロトコル(ルール)」機器同士の言語。
産業機器では定番の通信方式。
PZEM-004T v3.0 はこの形式を使っている。
日本語・英語のような言語
minimalmodbusPythonでModbus-RTUを簡単に扱うためのライブラリ(ツール)
UARTポート(例:/dev/serial0)を通してModbus通信を行う。
read_register(0) や read_float() でデータ取得できる
通訳アプリ

UARTを有効化しておく

sudo raspi-config

# → Interface Options → Serial Port → “Login shell” = No, “Serial interface” = Yes

UART接続の注意① PZEMをUARTで使う場合はBluetoothを無効のままにしておくのが安全

ラズパイZEROの場合は、1つしかないメインのUARTポート(ttyAMA0)が、Bluetoothで使われており、今回のようなデータ取得でUARTポートを使いたい場合はBluetoothをOFFにする必要があるらしい。

一応、サブのUARTポート( ttyS0 )もあるが、これを今回のようにGPIO14,15で割り当てると、通信が不安定になりやすいらしい。

UARTの設定を行い、以下を実行

ls -l /dev/serial*

出力が、以下のどちらかのような表示になるはず
lrwxrwxrwx 1 root root 7 Oct 25 21:00 /dev/serial0 -> ttyAMA0 #これならOK
lrwxrwxrwx 1 root root 5 Oct 25 21:00 /dev/serial0 -> ttyS0 #これはbluetoothをOFFにする必要がある。

bluetoothをOFFにするためには、

sudo nano /boot/firmware/config.txt

末尾に以下を追記。bluetoothが無効化される

dtoverlay=disable-bt

その後、再起動

sudo reboot
pi@raspberrypi:~ $ ls -l /dev/serial*
lrwxrwxrwx 1 root root 7 Oct 26 07:56 /dev/serial0 -> ttyAMA0

となれば、OK。
仕方ないけど、このラズパイで電力量測定を行っている限りはBluetoothが使えない、と思っておこう。

UART接続の注意② 安全性

機器を購入した後に知ったのだが、ラズベリーパイでPZEM-004Tを使う場合、注意点がある。

Pzem-004Tの信号電圧は5Vである。しかし、ラズパイ側のGPIO入力最大許容電圧は3.3Vまでなので、5Vに対する耐性が無いらしい。
そのため、5V信号を直接ラズパイに入力すると、ラズパイが破損する可能性があるらしい。

たまたま破損しなかったとしても、長期間運用することで、GPIOの入力バッファが損傷したり、高温時による保護ダイオード破損の危険性が増したり、ノイズ混入による通信異常の原因になるらしい。

PZEM-004Tの信号をRaspberry Piにつなぐ際の安全対策

レベル変換モジュール(5V⇔3.3V) を挟む。

双方向ロジックレベル変換モジュール(Amazonで数百円)を間に挟むことで、5Vと3.3V通信電圧を変換してつなぐ

② 1方向だけで良ければ、2種類の抵抗を間に挟んで降圧回路を組み込む。

TX(5V)→ GPIO:分圧抵抗(10kΩと20kΩなど)で3.3Vへ降圧。
RX(3.3V)→ PZEM はそのまま接続。3.3Vでも認識可能らしい

本来は、①のレベル変換モジュールを使うのが良いらしいが、幸い我が家に使っていない抵抗がたくさんあるので、ようやく使う機会が来たということで、②の方法で降圧回路を組んでみることにする。

分圧回路

参考:https://zenn.dev/botamochi6277/articles/a47bf9455c93e2

分圧後の電圧は以下の通り。
5V × (20k / (10k + 20k)) = 約3.3V

UART接続の注意③ 通信モジュールを2組つなぐ対応

先述の通り、今回インバーターの出力2系統をそれぞれ測定するために、PZEM-004Tを2組使う。
通信方式は、UARTを使うのだが、ラズパイ側にはUARTの通信GPIO端子が1組分(GPIO14_TxD,GPIO15_RxD)しかない。

そのため、もう1組分の接続はどうするか、ということになるのだが、幸いUART→USBへの変換ケーブル(USB–TTL変換モジュール)というのがある。もう1組分は、ラズパイ側のmicroUSB端子を使って入力するようにする。(間にmicroUSB ⇔USB-Aのコネクタを入れる必要があるが)。

Amazonでは、変換ケーブル付きのセットもあるので、これで対応することにする。

PZEM計測用コンセント治具の制作

PZEM-004TのCTをかましやすいように、治具を作成。


通信モジュールPZEM-004Tの接続

pythonプログラム( PZEM-004Tから値取得 → CSVファイルに書込)

/home/pi/Documents/power-measurement/pzem004t/pzem_logger.py

#!/usr/bin/env python3
import minimalmodbus
import serial
import csv
import os
from datetime import datetime

# --- PZEM設定 ---
PORT = "/dev/serial0"  # UARTポート
SLAVE_ADDRESS = 1      # PZEM-004TのModbusアドレス

instrument = minimalmodbus.Instrument(PORT, SLAVE_ADDRESS)
instrument.serial.baudrate = 9600
instrument.serial.bytesize = 8
instrument.serial.parity   = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout  = 1
instrument.mode = minimalmodbus.MODE_RTU

# --- 保存フォルダとファイル名 ---
csv_dir = "/home/pi/Documents/power-measurement/pzem004t/csv"
os.makedirs(csv_dir, exist_ok=True)  # フォルダがなければ作成

today = datetime.now().strftime("%Y%m%d")
csv_filename = os.path.join(csv_dir, f"{today}_power.csv")

# --- ヘッダ ---
header = ["time", "voltage(V)", "current(A)", "power(W)", "energy(Wh)", "frequency(Hz)", "pf"]

# --- データ取得 ---
try:
    voltage   = instrument.read_register(0x0000, 0,4) / 10.0  # 電圧 (V)
    current   = instrument.read_register(0x0001, 0,4) / 1000.0  # 電流 (A)
    power     = instrument.read_register(0x0003, 0,4) / 10.0  # 電力 (W)
    energy    = instrument.read_register(0x0005, 0,4)  # 電力量 (Wh)
    frequency = instrument.read_register(0x0007, 0,4) / 10.0  # 周波数 (Hz)
    pf        = instrument.read_register(0x0008, 0,4) / 100.0  # 力率

    current_time = datetime.now().strftime("%H:%M:%S")
    data = [
        current_time, voltage, current, power, energy, frequency, pf
    ]
    # --- 整形表示 ---
    print(f"{current_time},{round(voltage, 1)},{round(current, 3)},"
        f"{round(power, 1)},{energy},{round(frequency, 1)},{round(pf, 2)}")

    # --- CSV書き込み ---
    file_exists = os.path.exists(csv_filename)
    with open(csv_filename, "a", newline="") as f:
        writer = csv.writer(f)
        if not file_exists:
            writer.writerow(header)
        writer.writerow(data)

    print(f"Data saved to {csv_filename}")

except Exception as e:
    print(f"Error reading PZEM-004T: {e}")

Webページに表示

基本方針は、取得したデータをcsvファイルに書き込んで、csvファイルと、index.phpをcronを使って10分ごとにサーバーにアップロード。

アップロード用スクリプト
/home/pi/Documents/power-measurement/html/upload-volt.sh

#!/bin/bash
TODAY=$(date '+%Y%m%d')
LOCAL_CSV="/home/pi/Documents/power-measurement/ina260/csv/$TODAY.csv"
LOCAL_CSV_A="/home/pi/Documents/power-measurement/pzem004t/csv/${TODAY}_pzemA.csv"
LOCAL_CSV_B="/home/pi/Documents/power-measurement/pzem004t/csv/${TODAY}_pzemB.csv"
LOCAL_PHP="/home/pi/Documents/power-measurement/html/index.php"
REMOTE_DIR="/home/supp/www/rasppi/ina260"
FTP_USER="****"
FTP_PASS="********"
FTP_HOST="******.sakura.ne.jp"  //さくらサーバーなもので。。

# CSV アップロード
ncftpput -u "$FTP_USER" -p "$FTP_PASS" "$FTP_HOST" "$REMOTE_DIR" "$LOCAL_CSV"
ncftpput -u "$FTP_USER" -p "$FTP_PASS" "$FTP_HOST" "$REMOTE_DIR" "$LOCAL_CSV_A"
ncftpput -u "$FTP_USER" -p "$FTP_PASS" "$FTP_HOST" "$REMOTE_DIR" "$LOCAL_CSV_B"

# index.php アップロード
ncftpput -u "$FTP_USER" -p "$FTP_PASS" "$FTP_HOST" "$REMOTE_DIR" "$LOCAL_PHP"

ループ作業のための、cron設定

crontab -e

/tmp/crontab.bwP7NL/crontab

*/10 * * * * /usr/bin/python3 /home/pi/Documents/power-measurement/pzem004t/pzem_logger.py
*/10 * * * * /usr/bin/python3 /home/pi/Documents/power-measurement/ina260/volt_logger.py
*/10 * * * * sh /home/pi/Documents/power-measurement/html/upload-volt.sh


Webでの表示に用いるindex.phpは、アドバイザーGPTと相談しながら、プログラムを改善していきました。以下のようなWeb表示が出来るようになりました。

ラズパイによる電力モニタリングの画面

これで、外出先でもスマートフォンで、今までのバッテリー電圧に加えて、太陽光で作った電気の使用状況がほぼリアルタイムで分かるようになりました。

感想

こういうの、個人的にはとにかく楽しい。
やっていくうちに色々と学びが増えていくし。
ネット上の諸先輩方に感謝するとともに、今更年甲斐もなく電子工作に目覚めつつあることに喜びを覚えながら、これからも楽しくDIYしていこうと思います。

今回のDIYプロジェクトは、とてもやりがいがあって楽しかったですね!

Web表示用プログラム index.php

index.phpは以下にコードを記載しています。

コメント

タイトルとURLをコピーしました