これは、前々からやってみたかったこと。家の消費電力量をモニターしたいなぁと思っていたけどコストの面、予備知識が不足しているってことで敬遠してきたが、やっとその日が来た。
まず、家の電力を測定するには、2つの方法がある
- クランプ電流計を配電盤につけて電流量を測定し、そこから電力量を計算する
- スマートメーターからBルートサービスを使いWi-SUNで電力量をリアルタイムに取得する
1の方法で参考になるサイトは
2の方法で参考になるのは
この辺かな。とりあえず、2の方法はWi-SUNという無線規格でスマートメーターと通信してリアルタイムに情報を取得するというもの。Wi-SUNの通信ドングルを購入しないといけない。アマゾンで確認してみる
高いねぇ・・・。遊びで買うにはちょっと勇気が要るレベルw。見送りです。
1の方法も、クランプタイプの交流電流センサーを買う必要がある。色々あるが、最安値(であろう)の下を見つけた。1500円(2個)ならば、やってみる価値はありそう!。よって1の方法で進めることにした。
これは、SCT013-030という30Aまで計測できるタイプ。電流比1800:1で、62Ωの抵抗が内蔵されている。あんまり深く考えないで、
よくわかんないけど・・・この辺のセンサーかなぁ??
程度で購入。いつもどおりの中華発送で忘れそうになるころに届いた。
とりあえず、どんなものか?正常に動作するか?を検証するためにオシロスコープにつなぐ。オシロにつなぐ際に、オーディオ用の延長ケーブル(ダイソー)を分解改造して使う。ついでに、ラズパイZeroで運用予定なので電源コードを購入(3つで330円)。
それと、以前のソーラーパネルをつないだ電線にコンセントのメス・オスをつないぎ、2本のケーブルの割いたプチ延長ケーブルを作った。それにセンサーを挟め24ワットの半田こてをつないで波形を観察。
交流のセンサーは電磁誘導の原理で出力するので交流波で観測される。計測数値の中でRMSという数値が交流電圧の実効値となる。「RMSとは何ぞや」は下のサイトを参考にしてね。
大きくして見てもらうとRMS=7.92mVとなっている。62Ωの抵抗が入っているわけですから電流はオームの法則で計算できます。電流比は1800倍なのでそれをかけて、さらに100Vをかければ消費電力(W)となる。
$$\frac{0.00792V}{62Ω}\times1800倍\times100V=22.99W$$
24ワットの半田こてで22.99ワットはイイ線いってるよね~。
これを分電盤にある大元の電線に取り付ければ家の消費電力がわかる。一般家庭用の電源は単相3線(+100v 0v -100vの3本)で構成されている。どちらかの火線と中性線で100v負荷を接続できるし、2本の火線同士では200v負荷を接続できる。詳しくはwikiを読んでほしい。大体多くても契約電流は60A程度なので片方30Aとして、センサー計測範囲かなとおもう。
SCR-013-030での情報を集めたら、SCR-013-000を使っているサイトを見つけた。しかも、ADコンバータとして、すでに持っているADS1115を使っているというタイミングの良さw
ADS1115については本ブログの下のサイトを参考にしてね。
今までは、ADS1115はSingle-Ended Inputで使ってたけど、今回はDifferencial Input(差動入力)で使うようだ。また、高速サンプリングが必要になってくる。とりあえず、公式ライブラリの中に高速サンプリングのサンプルコードがあったので、それを見て変更していく。
変更点、追加点は以下
- サンプルコードはads1015になっているので、ads1115へ変更。
- 差動モードで2チャンネル分のadcオブジェクトを生成
- ads1015の最大サンプリングレートは3300spsだが、ads1115は860spsなので変更
- getRMS()で二乗平均平方根を求めている(実測)。
- 時間差から消費電力量(Wh)を計算して加算していき、一日毎のcsvに書き出す。
getRMS()の部分は上にある参考サイトのコードを参考にしたけど・・・
つか・・・拡大してもよくみえねぇ・・・。目を凝らしながら、この部分をpythonに書き換えた。この下には、ピーク電圧の最大値と最小値を使って近似計算するバージョンも載っている。これは
「波形がサイン波の場合は、波形のピークレベルに対して RMS 値は1/√2の大きさとなる」
を基にコード化したものと思う。実際pythonに書き直して計測したけどズレがでるようだ。オシロスコープで色々計測してみた結果、半田こては上のようなサイン波だっけど、電気毛布とかはサイン波にならなかった。負荷器具によっていろいろ変わりそうなので実測して計算するようにした。
あと、いまだに原因不明なんだけれども、下の掲載コードはch0とch1で2回1秒間計測しRMSを計測しているが、本当はch0・ch1を同時に計測しRMSを出したかった。でもそうすると、正しい電流値がとれなくなった。具体的には、ch0とch1が干渉しているような数値がとられてしまうようだった。2回に分けて計測すると正しい数値が取得できたのでそうしている。サンプリング周波数のからみかなぁと思ったんだけど原因追及できなった・・・。
実際のコードがこちら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
import math import time import board import busio import adafruit_ads1x15.ads1115 as ADS from adafruit_ads1x15.ads1x15 import Mode from adafruit_ads1x15.analog_in import AnalogIn from datetime import datetime import csv # Data collection setup RATE = 860 # Create the I2C bus with a fast frequency i2c = busio.I2C(board.SCL, board.SDA) # Create the ADC object using the I2C bus ads = ADS.ADS1115(i2c) chan0 = AnalogIn(ads, ADS.P0, ADS.P1) chan1 = AnalogIn(ads, ADS.P2, ADS.P3) # ADC Configuration ads.mode = Mode.CONTINUOUS ads.data_rate = RATE def getRMS(): voltage_ch0 : float = 0 sum_ch0 : float = 0 voltage_ch1 : float = 0 sum_ch1 : float = 0 counter= 0 timepo = time.time() while (time.time() - timepo < 1): voltage_ch0 = chan0.voltage sum_ch0 = sum_ch0 + voltage_ch0**2 counter = counter +1 voltage_ch0 = math.sqrt( sum_ch0 / counter) counter= 0 timepo = time.time() while (time.time() - timepo < 1): voltage_ch1 = chan1.voltage sum_ch1 = sum_ch1 + voltage_ch1**2 counter = counter +1 voltage_ch1 = math.sqrt( sum_ch1 / counter) return voltage_ch0,voltage_ch1 total_watth_ch0 : float = 0.0; total_watth_ch1 : float = 0.0; last_day = 0 while True: s_time = time.time() dt = datetime.fromtimestamp(s_time) if last_day!=dt.day: total_watth_ch0 = 0 total_watth_ch1 = 0 last_day = dt.day rms_vol_ch0,rms_vol_ch1 = getRMS() pass_sec = time.time()-s_time current_ch0 = (rms_vol_ch0 / 62) * 1800 current_ch1 = (rms_vol_ch1 / 62) * 1800 watt_ch0 = current_ch0 * 100 watt_ch1 = current_ch1 * 100 watth_ch0 = (pass_sec * watt_ch0) / 3600 watth_ch1 = (pass_sec * watt_ch1) / 3600 total_watth_ch0 += watth_ch0 total_watth_ch1 += watth_ch1 today = dt.strftime("%Y-%m-%d") nowtime = dt.strftime("%H:%M:%S") file_end = dt.strftime("%Y%m%d") print ('日付: %s 時刻: %s 全電力: %.2fw(%.2fwh) 電力ch0: %.2fw(%.2fwh) 電力ch1 %.2fw(%.2fwh)' % (today,nowtime,watt_ch0+watt_ch1,total_watth_ch0+total_watth_ch1,watt_ch0,total_watth_ch0,watt_ch1,total_watth_ch1)) with open('/home/pi/Desktop/homepower/homepower_%s.csv' % (file_end),'a') as f: writer = csv.writer(f) writer.writerow([today,nowtime,watt_ch0+watt_ch1,total_watth_ch0+total_watth_ch1,watt_ch0,total_watth_ch0,watt_ch1,total_watth_ch1]) |
とりあえず、取得で来ているが、精度は電力会社のスマートメータ値と比較してみてからになるかな。Looop電気はホームページ上で確認できるけど、2,3日後じゃないと見れないんだよなぁ・・・。
[追記 2019/12/20]
どうも、例外で止まることがある。原因はわからず。急に電流が変化したときにADCがエラーを起こしてしまうのかな?。止まられると困るので
上のサイトを参考にしながら、サービスを作り、止まったら再スタートさせるようにした。積算電力についてはリセットされてしまう(コーディング次第でどうにでもなると思う)けどとりあえずは記録し続けてくれている。
Looop電気の消費電力量と比較してみたところ、大体、1kwぐらい多い誤差が確認されている。誤差の割合としては8%程度とみているので、もーすこしデータをとってみてキャリブレーションしてみると数値を詰められるとおもう。
[追記 2020/04/28]
データのセンシングはArduinoのほうがいいかもと思いやっちゃいました。そっちの方が安定して計測できているので読んでみてください