SA-M0経由でECHONET Liteのスマートメーターにアクセスしてみた


概要

nodejsを使ってSA-M0を経由してスマートメーターの値を取得します。

SA-M0を経由することで、Wi-SUNアダプタの事を考えずに、LAN上にスマートメーターが存在しているように見えます。


まず最初に

ゼロスタートだったので、基礎知識を身につける為に以下を読みました。

ECHONET電文の作り方

これを読まないと echonet-lite の出力が理解できません。略語だらけなので。。。

一応本稿でも必要な略語は解説していますがこちらの方が正しい解説です。

https://qiita.com/miyazawa_shi/items/725bc5eb6590be72970d


Wi−SUNを直接喋る場合とSA-M0を経由する場合の違い

http://route-b.iij.ad.jp/archives/128

Wi-SUNアダプタを使って直接やりとりする場合は、上記blogのスマートメーターの探索〜認証・接続の処理を行う必要がありますが、

SA-M0を経由した場合、この部分はすべてSA-M0がやってくれます。(ただし、スマホアプリで初期設定をすることが必要です)

SA-M0からデータを取得するアプリケーションは、単純に暗号化等の事を考えずに、リクエストを送信すれば応答してくれます。楽です。


Node.jsの echonet-lite ライブラリの使い方

今回必要なのは情報の取得だけですが、思いっきりドハマリしたので echonet-lite ライブラリの使い方も含めて書いていきます。

機器スキャンのサンプルプログラム(下記URL) を題材にして説明します。

https://www.npmjs.com/package/echonet-lite


基本的な考え方


  • ECHONET機器(SA-M0)と通信を行う為には、自分自身もECHONET機器になる必要があります。

  • ECHONETの通信対象の区別は、 (IPを使う場合) IPアドレス + 機器ID で行われます。


  • echonet-lite 的に命令の送信とその応答は非同期で扱う必要があります。

ECHONET機器になる部分は、echonet-lite が受け持ってくれるので難しいことはありません。

今回であれば、自分自身はコントローラ (05ff01) になれば良いので、サンプルをそのまま使うことができます。

# 機器IDはなんでもよさそうですが、下手な機器を設定すると他のECHONET機器から発見されて状態取得系の命令が飛んでくるかもしれません。

やりとりは、命令を送信すると、それに対する応答が返ってくる。という単純なものです。(命令によっては、PUSH通知的な動きもありそうですが未確認)

落とし穴なのは、データ送信をした結果の応答は EL.initialize の第三引数のfunctionに返ってくるという点です。


データの送信

EL.sendOPC1 = function( ip, seoj, deoj, esv, epc, edt)

これを使えばよい。 大事なことなので強調しますが、応答はEL.initializeの第三引数のfunctionで受け取ります

引数
内容
設定値

ip
要求先IPアドレス
192.168.1.25 (EL.search()して見つけておく)

seoj
要求元機器ID
05ff01 (コントローラー) *1

deoj
要求先機器ID
028801 (低圧スマート電力メーター) *1

esv
命令コード
EL.GET (0x62: Get) *2

epc
引数1(プロパティを指定する)
0xE0 (積算電力量) *3 *4

edt
引数2(セット系命令の値)
空文字列(Get系命令であれば無視される為) *4

*1 機器ID

APPENDIX 機器オブジェクト詳細規定に規定されている。 (今回は、EL.search()して見つけた機器を片っ端から調べた)

https://echonet.jp/spec_object_rk/

2 命令コード

第二部 ECHONET Lite通信ミドルウェア仕様の 3-6ページに記載されている、 表 3-9 要求用ESVコード一覧に規定されている。

EL.
定数を見れば分かるかもしれない。

https://echonet.jp/spec_v113_lite/

*3 プロパティ (EPC)

APPENDIX 機器オブジェクト詳細規定に規定されている。 スマートメーターは 3.3.25 (3-290ページ)

https://echonet.jp/spec_object_rk/

*4 引数

規格上は、複数のプロパティを同時に要求できるが、 echonet-lite ではその機能は実装されていない。

# 送ろうと思えば送れそうな関数はあるが、一個ずつ要求しても良いだろうという考えだと思われる。


データの受信

データの受信は、 EL.initialize の第三引数の関数にて行われます。

第三引数の関数は function( rinfo, els, err ) となっており、それぞれ

引数
内容
設定値

rinfo
送信元情報
IPアドレス以外は使わないかも

els
受信情報
主に扱う部分

err
エラー情報
err != undefined ならエラーなので無視するなりなんなりする必要あり


rinfoサンプルデータ

{address: '10.1.0.1xx', family: 'IPv4', port: 35110, size: 18 }

こんな感じなので、IPアドレス以外はつかわなそうです。


elsサンプルデータ

elsサンプルデータは、下記のコマンドを実行した際の応答例である。

EL.sendOPC1('10.1.0.100', '05ff01', '028801', EL.GET, "e8", "");

{ EHD: '1081',

TID: '0000',
SEOJ: '028801',
DEOJ: '05ff01',
EDATA: '7201e804001e0096',
ESV: '72',
OPC: '01',
DETAIL: 'e804001e0096',
DETAILs: { e8: '001e0096' } }

引数
内容
備考

EHD
ECHONETバージョン
1081固定

TID
トランザクションID

echonet-liteを使う限りは 0000固定

SEOJ
送信元機器ID
要求のDEOJと等しいはず

DEOJ
送信先機器ID
自分自身の機器ID

EDATA
生データ
データ部を解釈しないでそのまま格納したもの

ESV
応答・通知用ESVコード
72は GETに対する応答を表す *1

OPC
プロパティ数
回答データ数。echonet-liteを使う限りは 01 固定

DETAIL
データ詳細
解釈前データ

DETAILs
データ詳細
解釈後データ。要求プロパティがキーになっている。この例だと e8を要求したのでe8だけが含まれる

*1 ESVコード

第二部 ECHONET Lite通信ミドルウェア仕様の 3-6ページに記載されている、 表 3-10 応答・通知用ESVコード一覧に規定されている。

https://echonet.jp/spec_v113_lite/


注意点


  • 自分が送信した命令も受信してしまうので、それは処理しないようにする必要がある。

    例えば、 rinfo が自分自身のIPアドレスである場合は無視するとか、SEOJが自分の機器IDだったら無視するとか


  • 数値は16進数なので注意。 parseInt(value, 16) で10進に変換可能。



プログラムの終了

echonet-liteのサンプルプログラムを動作させると、いつまでまっても終了しない。これは、ソケットの受信待ちがずっと行われている為である。

プログラムを終了する為には以下の用にすれば良い。

(EL.initializeが内部で使用する dgram.socket が返ってくるので、これをクローズすればイベントハンドラが終了できる)

var elsocket = EL.initialize( objList, function( rinfo, els, err ) {

(略)
    if (データ受信完了) {
global.complete_flag = true; // グローバル領域にフラグを立てる
}
}

setTimeout(function(sock) {
if (global.complete_flag) { // データ受信完了なら
sock.close(); // sock = elsocket
}
, 10000, elsocket); // 関数に EL.initializeの返り値を渡す

雑なプログラムですが、こんな感じでフラグを監視するようにすればOKです。


まとめ

出来たものは、下記URLで公開しています。

https://github.com/yakumo-saki/b-route-reader


蛇足

sendOPC1をpromiseでラップしたら使いやすさが一気に上がる気がする。