ECHONET LiteとGrafanaで自宅の電力消費を見てみる

2023-12-06

この記事は みすてむず アドベントカレンダー(2) 6日目の記事です。


ECHONET Liteで自宅の太陽光発電と蓄電池のメトリクスを取ってGrafanaでグラフを描いてみた話。

太陽光発電

ECHONET Liteてなに

ECHONET Liteは、センサ類、白物家電、設備系機器など省リソースの機器をIoT化し、エネルギーマネジメントやリモートメンテナンスなどのサービスを実現するための通信仕様です。 https://echonet.jp/about/features/

最近の家電や住宅設備はネットワーク接続の機能を持っていて、太陽光パネルなら発電量、エアコンなら設定温度や風量などを外部の機器から取得・設定することができる。 ECHONET Liteはそのときの通信まわりを規格化したもの。

通常はこういったHEMS機器を通して家庭内のエネルギーの流れを見たり家電の遠隔コントロールを行うのに使われるが、 プロトコルの仕様が公開されているので自分でECNONET Liteのリクエストを投げてデータを取ることもできる。

今回は

  • Pythonを使ってECHONET Liteから太陽光発電と蓄電池の情報を取得し、OpenMetrics形式で出力
  • VictoriaMetricsで出力したメトリクスを収集・蓄積してGrafanaでダッシュボード化

をやってみた。

リポジトリ

gitlab.com/minokavva/hems-exporter

見るべき規格書

ECHONET Lite公式サイトのダウンロードページに行くと規格書や仕様書がいくつもあるが、とりあえず見るべきは以下の2つ。

  1. ECHONET Lite規格書 第2部 ECHONET Lite 通信ミドルウェア仕様
    • リクエストとレスポンスの形式が載ってる
  2. APPENDIX ECHONET機器オブジェクト詳細規定
    • 太陽光発電、エアコン、湯沸かし器、その他機器ごとに規定されているプロパティの一覧と値の形式が載ってる

PythonでECHONET Liteのパケットを投げる

通信ミドルウェア仕様に載ってる図とECHONET Lite対応の部屋のエアコンをPython3から操作してみたを参考にリクエストを組み立てる。 組み立てたリクエストをUDPマルチキャストで224.0.23.0へ送ると、同じネットワーク内のECNONET Lite機器からレスポンスが返ってくる。

ECHONET Lite電文形式

Pythonで書くとこんな感じ?

import socket
import textwrap

ECHONET_PORT = 3610


# ECHONET-Liteから情報取得
def fetch_echonet(edata):
    # ヘッダ
    ehd1 = "10"     # ECHONET-Lite
    ehd2 = "81"     # 規定電文形式
    tid = "0001"    # トランザクションID=1(使わないので固定)
    ehd = ehd1 + ehd2 + tid

    # 受信ソケット準備
    recv_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    recv_sock.bind(("0.0.0.0", ECHONET_PORT))

    # マルチキャストで送信
    destination_ip = "224.0.23.0"
    send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    send_sock.sendto(bytes.fromhex(ehd + edata), (destination_ip, ECHONET_PORT))
    send_sock.close()

    # 回答受信
    data = recv_sock.recv(1024)
    recv_sock.close()
    
    return data


# 蓄電池
def fetch_battery_metrics():
    # 送信元(自分)
    seoj = "05ff01"     # 管理・操作関連機器クラスグループ/コントローラ/インスタンス01

    # 送信先(蓄電池)
    deoj = "027d01"     # 住宅・設備機関連機器クラスグループ/蓄電池/インスタンス01
    esv = "62"          # プロパティ値読み出し要求
    opc = "02"          # 読み出すプロパティ2件
    prop1 = "d300"      # 瞬時充放電電力計測値/パラメータ0件
    prop2 = "e400"      # 蓄電残量3/パラメータ0件

    # リクエスト送信
    data = fetch_echonet(seoj + deoj + esv + opc + prop1 + prop2)
    
    # プロパティが2つあるはず
    opc_pos = 11
    if data[opc_pos] != 0x2:
        raise Exception(f"回答のプロパティの数が変(opc={data[opc_pos]:#x})")

    # プロパティ取り出し
    return {
        "electricity_flow": int.from_bytes(data[14:18], byteorder="big", signed=True),
        "state_of_charge": int.from_bytes(data[20:21], byteorder="big", signed=False),
    }

取得した数値を /metrics で公開すればOpenMetricsのexporterとしての準備はOK。gunicornと一緒にDockerコンテナにして走らせておく。

$ docker build -t hems-exporter .
$ docker run -d --restart=always --net=host hems-exporter
$ curl localhost:3216/metrics
battery_state_of_charge 100
battery_electricity_flow -56
pv_generated_electricity 293

Grafanaでグラフにしてみた

作ったexporter・VictoriaMetrics・Grafanaをどのご家庭にもある適当なサーバで動かして、それっぽくグラフを並べてみるとこんな感じ。 太陽光発電は天候に左右される部分が大きいので、途中からアメダスの情報も取り込んで色でわかるようにした。

1ヶ月ほど眺めていた感じでは、秋ごろの日照時間だと晴れていれば昼までに蓄電池の充電が終わって売電モード、曇りでも1日あればまぁフル充電にはなる。 逆に雨の日で寒くて暖房をつけたりするとほとんど蓄電池は充電されず、発電したそばから全部使っている(+足りない分を買電)状態。

おうちエネルギーダッシュボード

おわりに

今回は予想通りといえば予想通りのグラフが出てきたけど、自分の好きなようにデータを抽出して並べるのはおもしろい。 そしてこういう遊びをするときにProxmoxでサッとサーバが立てられると非常に便利。

ということで最後はみすてむずの大好きなemojiで締めようと思う。

自宅鯖買え

明日は あたまたりん(@atamatarin_) さんです。

※emojiのライセンスなど問題があれば修正しますので連絡ください

余談

実環境でECHONET Liteの動作を確認するにあたり、SSNGというアプリを使用した。 このアプリはもともとiPhoneとiPad用にリリースされているものだが、M1を積んだMacbook AirでもApp Storeからインストールして普通に動く。 Apple Siliconすげーなと思った。 (ついでにSwitchbotのアプリも試してみたが、インストール自体はできるものの動作しなかった)