スマートメーターと通信する その3

さて、実際にやってみます。

 
■仕様
電力スマートメーターBルートサービスを利用して、屋外に設置されている電力会社のスマートメーターと通信し、現在の消費電力(瞬時電力計測値)と電流(瞬時電流計測値)を取得して出力するシステムとする。
得られたデータの出力先は、シリアルポート、液晶表示器、ESP内に動作させる簡易httpサーバー、IOT用クラウドサービス"ambient"とする。
 
■ハードウェア
お手軽にブレットボート上に配置した。主なハードウェアは3つ。
スマートメーターと通信するWi-SUN対応無線モジュールBP35A1(技適取得済)
WiFiモジュールESP-WROOM-02(ESP8266)(技適取得済)
PCとWiFiモジュールを接続するためのUSBシリアル変換モジュール
 
・BP35A1とESPは、ESP側は仮想シリアルポートライブラリSoftwareSerialを使ってシリアル接続(12,13番pinを割り当て。9600bpsに設定)
・ESPとPCは、ESPのハードウェアシリアルポートをUSBシリアル変換モジュール経由で接続(115200bpsに設定)
・ESPと液晶表示器は、I2Cで接続。(4,5番pinを割当)
・ESPはWifiで自宅LANに接続。
・電源電圧は3.3Vで設計(BP35A1もESPも3.3V動作なので)
 
■ソフトウェア
・ArduinoIDEで作成。
先人のブログにしっかりとしたソースが公開されているところがあり、多少手直ししてコンパイルしたものESP8266に書き込んで動かすとwdtエラーが出てうまくいかなかった。(loopにdelayを入れたが解決せず、深追いしていない)
とりあえず手打ちのコマンドを単にコード化しただけのようなもので試作。ソースなんぞ恥ずかしく公開できない。概要だけメモする。
 
(1)BP35A1の設定
あらかじめ、BP35A1の電文を、ROPTマンドで16ASCII 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帯特定小電力無線の通信時間の制限は超えていないはず。

f:id:t1000zawa:20170207132522j:image

1枚のブレッドボードにまとめてみる。

f:id:t1000zawa:20170207132707j:plain

続く。