As I Please

MTのいんすとーるの練習と、その他びぼうろく・・・

タグ「HEMS」が付けられているもの


スマートメーター HEMS データのグラフ化 for python3

HEMSでデータが取得出来るようになったので、時系列でグラフ化してみる。 自宅では特に発電してるわけでもないので、「定時積算電力量計測値(逆方向計測値)」とか、履歴はいらないか。
ここでは「瞬時電流計測値」「瞬時電力計測値」「積算電力量計測値(正方向計測値)」「積算電力量計測値(逆方向計測値)」を測り、cacti の scriptsで動かして5分毎のデータをグラフ化。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#  smartmeter.py3
#
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
# Bルート認証パスワード設定
wcom="SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
# Bルート認証ID設定
wcom="SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
scanRes = {} # スキャン結果の入れ物
scanRes["Channel"]="33"
scanRes["Channel Page"]="09"
scanRes["Pan ID"]="24EF"
scanRes["Addr"]="00FFEEDDCCBBAA99"
scanRes["LQI"]="3C"
scanRes["PairID"]="12345678"
# スキャン結果からChannelを設定。
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
#print(ser.readline(), end="") # エコーバック
ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
ser.readline()
# スキャン結果からPan IDを設定
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
#print(ser.readline(), end="") # エコーバック
ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
ser.readline()
# 直接指定しちゃう
ipv6Addr = "FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99"
#
# いきなり SKJOINをしてもつながらないことがあるため、SKPINGしてみます。
#
while True:
    wcom="SKPING " + ipv6Addr + "\r\n"
    ser.write(str.encode(wcom))
    time.sleep(1)
#    print(ser.readline(), end="") # echo
#    print(ser.readline(), end="") # res
    pingres = ser.readline() #
    if pingres.startswith(b"OK"):
       break
#
#
#
# PANA 接続シーケンスを開始します。
#time.sleep(1)
wcom="SKJOIN " + ipv6Addr + "\r\n"
ser.write(str.encode(wcom))
# PANA 接続完了待ち(10行ぐらいなんか返してくる)
bConnected = False
while not bConnected :
    line = ser.readline()
#    print(line, end="")
    if line.startswith(b"EVENT 24") :
#        print("PANA 接続失敗")
        sys.exit()  #### 糸冬了 ####
    elif line.startswith(b"EVENT 25") :
        # 接続完了!
        bConnected = True
# これ以降、シリアル通信のタイムアウトを設定
ser.timeout = 2
# スマートメーターがインスタンスリスト通知を投げてくる
# (ECHONET-Lite_Ver.1.12_02.pdf p.4-16)
#print(ser.readline(), end="") #無視
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL) : 最新版は ver 1.13_02
    #  ・Appendix_H.pdf (以下 AppH)            : 最新版は J (2018/07/30現在)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b"" # echonetLiteFrame type is byte
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
    echonetLiteFrame += b'\xE7'          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
#    echonetLiteFrame += "\xE8"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E7" :
                # 内容が瞬時電力計測値(E7)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
                intPower = int(hexPower, 16)
                outputE7=intPower
                break
#####################################################################################################
#
#   for EPC = 0xE8 (瞬時電流計測値)
#
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    echonetLiteFrame += b'\xE8'          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
#    print(ser.readline(), end="") # エコーバック
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E8" :
                # 内容が瞬時電流力計測値(E8)だったら
#                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
                rCur = res[-8:-4]
                tCur = res[-4:]
                intrCur = round( float( int(rCur, 16) * 0.1 ), 1)
                inttCur = round( float( int(tCur, 16) * 0.1 ), 1)
                break
##################################################################################################
#
#   for EPC = 0xE0 (積算電力量計測値(正方向計測値))
#
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    echonetLiteFrame += b'\xE0'          # EPC(参考:EL p.3-7 AppH p.3-275) : 積算電力量計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
#    print(ser.readline(), end="") # エコーバック
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E0" :
                # 内容が瞬時電流力計測値(E8)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
#                floatPower = round ( float( int( hexPower, 16) * 0.1 ),1)
#               cacti の Data Source で COUNTER を使いたい、となるとデータは intでなくてはいけなくて、floatはだめ。
#               なので、係数を使わずにそのままにする。
                intPower =  int( hexPower, 16)
                break
##################################################################################################
#
#   for EPC = 0xE3 (積算電力量計測値(逆方向計測値))
#
while True:
    #  for EPC = 0xE3
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
    echonetLiteFrame += b'\xE3'          # EPC(参考:EL p.3-7 AppH p.3-275) : 積算電力量計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
    ser.readline()
    ser.readline()
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E3" :
                # 内容が瞬時電流力計測値(E8)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
                intPowerM = int(hexPower, 16)
                break
#######################################################################################################
#
print ("E7:{0} E8r:{1} E8t:{2} E0:{3} E3:{4}".format(outputE7,intrCur,inttCur,intPower,intPowerM),end="")
#
#
ser.close()

出力はcactiに食わせる形式にしていて、E7:瞬時電力計測値,E8r:瞬時電流計測値(R相),E8t:瞬時電流計測値(T相),E0:積算電力量計測値(正方向計測値),E3:積算電力量計測値(逆方向計測値)。

raspberrypi:~/smartmeter3# python3 /usr/share/cacti/scripts/smartmeter.py3
E7:686 E8r:7.0 E8t:1.0 E0:86704 E3:10
瞬間電力値、瞬間電流値は5分に1回のピンポイントの計測なので、瞬発的な消費は拾えてないこともある。

瞬間電流値の5分グラフ(T相、R相) cacti_graph_143.png 電子レンジ、電気ポットなどでの瞬間ピークが出ている。

瞬間電力値 cacti_graph_142.png

積算電力量を cactiの counterでグラフ化したもの。 cacti_graph_144.png 5分データだと、最小単位(0.1 KWH)を超えないときがある。もっと細かな数値が取れると良いけど HEMS機器の出力積算電力量単位(EPC 0xE1)が 0.1 kWhなので難しい。

瞬間値については5分に1回ではなくもっと詳細に取るのもありだと思うが、一応HEMSのBルートは送信制限時間の制限(たしか1時間に360秒)がある。たとえばここ。この制限、どういう基準で計測しての360秒なのか詳しくわからない。まさか TCPでの接続セッションの時間とは思えない。UDPだとさらにわかりにくい?。電波系に詳しい人にはご承知おきのことかもしれない。にしても、連続して毎秒で計測値を取るような利用の仕方だとあっさり超えそうな気もする。
今後は、この資料のP.32にもあるように、「通信負担を軽減する目的から、1つのパケットで複数のコマンド処理が可能なマルチゲットコマンド(エコーネットコンソーシアムが定義)などの実装が推奨される。」を行ってみることか? 最近はいろいろな Bルート製品が出ているのも気になる。

スマートメーター HEMS データのグラフ化 for python3

HEMSでデータが取得出来るようになったので、時系列でグラフ化してみる。 自宅では特に発電してるわけでもないので、「定時積算電力量計測値(逆方向計測値)」とか、履歴はいらないか。
ここでは「瞬時電流計測値」「瞬時電力計測値」「積算電力量計測値(正方向計測値)」「積算電力量計測値(逆方向計測値)」を測り、cacti の scriptsで動かして5分毎のデータをグラフ化。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#  smartmeter.py3
#
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
# Bルート認証パスワード設定
wcom="SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
# Bルート認証ID設定
wcom="SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
scanRes = {} # スキャン結果の入れ物
scanRes["Channel"]="33"
scanRes["Channel Page"]="09"
scanRes["Pan ID"]="24EF"
scanRes["Addr"]="00FFEEDDCCBBAA99"
scanRes["LQI"]="3C"
scanRes["PairID"]="12345678"
# スキャン結果からChannelを設定。
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
#print(ser.readline(), end="") # エコーバック
ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
ser.readline()
# スキャン結果からPan IDを設定
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
#print(ser.readline(), end="") # エコーバック
ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
ser.readline()
# 直接指定しちゃう
ipv6Addr = "FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99"
#
# いきなり SKJOINをしてもつながらないことがあるため、SKPINGしてみます。
#
while True:
    wcom="SKPING " + ipv6Addr + "\r\n"
    ser.write(str.encode(wcom))
    time.sleep(1)
#    print(ser.readline(), end="") # echo
#    print(ser.readline(), end="") # res
    pingres = ser.readline() #
    if pingres.startswith(b"OK"):
       break
#
#
#
# PANA 接続シーケンスを開始します。
#time.sleep(1)
wcom="SKJOIN " + ipv6Addr + "\r\n"
ser.write(str.encode(wcom))
# PANA 接続完了待ち(10行ぐらいなんか返してくる)
bConnected = False
while not bConnected :
    line = ser.readline()
#    print(line, end="")
    if line.startswith(b"EVENT 24") :
#        print("PANA 接続失敗")
        sys.exit()  #### 糸冬了 ####
    elif line.startswith(b"EVENT 25") :
        # 接続完了!
        bConnected = True
# これ以降、シリアル通信のタイムアウトを設定
ser.timeout = 2
# スマートメーターがインスタンスリスト通知を投げてくる
# (ECHONET-Lite_Ver.1.12_02.pdf p.4-16)
#print(ser.readline(), end="") #無視
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL) : 最新版は ver 1.13_02
    #  ・Appendix_H.pdf (以下 AppH)            : 最新版は J (2018/07/30現在)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b"" # echonetLiteFrame type is byte
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
    echonetLiteFrame += b'\xE7'          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
#    echonetLiteFrame += "\xE8"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E7" :
                # 内容が瞬時電力計測値(E7)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
                intPower = int(hexPower, 16)
                outputE7=intPower
                break
#####################################################################################################
#
#   for EPC = 0xE8 (瞬時電流計測値)
#
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    echonetLiteFrame += b'\xE8'          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
#    print(ser.readline(), end="") # エコーバック
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E8" :
                # 内容が瞬時電流力計測値(E8)だったら
#                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
                rCur = res[-8:-4]
                tCur = res[-4:]
                intrCur = round( float( int(rCur, 16) * 0.1 ), 1)
                inttCur = round( float( int(tCur, 16) * 0.1 ), 1)
                break
##################################################################################################
#
#   for EPC = 0xE0 (積算電力量計測値(正方向計測値))
#
while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    echonetLiteFrame += b'\xE0'          # EPC(参考:EL p.3-7 AppH p.3-275) : 積算電力量計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
#    print(ser.readline(), end="") # エコーバック
    ser.readline()
#    print(ser.readline(), end="") # EVENT 21 が来るはず(チェック無し)
    ser.readline()
#    print(ser.readline(), end="") # OKが来るはず(チェック無し)
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
#    print(line, end="")
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E0" :
                # 内容が瞬時電流力計測値(E8)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
#                floatPower = round ( float( int( hexPower, 16) * 0.1 ),1)
#               cacti の Data Source で COUNTER を使いたい、となるとデータは intでなくてはいけなくて、floatはだめ。
#               なので、係数を使わずにそのままにする。
                intPower =  int( hexPower, 16)
                break
##################################################################################################
#
#   for EPC = 0xE3 (積算電力量計測値(逆方向計測値))
#
while True:
    #  for EPC = 0xE3
    echonetLiteFrame = b""
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
    echonetLiteFrame += b'\xE3'          # EPC(参考:EL p.3-7 AppH p.3-275) : 積算電力量計測値
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
    # コマンド送信
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
    ser.write(command)
    ser.readline()
    ser.readline()
    ser.readline()
    line = ser.readline()         # ERXUDPが来るはず
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b"ERXUDP") :
        line = line.decode()
        cols = line.strip().split(' ')
        res = cols[8]   # UDP受信データ部分
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        #OPC = res[22,22+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
            if EPC == "E3" :
                # 内容が瞬時電流力計測値(E8)だったら
                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
                intPowerM = int(hexPower, 16)
                break
#######################################################################################################
#
print ("E7:{0} E8r:{1} E8t:{2} E0:{3} E3:{4}".format(outputE7,intrCur,inttCur,intPower,intPowerM),end="")
#
#
ser.close()

出力はcactiに食わせる形式にしていて、E7:瞬時電力計測値,E8r:瞬時電流計測値(R相),E8t:瞬時電流計測値(T相),E0:積算電力量計測値(正方向計測値),E3:積算電力量計測値(逆方向計測値)。

raspberrypi:~/smartmeter3# python3 /usr/share/cacti/scripts/smartmeter.py3
E7:686 E8r:7.0 E8t:1.0 E0:86704 E3:10
瞬間電力値、瞬間電流値は5分に1回のピンポイントの計測なので、瞬発的な消費は拾えてないこともある。

瞬間電流値の5分グラフ(T相、R相) cacti_graph_143.png 電子レンジ、電気ポットなどでの瞬間ピークが出ている。

瞬間電力値 cacti_graph_142.png

積算電力量を cactiの counterでグラフ化したもの。 cacti_graph_144.png 5分データだと、最小単位(0.1 KWH)を超えないときがある。もっと細かな数値が取れると良いけど HEMS機器の出力積算電力量単位(EPC 0xE1)が 0.1 kWhなので難しい。

瞬間値については5分に1回ではなくもっと詳細に取るのもありだと思うが、一応HEMSのBルートは送信制限時間の制限(たしか1時間に360秒)がある。たとえばここ。この制限、どういう基準で計測しての360秒なのか詳しくわからない。まさか TCPでの接続セッションの時間とは思えない。UDPだとさらにわかりにくい?。電波系に詳しい人にはご承知おきのことかもしれない。にしても、連続して毎秒で計測値を取るような利用の仕方だとあっさり超えそうな気もする。
今後は、この資料のP.32にもあるように、「通信負担を軽減する目的から、1つのパケットで複数のコマンド処理が可能なマルチゲットコマンド(エコーネットコンソーシアムが定義)などの実装が推奨される。」を行ってみることか? 最近はいろいろな Bルート製品が出ているのも気になる。

スマートメーター HEMS データの取得 for python3

次に、取得した接続情報を元に、HEMSのデータを取得する。HEMSスマートメーターからの出力で例示した ECHONETの「低圧スマート電力量メータクラス規定」で、素のデータを読み出すシンプルなscriptを。前ページで取得した Channel,Channel Page, Pan ID, PairID,ついでにLQI(これは不要と思うけど・・・),IPv6アドレスを指定してすみやかにデータ取得するようにした。コメントが重複している部分が多いが、自分用の備忘録として。。。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#  see https://qiita.com/kanon700/items/d4df13d45c2a9d16b8b0
#
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
# Bルート認証パスワード設定
wcom="SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# Bルート認証ID設定
wcom="SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
scanDuration = 4;   # スキャン時間。サンプルでは6なんだけど、4でも行けるので。(ダメなら増やして再試行)
scanRes = {} # スキャン結果の入れ物
scanRes["Channel"]="33"
scanRes["Channel Page"]="09"
scanRes["Pan ID"]="24EF"
scanRes["Addr"]="00FFEEDDCCBBAA99"
scanRes["LQI"]="32"
scanRes["PairID"]="12345678"
# スキャン結果からChannelを設定。
wcom="SKSREG S2 " + scanRes["Channel"] + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# スキャン結果からPan IDを設定
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# MACアドレス(64bit)をIPV6リンクローカルアドレスに変換。
# (BP35A1の機能を使って変換しているけど、単に文字列変換すればいいのではという話も??)
#ser.write("SKLL64 " + scanRes["Addr"] + "\r\n")
#print(ser.readline(), end="") # エコーバック
#ser.readline()
#time.sleep(2)
#ipv6Addr = ser.readline().strip()
#
# 直接指定しちゃう
ipv6Addr = "FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99"
#
# いきなり SKJOINをしてもつながらないことがあるため、SKPINGしてみます。
#
while True:
    wcom="SKPING " + ipv6Addr + "\r\n"
    ser.write(str.encode(wcom))
    print(ser.readline().decode('utf-8'), end="",flush=True) # echo
#    print(ser.readline(), end="") # res
    pingres = ser.readline() #
    if pingres.startswith(b'OK'):
       print("come OK break")
       break
    pingres = ser.readline() #
    if pingres.startswith(b'OK'):
       print("come OK break")
       break
#
#
# PANA 接続シーケンスを開始します。
#
time.sleep(1)
wcom="SKJOIN " + ipv6Addr + "\r\n"
ser.write(str.encode(wcom))
time.sleep(1)
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
#ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
#ser.readline()
# PANA 接続完了待ち(10行ぐらいなんか返してくる)
bConnected = False
while not bConnected :
    line = ser.readline()
    print(line.decode('utf-8'), end="",flush=True)
    if line.startswith(b'EVENT 24') :
#        print("PANA 接続失敗")
        sys.exit()  #### 糸冬了 ####
    elif line.startswith(b'EVENT 25') :
        # 接続完了!
        print("connect PANA OK",flush=True)
        bConnected = True
# これ以降、シリアル通信のタイムアウトを設定
ser.timeout = 2
# スマートメーターがインスタンスリスト通知を投げてくる
# (ECHONET-Lite_Ver.1.12_02.pdf p.4-16)
#print(ser.readline(), end="") #無視
#
#
#  Appendix_H.pdf
#
#
# python3 で変更。key を str として定義。
# bytes.fromhex(key) にて、byte1文字に変換し、コマンドとして送信するよ
echonetproperty = { '80':["status","80","動作状態"],  'D3':["keisuu","D3","係数"],'D7':["sekisanpower","D7","積算電力有効桁数"], \
                    'E0':["sekisanpowerplus","E0","積算電力量計測値(正方向計測値)"]    ,'E1':["sekisanpowerplusminus","E1","積算電力量単位"],\
                    'E2':["sekisanpowerplushis","E2","積算電力量計測値履歴1"] ,'E3':["sekisanpowerminus","E3","積算電力量計測値(逆方向計測値)"],\
                    'E4':["sekisanpowerminushis","E4","積算電力量計測値履歴1(逆方向計測値)"],'E5':["sekisanhiscollectday","E5","積算履歴収集日1"],\
                    'E7':["nowpower","E7","瞬時電力計測値"], 'E8':["nowcurrent","E8","瞬時電流計測値"],'EA':["teijisekisanpowerplus","EA","定時積算電力量計測値(正方向計測値)"],\
                    'EB':["teijisekisanpowerminus","EB","定時積算電力量計測値(逆方向計測値)"],'EC':["teijisekisanpowerplusminus","EC","積算電力量計測値履歴1(正方向,逆方向)"],\
                    'ED':["sekisanhiscollectday2","ED","積算履歴収集日2"]  }
#
#
#
for key,value in sorted(echonetproperty.items()):
  keystr  = str(echonetproperty[key][1])
  keydesc = echonetproperty[key][2]
  print(key,keystr,keydesc,end="",flush=True)
#  print(key,keystr,keydesc)
#  print (u"EPC = {0}".format(keyecho))
  while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b"" # echonetLiteFrame type is byte
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
    key2=bytes.fromhex(key)
#    print("key2 = ",key2,flush=True)
    echonetLiteFrame += key2
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
#    echonetLiteFrame += "\xE8"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    # コマンド送信
#    command = "SKSENDTO 1 {0} 0E1A 1 {1:04X} {2}".format(ipv6Addr, len(echonetLiteFrame), echonetLiteFrame)
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
#    print(command,end="",flush=True)
    ser.write(command)
#    ser.write(str.encode(command))
#    print(readl.decode('utf-8').encode(),end="",flush=True)
    print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
    print(ser.readline().decode('utf-8'), end="",flush=True) # EVENT 21 が来るはず(チェック無し)
    print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
#    line = ser.readline()         # ERXUDPが来るはず
    line = ser.readline()  # 本来のデータ?をこちらで取得する
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b'ERXUDP') :
#        print("ERXUDP found",flush=True)
        print(line.decode('utf-8'),end="",flush=True)
        line = line.decode()
        cols = line.strip().split(' ')
#        print(cols)
        res = cols[8]   # UDP受信データ部分
#        print("res=",res)
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
#            if EPC == "E7" :
            if EPC == keystr :
                # 内容が瞬時電力計測値(E7)だったら
#                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
#                print(u"瞬時電力計測値:{0}[W]".format(intPower))
#                print((u"瞬時電力計測値:{0}[W]".format(intPower)).encode('utf-8'))
                break
#
ser.close()
コメントにも書いているが、SKJOINをいきなり行っても繋がらないケースがままあった。SKPING を叩いて寝ているデバイス?インターフェースを起こす(?)必要がある感じ。
出力結果は次の通り(一部省略)
SKSETPWD C PASSWORDDDDDDD
OK
SKSETRBID AAAABBBBCCCCDDDD
OK
SKSREG S2 33
OK
SKSREG S3 24EF
OK
SKPING FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
come OK break
EPONG FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
SKJOIN FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
OK
(省略)
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
EVENT 25 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
connect PANA OK
80 80 動作状態SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 00808700301224EF 1 0012 108100000EF0010EF0017301D50401028801
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
D3 D3 係数SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201D30400000001
D7 D7 積算電力有効桁数SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201D30400000001
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201D70106
E0 E0 積算電力量計測値(正方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201D70106
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E00400015208
E1 E1 積算電力量単位SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201E10101
E2 E2 積算電力量計測値履歴1SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 00D0 1081000102880105FF017201E2C200FFFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFE
E3 E3 積算電力量計測値(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E3040000000A
E4 E4 積算電力量計測値履歴1(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 00D0 1081000102880105FF017201E4C200FFFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFE
E5 E5 積算履歴収集日1SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201E501FF
E7 E7 瞬時電力計測値SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E70400000274
E8 E8 瞬時電流計測値SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E80400320014
EA EA 定時積算電力量計測値(正方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0019 1081000102880105FF017201EA0B07E4030E081E0000015206
EB EB 定時積算電力量計測値(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0019 1081000102880105FF017201EB0B07E4030E081E000000000A
EC EC 積算電力量計測値履歴1(正方向,逆方向)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 001D 1081000102880105FF017201EC0FFFFFFFFFFFFF01FFFFFFFEFFFFFFFE
ED ED 積算履歴収集日2SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0015 1081000102880105FF017201ED07FFFFFFFFFFFF01

スマートメーター HEMS データの取得 for python3

次に、取得した接続情報を元に、HEMSのデータを取得する。HEMSスマートメーターからの出力で例示した ECHONETの「低圧スマート電力量メータクラス規定」で、素のデータを読み出すシンプルなscriptを。前ページで取得した Channel,Channel Page, Pan ID, PairID,ついでにLQI(これは不要と思うけど・・・),IPv6アドレスを指定してすみやかにデータ取得するようにした。コメントが重複している部分が多いが、自分用の備忘録として。。。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#  see https://qiita.com/kanon700/items/d4df13d45c2a9d16b8b0
#
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
# Bルート認証パスワード設定
wcom="SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# Bルート認証ID設定
wcom="SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
scanDuration = 4;   # スキャン時間。サンプルでは6なんだけど、4でも行けるので。(ダメなら増やして再試行)
scanRes = {} # スキャン結果の入れ物
scanRes["Channel"]="33"
scanRes["Channel Page"]="09"
scanRes["Pan ID"]="24EF"
scanRes["Addr"]="00FFEEDDCCBBAA99"
scanRes["LQI"]="32"
scanRes["PairID"]="12345678"
# スキャン結果からChannelを設定。
wcom="SKSREG S2 " + scanRes["Channel"] + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# スキャン結果からPan IDを設定
wcom="SKSREG S3 " + scanRes["Pan ID"] + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
# MACアドレス(64bit)をIPV6リンクローカルアドレスに変換。
# (BP35A1の機能を使って変換しているけど、単に文字列変換すればいいのではという話も??)
#ser.write("SKLL64 " + scanRes["Addr"] + "\r\n")
#print(ser.readline(), end="") # エコーバック
#ser.readline()
#time.sleep(2)
#ipv6Addr = ser.readline().strip()
#
# 直接指定しちゃう
ipv6Addr = "FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99"
#
# いきなり SKJOINをしてもつながらないことがあるため、SKPINGしてみます。
#
while True:
    wcom="SKPING " + ipv6Addr + "\r\n"
    ser.write(str.encode(wcom))
    print(ser.readline().decode('utf-8'), end="",flush=True) # echo
#    print(ser.readline(), end="") # res
    pingres = ser.readline() #
    if pingres.startswith(b'OK'):
       print("come OK break")
       break
    pingres = ser.readline() #
    if pingres.startswith(b'OK'):
       print("come OK break")
       break
#
#
# PANA 接続シーケンスを開始します。
#
time.sleep(1)
wcom="SKJOIN " + ipv6Addr + "\r\n"
ser.write(str.encode(wcom))
time.sleep(1)
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
#ser.readline()
#print(ser.readline(), end="") # OKが来るはず(チェック無し)
#ser.readline()
# PANA 接続完了待ち(10行ぐらいなんか返してくる)
bConnected = False
while not bConnected :
    line = ser.readline()
    print(line.decode('utf-8'), end="",flush=True)
    if line.startswith(b'EVENT 24') :
#        print("PANA 接続失敗")
        sys.exit()  #### 糸冬了 ####
    elif line.startswith(b'EVENT 25') :
        # 接続完了!
        print("connect PANA OK",flush=True)
        bConnected = True
# これ以降、シリアル通信のタイムアウトを設定
ser.timeout = 2
# スマートメーターがインスタンスリスト通知を投げてくる
# (ECHONET-Lite_Ver.1.12_02.pdf p.4-16)
#print(ser.readline(), end="") #無視
#
#
#  Appendix_H.pdf
#
#
# python3 で変更。key を str として定義。
# bytes.fromhex(key) にて、byte1文字に変換し、コマンドとして送信するよ
echonetproperty = { '80':["status","80","動作状態"],  'D3':["keisuu","D3","係数"],'D7':["sekisanpower","D7","積算電力有効桁数"], \
                    'E0':["sekisanpowerplus","E0","積算電力量計測値(正方向計測値)"]    ,'E1':["sekisanpowerplusminus","E1","積算電力量単位"],\
                    'E2':["sekisanpowerplushis","E2","積算電力量計測値履歴1"] ,'E3':["sekisanpowerminus","E3","積算電力量計測値(逆方向計測値)"],\
                    'E4':["sekisanpowerminushis","E4","積算電力量計測値履歴1(逆方向計測値)"],'E5':["sekisanhiscollectday","E5","積算履歴収集日1"],\
                    'E7':["nowpower","E7","瞬時電力計測値"], 'E8':["nowcurrent","E8","瞬時電流計測値"],'EA':["teijisekisanpowerplus","EA","定時積算電力量計測値(正方向計測値)"],\
                    'EB':["teijisekisanpowerminus","EB","定時積算電力量計測値(逆方向計測値)"],'EC':["teijisekisanpowerplusminus","EC","積算電力量計測値履歴1(正方向,逆方向)"],\
                    'ED':["sekisanhiscollectday2","ED","積算履歴収集日2"]  }
#
#
#
for key,value in sorted(echonetproperty.items()):
  keystr  = str(echonetproperty[key][1])
  keydesc = echonetproperty[key][2]
  print(key,keystr,keydesc,end="",flush=True)
#  print(key,keystr,keydesc)
#  print (u"EPC = {0}".format(keyecho))
  while True:
    # ECHONET Lite フレーム作成
    #  参考資料
    #  ・ECHONET-Lite_Ver.1.12_02.pdf (以下 EL)
    #  ・Appendix_H.pdf (以下 AppH)
    #  for EPC = 0xE7  (瞬時電力計測値)
    echonetLiteFrame = b"" # echonetLiteFrame type is byte
    echonetLiteFrame += b'\x10\x81'      # EHD (参考:EL p.3-2) : 2byte目は \x81(電文形式1) or \x82(電文形式2)
    echonetLiteFrame += b'\x00\x01'      # TID (参考:EL p.3-3) : TID= Transaction ID
    # ここから EDATA
    echonetLiteFrame += b'\x05\xFF\x01'  # SEOJ (参考:EL p.3-3 AppH p.3-408~) : コントローラクラス規定
    echonetLiteFrame += b'\x02\x88\x01'  # DEOJ (参考:EL p.3-3 AppH p.3-274~) : 低圧スマート電力量メータクラス規定
    echonetLiteFrame += b'\x62'          # ESV(62:プロパティ値読み出し要求) (参考:EL p.3-5)  : Get
    echonetLiteFrame += b'\x01'          # OPC(1個)(参考:EL p.3-7)
#    echonetLiteFrame += "\x02"          # OPC(2個)(参考:EL p.3-7)   : 2つのデータを取得する。
#    echonetLiteFrame += "\xE7"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電力計測値
    key2=bytes.fromhex(key)
#    print("key2 = ",key2,flush=True)
    echonetLiteFrame += key2
    echonetLiteFrame += b'\x00'          # PDC(参考:EL p.3-9)
#    echonetLiteFrame += "\xE8"          # EPC(参考:EL p.3-7 AppH p.3-275) : 瞬時電流計測値 R相T相
#    echonetLiteFrame += "\x00"          # PDC(参考:EL p.3-9)
    # コマンド送信
#    command = "SKSENDTO 1 {0} 0E1A 1 {1:04X} {2}".format(ipv6Addr, len(echonetLiteFrame), echonetLiteFrame)
    com1 = "SKSENDTO 1 {0} 0E1A 1 {1:04X} ".format(ipv6Addr, len(echonetLiteFrame))
    command = com1.encode() + echonetLiteFrame
#    print(command,end="",flush=True)
    ser.write(command)
#    ser.write(str.encode(command))
#    print(readl.decode('utf-8').encode(),end="",flush=True)
    print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
    print(ser.readline().decode('utf-8'), end="",flush=True) # EVENT 21 が来るはず(チェック無し)
    print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
#    line = ser.readline()         # ERXUDPが来るはず
    line = ser.readline()  # 本来のデータ?をこちらで取得する
    # 取りこぼしたりして変なデータを拾うことがあるので
    # チェックを厳しめにしてます。
    if line.startswith(b'ERXUDP') :
#        print("ERXUDP found",flush=True)
        print(line.decode('utf-8'),end="",flush=True)
        line = line.decode()
        cols = line.strip().split(' ')
#        print(cols)
        res = cols[8]   # UDP受信データ部分
#        print("res=",res)
        #tid = res[4:4+4];
        seoj = res[8:8+6]
        #deoj = res[14,14+6]
        ESV = res[20:20+2]
        if seoj == "028801" and ESV == "72" :
            # スマートメーター(028801)から来た応答(72)なら
            EPC = res[24:24+2]
#            if EPC == "E7" :
            if EPC == keystr :
                # 内容が瞬時電力計測値(E7)だったら
#                hexPower = line[-8:]    # 最後の4バイト(16進数で8文字)が瞬時電力計測値
#                intPower = int(hexPower, 16)
#                print(u"瞬時電力計測値:{0}[W]".format(intPower))
#                print((u"瞬時電力計測値:{0}[W]".format(intPower)).encode('utf-8'))
                break
#
ser.close()
コメントにも書いているが、SKJOINをいきなり行っても繋がらないケースがままあった。SKPING を叩いて寝ているデバイス?インターフェースを起こす(?)必要がある感じ。
出力結果は次の通り(一部省略)
SKSETPWD C PASSWORDDDDDDD
OK
SKSETRBID AAAABBBBCCCCDDDD
OK
SKSREG S2 33
OK
SKSREG S3 24EF
OK
SKPING FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
come OK break
EPONG FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
SKJOIN FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
OK
(省略)
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
EVENT 25 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99
connect PANA OK
80 80 動作状態SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 00808700301224EF 1 0012 108100000EF0010EF0017301D50401028801
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
D3 D3 係数SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201800130
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201D30400000001
D7 D7 積算電力有効桁数SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201D30400000001
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201D70106
E0 E0 積算電力量計測値(正方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201D70106
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E00400015208
E1 E1 積算電力量単位SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201E10101
E2 E2 積算電力量計測値履歴1SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 00D0 1081000102880105FF017201E2C200FFFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFE
E3 E3 積算電力量計測値(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E3040000000A
E4 E4 積算電力量計測値履歴1(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 00D0 1081000102880105FF017201E4C200FFFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFE
E5 E5 積算履歴収集日1SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 000F 1081000102880105FF017201E501FF
E7 E7 瞬時電力計測値SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 01
OK
SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E70400000274
E8 E8 瞬時電流計測値SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0012 1081000102880105FF017201E80400320014
EA EA 定時積算電力量計測値(正方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0019 1081000102880105FF017201EA0B07E4030E081E0000015206
EB EB 定時積算電力量計測値(逆方向計測値)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0019 1081000102880105FF017201EB0B07E4030E081E000000000A
EC EC 積算電力量計測値履歴1(正方向,逆方向)SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 001D 1081000102880105FF017201EC0FFFFFFFFFFFFF01FFFFFFFEFFFFFFFE
ED ED 積算履歴収集日2SKSENDTO 1 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 0E1A 1 000E
EVENT 21 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 00
OK
ERXUDP FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99 FE80:0000:0000:0000:02FF:EEDD:CCBB:AA88 0E1A 0E1A 00808700301224EF 1 0015 1081000102880105FF017201ED07FFFFFFFFFFFF01

スマートメーター HEMS デバイススキャン for python3

以前書いた、HEMS 機器からのデータの取り出し関連で、とても参考にさせてもらった スマートメーターの情報を最安ハードウェアで引っこ抜くをベースにプログラムを書いた。
このサンプルプログラムはpython2 でのプログラムだったので、今後のためにもpython3 用に書き直しておいたほうが良かったので、作成してみた。例示してあるプログラムはデバイスを探索してデータを取得するのだが、定期的にデータを取得して時系列データを作成するのであれば、デバイス探索は毎回繰り返さなくても良い(スマートメーターのサイトローカルのIPv6アドレスで特定できる)ので、(1)デバイスを探索し、アクセスするための諸元データを取得する。(2)データを定期的に取得する。の2つにわけてしまうほうが良さそうで、それを実施してみた。 まずは (1)の python3 に自分なりに書き換えたものを。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
wcom = "SKVER\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # バージョン
#
# Bルート認証パスワード設定
wcom = "SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
ser.readline() # エコーバック
# Bルート認証ID設定
wcom = "SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
ser.readline()
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
ser.readline()
scanDuration = 4;   # スキャン時間。サンプルでは6なんだけど、4でも行けるので。(ダメなら増やして再試行)
scanRes = {} # スキャン結果の入れ物
# スキャンのリトライループ(何か見つかるまで)
#while not scanRes.has_key("Channel") :  python2
while not 'Channel' in scanRes :
        # アクティブスキャン(IE あり)を行う
        # 時間かかります。10秒ぐらい?
        #ser.write(str.encode("SKSCAN 2 FFFFFFFF " + str(scanDuration) + "\r\n"))
        wcom = "SKSCAN 2 FFFFFFFF " + str(scanDuration) + "\r\n"
        ser.write(str.encode(wcom))
        # スキャン1回について、スキャン終了までのループ
        scanEnd = False
        while not scanEnd :
            line = ser.readline()
            print(line.decode(), end="",flush=True)
#
            line = line.decode()
            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()  #### 糸冬了 ####
これを実行すると次のような結果が出てくる。
raspberrypi:~/smartmeter3# ./test-bs_scan.py
SKVER
EVER 1.2.8
SKSETPWD C PASSWORDDDDDDD
SKSETRBID AAAABBBBCCCCDDDD
SKSCAN 2 FFFFFFFF 4
OK
EVENT 20 FE80:0000:0000:0000:1234:5678:9ABC:DEF0
EPANDESC
  Channel:33
  Channel Page:09
  Pan ID:24EF
  Addr:00FFEEDDCCBBAA99
  LQI:32
  PairID:12345678
EVENT 22 FE80:0000:0000:0000:1234:5678:9ABC:DEF0
Addr は64bit、これを IPv6のリンクローカルアドレスに変換するには SKLL64 コマンドを使う、ようだが 単純に、MACアドレス 48bit を、EUI-64で変換する場合の、'FF:FE'の挿入をやめただけのよう。先頭の7bit目を反転させて、後半64bit の IPv6 アドレスにしてしまえば良いみたい。例の 'Addr:00FFEEDDCCBBAA99' なら、IPv6アドレスは 'FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99' になる、と思われる。
これで取得できた Channel, Channel Page, Pan ID,PairID, 生成した IPv6アドレスを利用して定期的なデータ取得 scriptを動かす。

スマートメーター HEMS デバイススキャン for python3

以前書いた、HEMS 機器からのデータの取り出し関連で、とても参考にさせてもらった スマートメーターの情報を最安ハードウェアで引っこ抜くをベースにプログラムを書いた。
このサンプルプログラムはpython2 でのプログラムだったので、今後のためにもpython3 用に書き直しておいたほうが良かったので、作成してみた。例示してあるプログラムはデバイスを探索してデータを取得するのだが、定期的にデータを取得して時系列データを作成するのであれば、デバイス探索は毎回繰り返さなくても良い(スマートメーターのサイトローカルのIPv6アドレスで特定できる)ので、(1)デバイスを探索し、アクセスするための諸元データを取得する。(2)データを定期的に取得する。の2つにわけてしまうほうが良さそうで、それを実施してみた。 まずは (1)の python3 に自分なりに書き換えたものを。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import serial
import time
# Bルート認証ID(東京電力パワーグリッドから郵送で送られてくる)
rbid  = "AAAABBBBCCCCDDDD"
# Bルート認証パスワード(東京電力パワーグリッドからメールで送られてくる)
rbpwd = "PASSWORDDDDDDD"
# シリアルポートデバイス名
#serialPortDev = 'COM3'  # Windows の場合
serialPortDev = '/dev/ttyUSB0'  # Linux(ラズパイなど)の場合
#serialPortDev = '/dev/cu.usbserial-A103BTPR'    # Mac の場合
#
ser = serial.Serial(serialPortDev, 115200)
#
wcom = "SKVER\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
print(ser.readline().decode('utf-8'), end="",flush=True) # バージョン
#
# Bルート認証パスワード設定
wcom = "SKSETPWD C " + rbpwd + "\r\n"
ser.write(str.encode(wcom))
ser.readline() # エコーバック
# Bルート認証ID設定
wcom = "SKSETRBID " + rbid + "\r\n"
ser.write(str.encode(wcom))
print(ser.readline().decode('utf-8'), end="",flush=True) # エコーバック
ser.readline()
print(ser.readline().decode('utf-8'), end="",flush=True) # OKが来るはず(チェック無し)
ser.readline()
scanDuration = 4;   # スキャン時間。サンプルでは6なんだけど、4でも行けるので。(ダメなら増やして再試行)
scanRes = {} # スキャン結果の入れ物
# スキャンのリトライループ(何か見つかるまで)
#while not scanRes.has_key("Channel") :  python2
while not 'Channel' in scanRes :
        # アクティブスキャン(IE あり)を行う
        # 時間かかります。10秒ぐらい?
        #ser.write(str.encode("SKSCAN 2 FFFFFFFF " + str(scanDuration) + "\r\n"))
        wcom = "SKSCAN 2 FFFFFFFF " + str(scanDuration) + "\r\n"
        ser.write(str.encode(wcom))
        # スキャン1回について、スキャン終了までのループ
        scanEnd = False
        while not scanEnd :
            line = ser.readline()
            print(line.decode(), end="",flush=True)
#
            line = line.decode()
            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()  #### 糸冬了 ####
これを実行すると次のような結果が出てくる。
raspberrypi:~/smartmeter3# ./test-bs_scan.py
SKVER
EVER 1.2.8
SKSETPWD C PASSWORDDDDDDD
SKSETRBID AAAABBBBCCCCDDDD
SKSCAN 2 FFFFFFFF 4
OK
EVENT 20 FE80:0000:0000:0000:1234:5678:9ABC:DEF0
EPANDESC
  Channel:33
  Channel Page:09
  Pan ID:24EF
  Addr:00FFEEDDCCBBAA99
  LQI:32
  PairID:12345678
EVENT 22 FE80:0000:0000:0000:1234:5678:9ABC:DEF0
Addr は64bit、これを IPv6のリンクローカルアドレスに変換するには SKLL64 コマンドを使う、ようだが 単純に、MACアドレス 48bit を、EUI-64で変換する場合の、'FF:FE'の挿入をやめただけのよう。先頭の7bit目を反転させて、後半64bit の IPv6 アドレスにしてしまえば良いみたい。例の 'Addr:00FFEEDDCCBBAA99' なら、IPv6アドレスは 'FE80:0000:0000:0000:02FF:EEDD:CCBB:AA99' になる、と思われる。
これで取得できた Channel, Channel Page, Pan ID,PairID, 生成した IPv6アドレスを利用して定期的なデータ取得 scriptを動かす。

HEMS 機器オブジェクトスーパークラス

電力スマートメーターは「住宅・設備関連機器クラスグループ」の「低圧スマート電力量メータクラス」だそうで、クラスグループ"0x02",クラスコード "0x88" になる。その他に取れるデータが無いかと見てみたら、一番上位の「機器オブジェクトスーパークラス」のデータにGetできるものがあるようなので、とりあえず見てみた。

プロパティ名称 EPC 取得データ 内容 備考
動作状態 0x80 30 ON
設置場所 0x81 61 庭・外周 場所番号 01
規格Version情報 0x82 00004600 Release F (?)
識別番号 0x83 ESV=52,読み出し応答不可
瞬時消費電力計測値 0x84 ESV=52,読み出し応答不可
積算消費電力計測値 0x85 ESV=52,読み出し応答不可
メーカ異常コード 0x86 ESV=52,読み出し応答不可
電流制限設定 0x87 ESV=52,読み出し応答不可
異常発生状態 0x88 42 異常発生無
異常内容 0x89 ESV=52,読み出し応答不可
メーカコード 0x8A 000016
事業場コード 0x8B ESV=52,読み出し応答不可
商品コード 0x8C ESV=52,読み出し応答不可
製造番号 0x8D 313233343536373839300000 1234567890
製造年月日 0x8E ESV=52,読み出し応答不可
節電動作設定 0x8F ESV=52,読み出し応答不可
遠隔操作設定 0x93 ESV=52,読み出し応答不可
現在時刻設定 0x97 0C35 12時41分
現在年月日設定 0x98 07E20803 2018年8月3日
電力制限設定 0x99 ESV=52,読み出し応答不可
積算運転時間 0x9A ESV=52,読み出し応答不可

意味があるデータは製造番号くらいで、ほぼ読み出し応答不可が帰ってきた。

excel 2 table にはここを利用

HEMS 機器オブジェクトスーパークラス

電力スマートメーターは「住宅・設備関連機器クラスグループ」の「低圧スマート電力量メータクラス」だそうで、クラスグループ"0x02",クラスコード "0x88" になる。その他に取れるデータが無いかと見てみたら、一番上位の「機器オブジェクトスーパークラス」のデータにGetできるものがあるようなので、とりあえず見てみた。

プロパティ名称 EPC 取得データ 内容 備考
動作状態 0x80 30 ON
設置場所 0x81 61 庭・外周 場所番号 01
規格Version情報 0x82 00004600 Release F (?)
識別番号 0x83 ESV=52,読み出し応答不可
瞬時消費電力計測値 0x84 ESV=52,読み出し応答不可
積算消費電力計測値 0x85 ESV=52,読み出し応答不可
メーカ異常コード 0x86 ESV=52,読み出し応答不可
電流制限設定 0x87 ESV=52,読み出し応答不可
異常発生状態 0x88 42 異常発生無
異常内容 0x89 ESV=52,読み出し応答不可
メーカコード 0x8A 000016
事業場コード 0x8B ESV=52,読み出し応答不可
商品コード 0x8C ESV=52,読み出し応答不可
製造番号 0x8D 313233343536373839300000 1234567890
製造年月日 0x8E ESV=52,読み出し応答不可
節電動作設定 0x8F ESV=52,読み出し応答不可
遠隔操作設定 0x93 ESV=52,読み出し応答不可
現在時刻設定 0x97 0C35 12時41分
現在年月日設定 0x98 07E20803 2018年8月3日
電力制限設定 0x99 ESV=52,読み出し応答不可
積算運転時間 0x9A ESV=52,読み出し応答不可

意味があるデータは製造番号くらいで、ほぼ読み出し応答不可が帰ってきた。

excel 2 table にはここを利用

HEMS スマートメーターからの出力

電灯契約を変えたことで、スマートメータに取り替えられた。
東電にBルートサービスを申し込んで、自宅raspberry pi3に テセラ・テクノロジーのRL7023 Stick-D/IPS を刺して計測し、グラフ化することを目標としてみる。
ほぼ、

スマートメーターの情報を最安ハードウェアで引っこ抜くを大変に参考にさせてもらった。

ECHONETの機器オブジェクト詳細規定の「低圧スマート電力量メータクラス規定」のところを読む。

https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/Release/Release_H_jp/Appendix_H.pdf

プロパティ名称 EPC 取得データ 内容 備考
動作状態 0x80 30 ON
係数 0xD3 00000001 1 0.1Kwh
積算電力量有効桁数 0xD7 06 6桁
積算電力量計測値
(正方向計測値)
0xE0 00003354 1314.0 (kWh)
積算電力量単位 0xE1 01 0.1 kWh
積算電力量計測値履歴1
(正方向計測値)
0xE2 (194 byte= 48 data) FFFFFFFE (初期設定)
積算電力量計測値
(逆方向計測値)
0xE3 00000015 2.1 kWh
積算電力量計測値履歴1
(逆方向計測値)
0xE4 (0xC2=194 byte = 48data) FFFFFFFE (初期設定)
積算履歴収集日1 0xE5 FF 設定無 (初期値)
瞬時電力計測値 0xE7 0000073C 1852 W
瞬時電流計測値 0xE8 0046006E R相 7.0(A) T相11.0(A)
定時積算電力量計測値
(正方向計測値)
0xEA 07E2071D17000000003354 2018年07月29日
23時00分00秒
1314.0 (kWh)
定時積算電力量計測値
(逆方向計測値)
0xEB 07E2071D17000000000015 2018年07月29日
23時00分00秒
2.1 (kWh)
積算電力量計測値履歴2
(正方向、逆方向計測値)
0xEC FFFFFFFFFFFF01F
FFFFFFEFFFFFFFE
(初期値)
積算履歴収集日2 0xED FFFFFFFFFFFF01 (初期値)

電子レンジを使っているときだったのでちょっと電力量が高いかも。

電力量単位が 0.1kWh、有効桁数が6桁あたりは見落としがちだった。

とりあえずグラフ化するのは、積算電力量、瞬時電力、瞬時電流あたりか?発電・売電はしていないので、逆方向は必要ないと思うが一応モニタしておくか。

HEMS スマートメーターからの出力

電灯契約を変えたことで、スマートメータに取り替えられた。
東電にBルートサービスを申し込んで、自宅raspberry pi3に テセラ・テクノロジーのRL7023 Stick-D/IPS を刺して計測し、グラフ化することを目標としてみる。
ほぼ、

スマートメーターの情報を最安ハードウェアで引っこ抜くを大変に参考にさせてもらった。

ECHONETの機器オブジェクト詳細規定の「低圧スマート電力量メータクラス規定」のところを読む。

https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/Release/Release_H_jp/Appendix_H.pdf

プロパティ名称 EPC 取得データ 内容 備考
動作状態 0x80 30 ON
係数 0xD3 00000001 1 0.1Kwh
積算電力量有効桁数 0xD7 06 6桁
積算電力量計測値
(正方向計測値)
0xE0 00003354 1314.0 (kWh)
積算電力量単位 0xE1 01 0.1 kWh
積算電力量計測値履歴1
(正方向計測値)
0xE2 (194 byte= 48 data) FFFFFFFE (初期設定)
積算電力量計測値
(逆方向計測値)
0xE3 00000015 2.1 kWh
積算電力量計測値履歴1
(逆方向計測値)
0xE4 (0xC2=194 byte = 48data) FFFFFFFE (初期設定)
積算履歴収集日1 0xE5 FF 設定無 (初期値)
瞬時電力計測値 0xE7 0000073C 1852 W
瞬時電流計測値 0xE8 0046006E R相 7.0(A) T相11.0(A)
定時積算電力量計測値
(正方向計測値)
0xEA 07E2071D17000000003354 2018年07月29日
23時00分00秒
1314.0 (kWh)
定時積算電力量計測値
(逆方向計測値)
0xEB 07E2071D17000000000015 2018年07月29日
23時00分00秒
2.1 (kWh)
積算電力量計測値履歴2
(正方向、逆方向計測値)
0xEC FFFFFFFFFFFF01F
FFFFFFEFFFFFFFE
(初期値)
積算履歴収集日2 0xED FFFFFFFFFFFF01 (初期値)

電子レンジを使っているときだったのでちょっと電力量が高いかも。

電力量単位が 0.1kWh、有効桁数が6桁あたりは見落としがちだった。

とりあえずグラフ化するのは、積算電力量、瞬時電力、瞬時電流あたりか?発電・売電はしていないので、逆方向は必要ないと思うが一応モニタしておくか。