ウチの電気メーターをスマートメーターに変更してもらったら、Raspberry Pi(ラズパイ)とWi-SUN通信できるUSBモジュールを使って瞬時電力と積算電力をハックして、激安で電気の見える化をする方法の続きです。
- 電気スマートメーターと自作HEMSで電気の見える化 準備編
- 自作HEMS 激安電気の見える化 完成!(現在このページにいます)
更新するのを忘れていて・・・遅くなってしまってスンマセンm(_ _)m
ちなみにPythonは詳しくなく、適当に改造しただけなのでバグやうまく動かないことが多々あると思います・・・おかしいところがありましたらご指導いただけると大喜びします♬
Wi-SUN USBドングルのRL7023のデバイス名を固定
まずはラズパイでUSBドングルのRL7023のデバイス名を固定するところから始めていきましょう。
USBデバイス名を固定する方法の詳しくは以下をお読みください。
ttyUSBを調べてみると以下の通り↓
$ ls /dev/ttyUSB* /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB_solar
HEMS用 Wi-SUNモジュール RL7023は、ttyUSB1にマウントされていました。この状態だと他のUSBデバイスが接続されるたびにデバイス名がttyUSB1・ttyUSB2・ttyUSB3などに変わってしまうので、デバイス名を固定していきます。
Vendor・Productを取得
まずはlsusbコマンドでRL7023のVendorとProductを調べていきます。
$ lsusb Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter Bus 001 Device 006: ID 0bda:0109 Realtek Semiconductor Corp. Bus 001 Device 007: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO) Bus 001 Device 005: ID 0424:7800 Standard Microsystems Corp. Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
QinHeng Electronics HL-340はチャージコントローラーのケーブル、Realtek Semiconductor Corp.はMicroUSBを刺したUSBアダプタ。
該当のRL7023は、ID 0403:6015 Future Technology Devices International, Ltdになっていました。
- idVendor:0403
- idProduct:6015
- メーカー:Future Technology Devices International, Ltd
このように取得できましたので、デバイス名/dev/ttyUSB1 を /dev/ttyUSB_powerに固定していきます。
固定デバイス情報を99-com.rulesに書く
venderとProductoの文字を入れて、シンボリックリンク名は「ttyUSB_power」にしました。
$ sudo vim /etc/udev/rules.d/99-com.rules #以下を追加します。 KERNEL=="ttyUSB*", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", SYMLINK+="ttyUSB_power"
これで再起動してもデバイス名が変わらず、必ず/dev/ttyUSB_powerを見に行きますのでエラーになることはありません。
ラズパイで電気スマートメーターと通信するための下準備
電気スマートメーターと通信するWi-SUNドングルのRL7023をラズパイで使えるようにいろいろとインストールしていきます。
pyserial
pyserialが必要なのでインストールする。
$ cd /tmp $ sudo curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" $ sudo python get-pip.py $ sudo pip install pyserial
電力データを保存するDB InfluxDB
電気スマートメーターから取得した電力データを保存するためのデータベースです。
インストールや設定などの詳しくはコチラ↓をご覧ください。
$ sudo pip install influxdb
他のMySQLなどのデータベースやクラウドに保存される方はInflaxDBは導入する必要はありません。
Pandas
InfluxDBのResultを取り出すときに使いますので、InflaxDBを使わない場合は必要ありません。
$ sudo pip install pandas
電気スマートメーターの電力データを取得してみる
この方のプログラムを改造させていただきました。ありがとうございますm(_ _)m
まずはテスト的にターミナルからコチラ↑からいただいたスクリプトを動かしてみます。
以下のように電気スマートメーターとWi-SUN通信デバイスが通信しました。
$ python power.py SKVER EVER 1.2.8 OK SKSETPWD C VL0BXEG5HQ7C OK SKSETRBID 000000BF7706672ECC7321273541992E OK SKSCAN 2 FFFFFFFF 4 OK EVENT 22 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 SKSCAN 2 FFFFFFFF 5 OK EVENT 20 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 EPANDESC Channel:3B Channel Page:09 Pan ID:2BD8 Addr:38AFD7FFFE2A7189 LQI:28 PairID:3541992E EVENT 22 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 SKSREG S2 3B OK SKSREG S3 2BD8 OK SKLL64 38AFD7FFFE2A7189 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 SKJOIN FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 OK EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 02 EVENT 02 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 EVENT 01 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 02CC 02CC 38AFD7FFFE2A7189 0 0028 00000028C00000028224BEA3B9C2315100060000000400000000000500030000000400000000000C EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 02CC 02CC 38AFD7FFFE2A7189 0 0068 00000068800000028224BEA3B9C231520005000000100000212F98B7587A10146E81077D23382AB80002000000380000016500382F008A9048003068EB3B4B694C7A22DE003D534D3030303030304246373730363637324543433733323132373335343139393245 EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 02CC 02CC 38AFD7FFFE2A7189 0 0054 00000054800000028224BEA3B9C2315300020000003B00000166003B2F808A9048003068EB3B4B694C7A22DE003DA6246BC411C3F4DFA0F738038D3079FF00000000F84958A16045B78BFCA3F75D9C9953064500 EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 02CC 02CC 38AFD7FFFE2A7189 0 0058 00000058A00000028224BEA3B9C2315400070000000400000000000000020000000400000366000400040000000400000000000100080000000400000001518000010000001000005BE4275B1CD6E2B485D84173C008071D EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 EVENT 25 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 108100960EF0010EF0017301D50401028801 SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 108100970288010EF0017302810161880142 SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000256 瞬時電力計測値:598[W] SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000256 瞬時電力計測値:598[W] SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000256 瞬時電力計測値:598[W] SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000256 瞬時電力計測値:598[W] SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000240 瞬時電力計測値:576[W] ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000240 SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000240 瞬時電力計測値:576[W] ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000240 SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK SKSENDTO 1 FE80:0000:0000:0000:ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000208 3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ERXUDP FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 FE80:0000:0000:0000:1207:23FF:FEA0:74C5 0E1A 0E1A 38AFD7FFFE2A7189 1 0012 1081000102880105FF017201E70400000208 瞬時電力計測値:520[W] SKSENDTO 1 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 0E1A 1 000E EVENT 21 FE80:0000:0000:0000:3AAF:D7FF:FE2A:7189 00 OK ・・・省略
瞬時電力計測値が永遠と取得できています。このスクリプトを改造して、瞬時電力計測値だけではなく積算電力量計測値や瞬時電流(A)などの値も取得していきます。
ECHONET エコーネット規格を調査
ここで電気スマートメーターとUSBドングルのRL7023がどのような通信をするのか、エコーネット規格を参照して簡単に調査していきます。
エコーネット規格 規格書
電気スマートメーターの通信規格の説明書↓を参考に、どうやって数値を取得していくか勉強していきます。
参考にしたのは以下の2つのPDFファイル
- APPENDIXECHONET機器オブジェクト詳細規定
- Release N 最新 2020 9/25
- Release H 旧版
- 第2部 ECHONET Lite 通信ミドルウェア仕様 ECHONET-Lite_Ver.1.13_02.pdf
電気以外にも色々とあって長すぎて見るのがメンドウです・・・
コチラ↓の方の表も参考にさせていただきました。ありがとうございますm(_ _)m
HEMS 電気スマートメーターから取得できる電力値
電気スマートメーターから取得できる値を調べてみた結果は以下のようになりました。
個人的に調べた結果で自分の能力不足な点が多々ありそうで理解できない値がありました。もっと知識のある方はちゃんと取得できるのかもしれません。
APPENDIXECHONET機器オブジェクト詳細規定 Release N 最新の3-307ページ「3.3.25低圧スマート電力量メータクラス規定」あたりを参考に値を調査・取得してみました。
送られてくるデータは16進数なので10進数に変換して意味を理解してみます。意味が分からない箇所「?」の部分は未解決。
EPC | プロパティ名称 | 取得データ | 内容 |
---|---|---|---|
D3 | 係数 | 00000001 | 1 |
D7 | 積算電力量有効桁数 | 06 | 6桁 |
E0 | 積算電力量計測値(正方向計測値) | 00022721 | 14108.9kWh |
E1 | 積算電力量単位(正方向、逆方向計測値) | 01 | 0.1kWh |
E2 | 積算電力量計測値履歴1(正方向計測値) | 00FFFFFFFFFEFFFFFFFE・・・省略 | ?? |
E3 | 積算電力量計測値(逆方向計測値) | FFFFFFFEE304FFFFFFFE | 4294967294 |
E4 | 積算電力量計測値履歴1(逆方向計測値) | 00FFFFFFFFFEFFFFFFFE・・・省略 | ?? |
E5 | 積算履歴収集日1 | FFE501 | 255 |
E7 | 瞬時電力計測値 | 000000CE | 206W |
E8 | 瞬時電流計測値 | 忘れた・・・ | |
EA | 定時積算電力量正方向 メーターの数値 | 7E30C060A00000002276C EA0B 07E3 | 2019年 0C=12月 06=6日 0A=10時 00=0分 00=0秒 0002276C=141164 |
EB | 定時 積算電力量 計測値 (逆方向計測値) | 7E30C06100000FFFFFFFE EB0B 07E3 | 2019年 0C=12月 06=6日10=16時 00 00 FFFFFFFE=4294967294 |
EC | 積算電力量計測値履歴2(正方向、逆方向計測値) | 取得できない | ウチのスマートメーターには無い |
ED | 積算履歴収集日2 | 取得できない | ウチのスマートメーターには無い |
このうち以下の6項目を取得できたので、今回は6項目だけをランダムに取得していきます。
- E0:積算電力量計測値(正方向計測値)
- E1:積算電力量単位(正方向、逆方向計測値)
- E3:積算電力量計測値(逆方向計測値)
- E7:瞬時電力計測値
- E8:瞬時電流計測値
- EA:定時積算電力量計測値(正方向計測値)
電気見える化のPythonプログラム
電気スマートメーターから取得した瞬時電流などの値をPythonで取得して、InflaxDBに保存するスクリプトです。
電気スマートメーターのデータを取得するpower_rand.py
以下、コチラのスクリプトを改造してE0、E1、E3、E7、E8、EAをランダムに取得するスクリプトです。
pip3 install git+https://github.com/AmbientDataInc/ambient-python-lib.git
Cronで一定時間ごとに動かして、無限ループなので一定時間ごとにpkillしてます。自分の環境では一応動いていますが、もっと良い方法などありましたらご指導しただけると喜びます♪
#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function import sys import serial import time import random import ctypes #unit32 #------------設定ココから------------------------ #influxDB from influxdb import InfluxDBClient client = InfluxDBClient(host='192.168.31.53', port=8086, username='root', password='パスワード', database='sensor') measurement = 'power' tags = {'place': 'umi','host': 'RL7023'} # Bルート認証ID rbid = "BルートでもらったID" # Bルート認証パスワード rbpwd = "パスワード" # シリアルポートデバイス名 serialPortDev = '/dev/ttyUSB_power' #------------設定ココまで------------------------ # シリアルポート初期化 ser = serial.Serial(serialPortDev, 115200) # とりあえずバージョンを取得してみる(やらなくてもおk) ser.write("SKVER\r\n") #print(ser.readline(), end="") # エコーバック #print(ser.readline(), end="") # バージョン # Bルート認証パスワード設定 ser.write("SKSETPWD C " + rbpwd + "\r\n") #print(ser.readline(), end="") # エコーバック #print(ser.readline(), end="") # OKが来るはず(チェック無し) # Bルート認証ID設定 ser.write("SKSETRBID " + rbid + "\r\n") #print(ser.readline(), end="") # エコーバック #print(ser.readline(), end="") # OKが来るはず(チェック無し) scanDuration = 4; # スキャン時間。サンプルでは6なんだけど、4でも行けるので。(ダメなら増やして再試行) scanRes = {} # スキャン結果の入れ物 #influxDBにアップロード def influx_json(field,nowtime=''): json_body = [ { 'measurement': measurement, 'tags': tags, 'fields': field #'time': nowtime } ] client.write_points(json_body) print(json_body) #sys.exit() # スキャンのリトライループ(何か見つかるまで) while not scanRes.has_key("Channel") : # アクティブスキャン(IE あり)を行う # 時間かかります。10秒ぐらい? ser.write("SKSCAN 2 FFFFFFFF " + str(scanDuration) + "\r\n") # スキャン1回について、スキャン終了までのループ scanEnd = False while not scanEnd : line = ser.readline() print(line, end="") if line.startswith("EVENT 22") : # スキャン終わったよ(見つかったかどうかは関係なく) scanEnd = True elif line.startswith(" ") : # スキャンして見つかったらスペース2個あけてデータがやってくる # 例 # Channel:39 # Channel Page:09 # Pan ID:FFFF # Addr:FFFFFFFFFFFFFFFF # LQI:A7 # PairID:FFFFFFFF cols = line.strip().split(':') scanRes[cols[0]] = cols[1] scanDuration+=1 if 7 < scanDuration and not scanRes.has_key("Channel"): # 引数としては14まで指定できるが、7で失敗したらそれ以上は無駄っぽい print("スキャンリトライオーバー") sys.exit() #### 糸冬了 #### # スキャン結果からChannelを設定。 ser.write("SKSREG S2 " + scanRes["Channel"] + "\r\n") print(ser.readline(), end="") # エコーバック print(ser.readline(), end="") # OKが来るはず(チェック無し) # スキャン結果からPan IDを設定 ser.write("SKSREG S3 " + scanRes["Pan ID"] + "\r\n") print(ser.readline(), end="") # エコーバック print(ser.readline(), end="") # OKが来るはず(チェック無し) # MACアドレス(64bit)をIPV6リンクローカルアドレスに変換。 # (BP35A1の機能を使って変換しているけど、単に文字列変換すればいいのではという話も??) ser.write("SKLL64 " + scanRes["Addr"] + "\r\n") print(ser.readline(), end="") # エコーバック ipv6Addr = ser.readline().strip() print(ipv6Addr) # PANA 接続シーケンスを開始します。 ser.write("SKJOIN " + ipv6Addr + "\r\n"); print(ser.readline(), end="") # エコーバック print(ser.readline(), end="") # OKが来るはず(チェック無し) # PANA 接続完了待ち(10行ぐらいなんか返してくる) bConnected = False while not bConnected : line = ser.readline() print(line, end="") if line.startswith("EVENT 24") : print("PANA 接続失敗") sys.exit() #### 糸冬了 #### elif line.startswith("EVENT 25") : # 接続完了! bConnected = True # これ以降、シリアル通信のタイムアウトを設定 #ser.timeout = 2 # スマートメーターがインスタンスリスト通知を投げてくる # (ECHONET-Lite_Ver.1.12_02.pdf p.4-16) print(ser.readline(), end="") #無視 #powersの配列でランダムに取得していく。 #powersの配列を変えると他の値も取得できるかもしれませんのでやってみてください。 #特にソーラーパネルを導入して売電している方は逆方向計測値も取得したほうが良さそうです。 #powers = ["\xD3","\xD7","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE7","\xE8","\xEA","\xEB"] #powers = ["\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE7","\xE8","\xEA","\xEB"] powers = ["\xE0","\xE1","\xE3","\xE7","\xE8","\xEA"] #for echonet in powers:#配列を一つずつ取得していっても何故か?途中で終わるのでランダムで取得する while powers: echonetLiteFrame = "" echonetLiteFrame += "\x10\x81" # EHD (参考:EL p.3-2) echonetLiteFrame += "\x00\x01" # TID (参考:EL p.3-3) # ここから EDATA echonetLiteFrame += "\x05\xFF\x01" # SEOJ (参考:EL p.3-3 AppH p.3-408~) echonetLiteFrame += "\x02\x88\x01" # DEOJ (参考:EL p.3-3 AppH p.3-274~) echonetLiteFrame += "\x62" # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5) echonetLiteFrame += "\x01" # OPC(1個)(参考:EL p.3-7) randp = random.choice(powers) echonetLiteFrame += randp print(randp) echonetLiteFrame += "\x00" command = "SKSENDTO 1 {0} 0E1A 1 {1:04X} {2}".format(ipv6Addr, len(echonetLiteFrame), echonetLiteFrame) ser.write(command) print(ser.readline(), end="") # エコーバック print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し) print(ser.readline(), end="") # OKが来るはず(チェック無し) line = ser.readline() # ERXUDPが来るはず print(line, end="") if line.startswith("ERXUDP") : cols = line.strip().split(' ') res = cols[8] # UDP受信データ部分 seoj = res[8:8+6] ESV = res[20:20+2] #print(ESV) if seoj == "028801" and ESV == "72" : EPC = res[24:24+2] print(EPC) if EPC == "D3" :#係数 D304 00000001=1 print(EPC) elif EPC == "D7" :#積算電力量有効桁数 D701 06=6桁 print(EPC) elif EPC == "E0" :#積算電力量計測値(正方向計測値) E004 00022721=14108.9 0002272A=14109.8kWh hexPower = line[-8:] # 最後の4バイト(16進数で8文字)が瞬時電力計測値 intPower = int(hexPower, 16) print(EPC) print(u"sekisan{0}[kWh]".format(intPower)) field = {'E0': float(intPower)} influx_json(field) elif EPC == "E1" :#積算電力量単位(正方向、逆方向計測値) E10101=0.1kWh hexPower = line[-4:] # 最後の4バイト(16進数で8文字) intPower = int(hexPower, 16) print(EPC) print(u"sekisan seigyaku{0}[kWh]".format(intPower)) field = {'E1': float(intPower)} influx_json(field) elif EPC == "E2" :#積算電力量計測値履歴1(正方向計測値) ??? print(EPC) elif EPC == "E3" :#積算電力量計測値(逆方向計測値) E304 FFFFFFFE=4294967294 hexPower = line[-8:] # 最後の4バイト(16進数で8文字) intPower = int(hexPower, 16) print(EPC) print(u"sekisan Reverse{0}[kWh]".format(intPower)) field = {'E3': float(intPower)} influx_json(field) elif EPC == "E4" :#積算電力量計測値履歴1(逆方向計測値) ??? print(EPC) elif EPC == "E5" :#積算履歴収集日1:E501FF print(EPC) elif EPC == "E7" :# 瞬時電力計測値:E704 000000CE=206W hexPower = line[-8:] # 最後の4バイト(16進数で8文字)が瞬時電力計測値 intPower = int(hexPower, 16) print(EPC) print(u"power:{0}[W]".format(intPower)) field = {'power': float(intPower) } influx_json(field) #txtファイルに出力 with open('/home/pi/e7.txt', 'w') as f: print(float(intPower), file=f) elif EPC == "E8" :#瞬時電流(A) Current458792 最後の2バイト2個 hexCurR = line[-8:-4] hexCurT = line[-4:] intCurR = int(hexCurR, 16) intCurT = int(hexCurT, 16) intCurR = float(intCurR) intCurT = float(intCurT) intCurR = intCurR / 100 intCurT = intCurT / 100 print(EPC) #print(hexCurR) print(u"R:{0}[A]".format(intCurR)) #1280 153 print(u"T:{0}[A]".format(intCurT)) #54 97 32 61 field = {'E8_R': intCurR , 'E8_T': intCurT } influx_json(field) elif EPC == "EA" :#定時積算電力量正方向 メーターの数値 EA0B 07E3=2019年 0C=12月 06=6日 0A=10時 00=0分 00=0秒 0002276C=14116 hexYearKW = line[-22:-18] hexMoonKW = line[-18:-16] hexDayKW = line[-16:-1] hexTimeKW = line[-8:] # 最後の4バイト(16進数で8文字) nowtime = '{} {}:{}:{}'.format(hexYearKW, hexMoonKW, hexDayKW, hexTimeKW) print(u"Now {0}".format(nowtime)) intTimeKW = int(hexTimeKW, 16)#kWh print(EPC) print(u"teizi{0}[kWh]".format(intTimeKW)) field = {'EA': float(intTimeKW) } #influx_json(field,nowtime) influx_json(field) elif EPC == "EB" :#積算履歴収集日1:EB0B07E30C050B1E00FFFFFFFE print(EPC) elif EPC == "EC" :#積算電力量計測値履歴2(正方向、逆方向計測値) ウチのスマートメーターには無い print(EPC) elif EPC == "ED" :#積算履歴収集日2 ウチのスマートメーターには無い print(EPC) else : print("Other") print(EPC) time.sleep(1)
ファイルでもダウンロードできるようにしておきました。↓(右クリックして「リンク先を保存」を選択してダウンロードしてください。)
データベースにアップロードする電力の値
取得するデータは6項目でE1・E3は賃貸マンションで売電していない自分の場合は特に数値が変化することはありませんでしたが、数値が一定ですが一応データは送られてきます。
InflaxDB以外のデータベースやクラウドを使う場合は、influx_json関数でInflaxDBにアップロードしていますので、コチラを変更して、各プロパティのinflux_json(field)の部分も変更してみてください。
電気スマートメーターから送られてきた16進数データを10進数にしてわかるようにしたデータ名は以下の通りです。
- E0:E0(積算電力量計測値(正方向計測値))
- E1:E1(積算電力量単位(正方向、逆方向計測値))売電で使う?
- E3:E3(積算電力量計測値(逆方向計測値))売電している人は必要
- E7:power(瞬時電力計測値)
- E8:E8_R(電流R)、E8_T(電流T)
- EA:EA(定時積算電力量正方向 メーターの数値)
Grafana用 電力JSON
Grafanaをお使いの場合は以下のJSONをインサートすると手っ取り早いです。(右クリックして「リンク先を保存」を選択してダウンロードしてください。)
インサート方法はコチラ↓
Cron
最後にCronで定期的にスクリプトを実行していきます。
piユーザーで以下のようにCronを設定します。
pi@raspi3B:~ $ crontab -e #無限ループなので10分置きに終了させる */10 * * * * pkill -f power_rand.py > /home/pi/power_base_rand.log 2>&1 #D7やE7: 瞬時電力計測値・E8: 瞬時電流(A)などをランダムに取得する 3-58/5 * * * * /usr/bin/python /home/pi/script/power_rand.py > /home/pi/power_rand.log 2>&1 #再起動時に瞬間電力を表示 @reboot /usr/bin/python /home/pi/script/power_disp.py > /home/pi/power_disp.log 2>&1
power_disp.pyはラズパイに付けたちっちゃなディスプレイに瞬時電力を5付の機に更新さえて表示させています。
コチラ↓もPythonスクリプトをダウンロードできるようにしておきました。適当過ぎますけど・・・もしよかったらお使いください。(右クリックして「リンク先を保存」を選択してダウンロードしてください。)
power_rand.pyを実行すると、 Wi-SUN通信がおかしいのか?うまく接続できずにエラーになる場合↓もあります。接続できてもデータを取得できない場合もあってなんだか不安定です。
$ /usr/bin/python /home/pi/script/power_rand.py Traceback (most recent call last): File "/home/pi/script/power_rand.py", line 70, inline = ser.readline() File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 490, in read 'device reports readiness to read but returned no data ' serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Wi-SUN通信は?定期的にPythonスクリプトを実行しないとうまく接続できないようでした。
電気 見える化で電力グラフを作る まとめ
使用している電力会社が電気スマートメーターに替えて(自分で申請しても無料で替えてくれます。)くれたら、通常はHEMSを導入して電気の見える化ができますが、高額なHEMS機器を導入しなくても、Wi-SUN通信ができるUSBドングルとラズパイを使ってハックすれば簡易的に電気見える化のグラフを作ることができました。
今回の「自作 電気の見える化」のやり方は、電力会社に電気スマートメーターに替えてもらったら以下の準備をします。
- Linux:自分はRaspberry Pi 3Bを使いました。
- Wi-SUN機器:USBドングル RL7023
- InflaxDB:電気スマートメーターから取得した電力値を保存するデータベース
- Grafana:InflaxDBに保存してあるデータをグラフ表示してくれるアプリ
- Python:電力を取得してInflaxDBに保存するプログラムを作成
- Cron:作成したPythonプログラムを定期的に実行・停止する
市販のHEMSに表示されるパネルには劣りますが、瞬時電力や積算電力が以下のようにグラフ表示させることができました。
プログラムをもう少し進化させて、毎月の料金や毎日の電気使用量を計算できたら最高ですね。
けど、九州電力のページ見れば表示されるので必要ないかなぁ・・・
コメント
pythonの基礎から勉強中です。
def influx_json(field,nowtime=”):
の終わりはどこでしょうか?
returnは不要なのでしょうか?
onusay様
コメントありがとうございます。
自分もPythonは詳しくないので、ちゃんとお答えできるか不安ですが・・・
client.write_points(json_body)の部分でデーターをInfluxに送信しています。
なので、返り値(return)などは不要です。
Pythonはインデント(タブやスペース)で一つのブロックと認識されるようにできているので、PHPなどの他の言語のように{}は不要です。