As I Please

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

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


influxdb + grafana + python3 + python-influx データ投入 stringになってしまった。

InfluxDB Error: unsupported mean iterator type: *query.booleanInterruptIterator

というエラーが出た。meanが取れない?何でと思って、influxの中で各種データを見たら、ジャイロ、加速度、温度、気圧、その他全てのデータが 'string'になっていた。 cactiで使っているプログラム(python3)で、redisからデータを取ってきて do.wirte_points で書き込んでるだけだけど、redisで引っ張ってきたデータが文字列処理をしていることもあり、string形式を保ったまま influxdbに放り込まれてたっぽい。 float()とか int()(バッテリーは%の整数値)とcastして放り込み直して解決。

switchbot 温湿度計2つ目 交換品

がamazonから送られてきたのでさっそくつ買ってみた。冷蔵庫の中に新しいものと古いものをほぼ同じ場所に置いて計測。(cactiから influxdb + grafana に移行中)

古いswitchbot温湿度計
switchbot_old_b.png

新しいswitchbot温湿度計
switchbot_new_b.png


データは5分に1回取得するように設定。一目瞭然で、新しい方はほぼデータを拾えているのに、古い方は1時間1回程度。
製品の性能にばらつきありすぎのような気もするけど、中華製ならこんなもんですか?
とりあえずこの新しいものを冷蔵庫に。
また、gatt でエラーが出る件についても、新しい方では解消しなかった。
charastaristicsは同じようだが。。。
ただ、公式githubには、同じことを言っている人がいる。2022/02/10 の投稿のようなのでやはり最近の話っぽい。公式のレスポンスは無いが、そろそろ何か書き込みあるかも。

スマートメーター 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ルート製品が出ているのも気になる。

memcached の監視 by cacti

とりあえず、cacti or zabbix で監視対象にする。
cacti で探すと、

http://dealnews.com/developers/cacti/memcached.html

Data Input Methods は、phthon を使った scriptなので、pythonのinstallのやり直し( 2.5)から始まる。

mina# /usr/local/bin/python memcached.py localhost

total_items:670 get_hits:1849 uptime:26651 cmd_get:2779 time:1237381866 bytes:414522 curr_connections:3 connection_structures:4 bytes_written:1910143 limit_maxbytes:67108864 cmd_set:1000 curr_items:588 rusage_user:0.610411 get_misses:930 rusage_system:1.047495 bytes_read:607773 total_connections:41

無事データは取れてるっぽい。

memcached の監視 by cacti

とりあえず、cacti or zabbix で監視対象にする。
cacti で探すと、

http://dealnews.com/developers/cacti/memcached.html

Data Input Methods は、phthon を使った scriptなので、pythonのinstallのやり直し( 2.5)から始まる。

mina# /usr/local/bin/python memcached.py localhost

total_items:670 get_hits:1849 uptime:26651 cmd_get:2779 time:1237381866 bytes:414522 curr_connections:3 connection_structures:4 bytes_written:1910143 limit_maxbytes:67108864 cmd_set:1000 curr_items:588 rusage_user:0.610411 get_misses:930 rusage_system:1.047495 bytes_read:607773 total_connections:41

無事データは取れてるっぽい。

memcached の監視 by cacti

とりあえず、cacti or zabbix で監視対象にする。
cacti で探すと、

http://dealnews.com/developers/cacti/memcached.html

Data Input Methods は、phthon を使った scriptなので、pythonのinstallのやり直し( 2.5)から始まる。

mina# /usr/local/bin/python memcached.py localhost

total_items:670 get_hits:1849 uptime:26651 cmd_get:2779 time:1237381866 bytes:414522 curr_connections:3 connection_structures:4 bytes_written:1910143 limit_maxbytes:67108864 cmd_set:1000 curr_items:588 rusage_user:0.610411 get_misses:930 rusage_system:1.047495 bytes_read:607773 total_connections:41

無事データは取れてるっぽい。