■仕様
電力
スマートメーターBルートサービスを利用して、
屋外に設置されている電力会社のスマートメーターと通信し、現在の消費電力(瞬時電力計測値)と電流(瞬時電流計測値)を取得して出力するシステムとする。
得られたデータの出力先は、シリアルポート、液晶表示器、
ESP内に動作させる簡易httpサーバー、IOT用クラウドサービス"ambient"とする。
■ハードウェア
お手軽にブレットボート上に配置した。主なハードウェアは3つ。
・
PCとWiFiモジュールを接続するためのUSBシリアル変換モジュール
・BP35A1とESPは、ESP側は仮想シリアルポートライブラリSoftwareSerialを使ってシリアル接続(12,13番pinを割り当て。9600bpsに設定)
・ESPとPCは、ESPのハードウェアシリアルポートをUSBシリアル変換モジュール経由で接続(115200bpsに設定)
・ESPと液晶表示器は、I2Cで接続。(4,5番pinを割当)
・電源電圧は3.3Vで設計(BP35A1もESPも3.3V動作なので)
■ソフトウェア
・ArduinoIDEで作成。
先人のブログにしっかりとしたソースが公開されているところがあり、多少手直しして
コンパイルしたものESP8266に書き込んで動かすとwdtエラーが出てうまくいかなかった。(loopにdelayを入れたが解決せず、深追いしていない)
とりあえず手打ちのコマンドを単にコード化しただけのようなもので試作。ソースなんぞ恥ずかしく公開できない。概要だけメモする。
(1)BP35A1の設定
あらかじめ、BP35A1の電文を、
ROPTコ
マンドで16進ASCII dumpモードにしていることが前提。teratermから手動でいろいろコマンドを叩いて慣れたこともあり、相手の出方もだいたいわかったので、相手の言うことは無視してひたすら一方的に走り、意図した応答がなければしばらく経ってからリトライする、という乱暴なコードで試してみた。ESPとはSoftwareSerialで通信するようにしたが、ハードウェアシリアルの方が安定しているというレポートが多く、確かに文字化けが時々発生するようだが、入れ替えが面倒なのでそのまま。
#include <SoftwareSerial.h>
SoftwareSerial sSerial(12, 13);
で開いたシリアルポートを使って、無線モジュールに必要なコマンドを発行する。SKSCANの後のレスポンスは相手の応答が時間がかかることが多いので、
delayを多く取っている。SKSREGのパラメータ(920MHz帯のチャンネル番号とPAN ID)は、SKSCANの結果得た値を固定値で入れている。周囲にスマートメーターが増えてきたら、変更が必要になるかもしれない。SKJOINのパラメータ(スマートメーターのIPv6アドレス)もあらかじめSKLL64コマンドで得ておいた固定値を入れている。
void setup_BP35A1() {
sSerial.println("SKVER");
delay(500);
sSerial.println("SKTERM");//念のため
delay(500);
sSerial.println("SKSETRBID your ID");
delay(500);
sSerial.println("SKSETPWD C your password);
delay(500);
sSerial.println("SKSCAN 2 FFFFFFFF 6");
delay(15000);
sSerial.println("SKSREG S2 33");
delay(5000);
sSerial.println("SKSREG S3 001D");
delay(5000);
sSerial.println("SKJOIN FE80:0000:0000:0000:xxxx:xxxx:xxxx:xxxx");
delay(10000);
}
(実際はハードウェアシリアルポートにコマンド発行の進捗を出力してるがここでは省略)
SKJOINのあと無線モジュールからEVENT25(PANA接続OK)が返ってくればOKだが、頑としてEVENT24(PANA接続NG)しか返してくれない状態が続く場合があり、その際はSKSREGから戻って再度SKJOINするようにしている。
ENENT25を返してくれることを前提に、次に進む。
(2)ECHONETLiteコマンドの発行
PANA接続がOKになれば、暗号化された
UDPパケットでの通信に入る。SKSENDTOコマンドで 相手の
IPv6アドレスに対して、即時電力値と電流値をくれ、
と言うだけなのだが、いろいろ前口上を言わなくてはならない。(値の意味の解説はここでは省略)。ECHONETLiteコマンド部分だけバイナリデータで送る必要があるので16進ASCIIで送れる部分は普通に送った後、バイトデータを送出、最後に改行で締める。
void send_ECHONETLiteComm() {
int ECHONETLiteComm[17] = {0x10, 0x81, 0x00, 0x01, 0x05, 0xFF, 0x01, 0x02, 0x88, 0x01, 0x62, 0x02, 0xE7, 0x00, 0xE8, 0x00}; //コマンドバイト列
sSerial.print("SKSENDTO 1 FE80:0000:0000:0000:xxxx:xxxx:xxxx:xxxx 0E1A 1 0010 "); //UDPハンドラ、宛先、宛先ポート番号(0x0E1A)、暗号化フラグ、送信データ長の送信(16byte) 、スペース(0x20)
int d = 0; for (d = 0; d <= 15; d++) { //コマンドの送信
int senddata1 = ECHONETLiteComm[d];
sSerial.write(senddata1);
}
sSerial.println();
} //改行送信して終わり
(3)電文の受信
ECOHONET Liteコマンドを送り終えたら、仮想シリアルポートを監視して、データが来たら変数配列に格納。改行コードが来たら、改行コードの前の所定の位置が、瞬時電力取得値を示す0xE704かつ瞬時電流取得値を示す0xE804であるかチェックし、そうであるならば、それぞれの値(16進ASCIIテキスト)を取得し10進整数に変換するという手抜きなもの。各電文のヘッダは見ていない。
スマートメーターは30分おきに積算電力値を送り付けてきたリ、900秒ごとにPAN認証をし直したり、ビーコンを撒いたりしてくれるが、それらの電文は無視している。また、コマンドを送出後相手がダンマリになった場合、所定の秒数経過後、SKSREG、SKJOINからやり直すようにしている。
(4)結果の出力
瞬時電力測定値と、瞬時電流測定値(うちは単相3線式なのでR相、T相それぞれ電流値が得られる)が得られたら、簡易なhtmlを生成し、ESP8266webserverで他のPCのブラウザから読めるようし、さらに値をambientに送信し、液晶表示器にも表示されるようにした。現在時刻はNTPを使って得ている。
スマートメーターとの通信頻度はとりあえず30秒。920MHz帯特定小電力無線の通信時間の制限は超えていないはず。
1枚のブレッドボードにまとめてみる。
続く。