この記事について
ロームBP35C0-T01とESP-WROOM-32を使って、スマートメーターから取得した電力量を可視化します。
スマートメーターから取得した電力消費量を可視化する (1)機器の準備の続き、今回は電力消費量を取得します。
スマートメーターから情報を取得するための実装
前回の記事で、ESP-WROOM-32(以下ESP32) と BP35C0-T1 を接続しましたので、今回は実際にスマートメーターからのデータを取得します。
と言いつつ、スマートメーターからの情報を取得することなどは二番煎じ三番煎じどころか256番煎じくらいな感じなので、先人の知恵を借ります。
参考情報
以下ページの内容を参考にさせてもらいました。感謝。
その他、目を通しておいたほうが良いサイトや資料は、文末に書いておきます。
BP35C0-T01 とのやり取りについて
ざっくり以下の順番でBP35C0とコマンドをやり取りします。
以下、 >>
の行がESP32からのデータ送信、<<
の行がBP35C0からの応答です。
なお、詳細はBP35C0のコマンドリファレンスを確認してください。
事前準備
BP35C0 ファームウェアのバージョン確認 兼 コマンドのやり取りができることを確認する
>> SKVER
<< EVER 1.5.2
<< OK
SKVER
を実行して、バージョン表示とOK
が返ってくればOK
コマンドのエコーバックを無効に
やらなくてもいいと思うけど、エコーバック無効にしたほうがプログラム的に都合が良さそうなので、とりあえず。
>> SKSREG SFE 0
<< OK
SKSREG
コマンドでSFE
レジスタに0
をセットする。OK
が返ってくればOK
応答を16進ASCII文字で返すように
>> WOPT 01
<< OK
WOPT
コマンドで引数01
(ASCII文字列の意味)を渡す。OK
が返ってくればOK
BルートサービスのIDを設定する
>> SKSETRBID XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<< OK
SKSETRBID
コマンドで、電力会社から入手したBルートのID(32桁の16進)をセットします。XXXX
の部分は自分のIDに置き換えてください。OK
が返ってくればOK
Bルートサービスのパスワードを設定する
>> SKSETPWD c XXXXXXXXXXXX
<< OK
SKSETPWD
コマンドで、電力会社から入手したBルートのパスワードをセットします。SKSETPWD
の後ろのc
はパスワードの文字数の16進数です。16進でc
なのでこの例ではパスワードは12文字、という意味です。
OK
が返ってくればOKです。
###スマートメーターの存在をスキャンする
>> SKSCAN 2 FFFFFFFF 6 0
<< OK
<< EVENT 20 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX 0
<< EPANDESC
<< Channel:00
<< Channel Page:11
<< Pan ID:2222
<< Addr:3333333333333333
<< LQI:44
<< Side:55
<< PairID:66666666
<< EVENT 22 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX 0
SKSCAN
コマンドを実行すると、周辺に存在する機器のスキャンを行います。引数の2
は「アクティブスキャンを行う」の意味、FFFFFFFF
は対象機器をマスクしたい場合に指定(FFFFFFFF
だと全機器を対象に)、6
はスキャンの時間、最後の0
は固定値です。
スキャンに対して周辺機器が応答すると、応答した機器の情報が出力されます。
コマンド応答に含まれる Channnel
Pan ID
Addr
の値をメモしておきます。
なお、スマートメーターと通信できなかった場合は機器情報、つまりEVENT 20
~PairID:XXXXXXXX
までの行が返ってきません。
スマートメーター機器の登録
>> SKSREG S2 00
<< OK
>> SKSREG S3 2222
<< OK
>> SKLL64 3333333333333333
<< XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
使用するスマートメーターの情報、つまり上記のスキャンで取得できた値をセットします。
SKSREG S2
で引数にChannel
の値を、SKSREG S3
で引数にPan ID
の値を、SKLL64
の引数にAddr
の値を、それぞれ渡します。
SKLL64
のコマンド応答の文字列(スマートメーターのIPv6値)をメモしておきます。
長かったですが、ここまでが事前準備です。
データ取得開始
>> SKJOIN XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
<< OK
SKJOIN
コマンドに、上記SKLL64
実行時の戻り値を引数に渡します。
これを実行すると、以後30分ごとにスマートメーターからの消費電力情報を受信するようになります。
以下のような値が、だいたい毎時0分と30分くらいに受信されます。
ERXUDP XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY 0E1A 0E1A 0123456789ABCDEF 1 0 0026 1081000102880105FF017302EA0B07E30504161E0000005B93EB0B07E30504161E000000000C
ここで重要なのは、スペースで区切られたいくつかの値のうち、一番最後の部分の値、上記例でいうと1081000102880105FF017302EA0B07E30504161E0000005B93EB0B07E30504161E000000000C
の部分です。
No | 開始桁 | 文字数 | 上記例での実際の値 | 値の意味 |
---|---|---|---|---|
1 | 8 | 6 | 028801 | 028801 だと、スマートメーターからの応答 |
2 | 22 | 2 | 02 | 含まれる値の数 |
3 | 24 | 2 | EA |
EA だと「正方向の定時積算電力量計測値」 EB だと「逆方向の定時積算電力量計測値」 |
4 | 28 | 4 | 07E3 | データ計測日の「年」の16進(0x07e3 = 2019) |
5 | 32 | 2 | 05 | データ計測日の「月」の16進(0x05 = 5) |
6 | 34 | 2 | 04 | データ計測日の「日」の16進(0x04 = 4) |
7 | 36 | 2 | 16 | データ計測日の「時」の16進(0x16 = 22) |
8 | 38 | 2 | 1E | データ計測日の「分」の16進(0x1e = 30) |
9 | 40 | 2 | 00 | データ計測日の「秒」の16進(0x00 = 0) |
10 | 42 | 8 | 00005B93 | 電力量(kWh*10)の16進(0x00005B93 = 2344.3kWh) |
11 | 50以降 | EB0B07E30504161E000000000C | 上記No.2「含まれる値の数」が2以上の場合は、No.3~10までを繰り返す |
ということで、このデータの場合、以下のような値の意味になります。
- 2019/05/04/ 22:30:00 の正方向の定時積算電力量計測値が2344.3kWh
- 2019/05/04/ 22:30:00 の逆方向の定時積算電力量計測値が1.2kWh
ちなみに、他にも瞬間電力計測値なども取得できますが、とりあえず今回は省略します。
これらをESP32に実装してみる
前置きが長くなりましたが、実装してみます。
と、これらを1から実装するのは面倒でしょうから、ESP32向けにライブラリを作っておきました。
以下から取得してください。
https://github.com/nara256/Bp35c0_broute
###ライブラリのインポート方法
- 上記URLのページから、緑色の
Clone or download
のボタンを押し、Download ZIP
を選択し、zipファイルをダウンロードします。 - Arduino IDEから、メニューの スケッチ→ライブラリをインクルード→ZIP形式のライブラリをインストール を選択し、1.でダウンロードしたファイルを選択します。
###実装してみる
Arduino IDEから、メニューの ファイル→スケッチ例→Bp35c0_broute→simple_get_value を開きます。
#define
の行のID
/PASS
の値は、自分のBルートのID/PASSに書き換えてから、ビルドしてESP32に書き込みます。
#include "Bp35c0-broute.h"
#define ID "YOUR_B_ROUTE_ID_HERE"
#define PASS "YOUR_B_ROUTE_PASSWORD_HERE"
#define LED 2
HardwareSerial uart(2);
Bp35c0_broute b(uart);
void blink(int sec)
{
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
delay(sec);
digitalWrite(LED, LOW);
delay(sec);
}
void error()
{
pinMode(LED, OUTPUT);
while (true)
blink(500);
}
void initLed()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
}
void setup()
{
Serial.begin(115200);
uart.begin(115200);
//b.setDebugSerial(Serial);
initLed();
if (!b.available())
error();
if (!b.open(ID, PASS))
error();
}
void loop()
{
blink(100);
char u[32] = {'\0'}, d[32] = {'\0'};
float uu, dd;
b.waitForRecieve(d, &dd, u, &uu);
Serial.println(u"正方向:" + String(d) + " : " + String(dd));
Serial.println(u"逆方向:" + String(u) + " : " + String(uu));
}
だいたい、毎時0分ころ・30分頃に定時積算電力量計測値がスマートメーターから送られてきますので、それをSerialに出力します。
####実行結果
正方向:20190504223000 : 2344.30
逆方向:20190504223000 : 1.20
正方向:20190504230000 : 2344.50
逆方向:20190504230000 : 1.20
..(以下、30分毎に表示)
###サンプルスケッチの説明
ポイントを絞ってざっくり説明していきます。
ライブラリをインクルードします
#include "Bp35c0-broute.h"
BP35C0-T01の接続先の設定
HardwareSerial uart(2);
Bp35c0_broute b(uart);
BP35C0の接続先(UART2)を引数に、Bp35c0_broute
のインスタンスをグローバル変数として生成します。
BP35C0-T01の初期設定
setup()
関数内で、BP35C0-T01を初期化します。
void setup()
{
uart.begin(115200);
if (!b.available())
error();
if (!b.open(ID, PASS))
error();
}
UART2を115200bpsでオープンします。
b.available()
== TRUE
だと、BP35C0-T01と正常に通信できる状態です。
b.open(ID, PASS)
を実行すると、引数で渡したBルートのID/PASSでBP35C0-T01を初期化します。open()
関数の戻りがFALSE
だった場合は、スマートメーターから応答がなかったなど、何らかの初期化失敗が発生したことを示します。
####定時積算電力量計測値を取得する
loop()
関数内で、電力消費量を取得します。
void loop()
{
char u[32] = {'\0'}, d[32] = {'\0'};
float uu, dd;
b.waitForRecieve(d, &dd, u, &uu);
Serial.println(u"正方向:" + String(d) + " : " + String(dd));
Serial.println(u"逆方向:" + String(u) + " : " + String(uu));
}
b.waitForRecieve()
関数を呼び出すと、定時積算電力量計測値をスマートメーターから受信するまで応答を待ちます。つまりこの関数を実行すると毎時0分・30分になるまでこの関数から返ってきません。
引数に渡した変数に、計測日時の文字列(YYYYMMDDHHMMSS)と電力量がセットされます。
ここで取得できる電力量は積算値です。なので、数値は右肩上がりで増えていきます。
なお、「正方向」とは消費した電力量、「逆方向」はたぶん自宅内で発電した電力だと思います。(私のうちはソーラー付きではないので「逆方向」の値は値が増えません。)
##まとめ & 次回予告
とりあえず、今回は画面(Serial)にスマートメーターから取得した電力量を表示してみました。
次回はIoT的に可視化してみます。
##参考資料
- BP35C0
- BP35C0-T01 仕様書
- 「ROHM Sub-GHzシリーズ」サポートページ
- BP35C0 コマンドリファレンス ※要認証 認証方法はスターターガイドに書かれています。
- ECHONET Lite規格書