とりあえずやってみたレベルですが、Bルートサービスが利用開始できたので瞬間電力を読むところまでやってみました。

  • Bルートサービスの申込
  • Wi-SUN モジュールについて
  • ECHONET Lite について

あたりがポイントです。

Bルートサービス申込から

混んでることはわかっていたのであまり期待せずに申し込んでいます。スマートメータに変更していない状態で申し込んでおり、途中でスマートメータ切替工事が入るパターンです。

関東在住ですので、東京電力パワーグリッドの管轄です。

  1. 6月24日に申込
  2. 6月27日に「お客さま情報の照合を完了し、お申込みを受け付けましたので、お知らせいたします」メールがくる
  3. 7月上旬ぐらいに電気メータ交換について東京電力パワーグリッドから「7月15日〜8月10日の間で工事を実施させて頂きます」というお知らせがポスト投函(郵送ではない)される。「停電いたしません」が「ご在宅の場合で停電の了解がいただける場合は停電工事に変更させていただくことがあります」と書いてあった。立ち会いの必要なし。
  4. 7月27日にメーターの「取替完了のお知らせ」がポスト投函されており、メータが替わっていた。工事業者は関電工
  5. 8月3日にメールで『「電力メーター情報発信サービス(Bルートサービス)」パスワードのお知らせ』がくる
  6. 8月4日に郵便で『「電力メーター情報発信サービス(Bルートサービス)」認証IDお知らせ』がくる

できれば工事を見学をしたかったけど、帰宅したら替わってしまっていた。

備考:申込時に必要な供給地点特定番号について

ウェブの電気家計簿を使っている場合、ログインして以下のURLにアクセスするとわかります。

https://www.kakeibo.tepco.co.jp/dk/wmf/meterInfoReference/

電気家計簿を使ってない場合、検針票に書いてあると思います。

通信モジュール

Wi-SUN モジュールは今のところ個人でも手に入るのはロームのものしかなさそう。ロームが汎用Wi-SUNモジュールのインターネット販売を開始 | ローム株式会社 - ROHM Semiconductor に書いてある通り。技適付きなので心配いらない。

RS Online で BP35A1, BP35A7, BP35A7 - accessories を買おうとしたが入手困難といわれてダメで、BP35A7 - accessories だけ送られてきて辛い。チップワンストップ だと在庫があった…… 個人とは取引しないと書いてあるが無視して個人事業主ということで登録して買った。

BP35A7 は既に廃盤?で、BP35A7A というのがある。BP35A1はそのまま。よくわからないがまとめて入手する方法がすくない。

マザーボードとして BP359C というのがあるが、これはUSBシリアル変換とかがついてるだけなので、あまり必要なさそう。

Amazon でもなぜか取り扱いがあって (マーケットプレイスではなく Amazon.co.jp 販売)

Amazon で買う場合 BP35A7 - accessories は高価すぎるので買わずに別のところで買ったほうがよさそう。BP35A7もなぜか高い。が、在庫探しが面倒なら買ってもいいのではないか…

BP35A1 についているコネクタに対応するコネクタは 20P3.0-JMCS-G-TF という JST のコネクタ。Digikey で 120円ぐらいで売っているので、Digikey を利用する際に買っておけばBP35A7相当品を自作できるが、基板設計とか考えるとやはり面倒なのとそこまで高価ではないので素直に買ったほうが良いでしょう。

どうも結構今だと高いので辛い感じがしますがそのうち安いプロダクトがでると信じたい。

モジュールの使いかた

最低限使うのに必要な配線は

  • VCC
  • GND
  • RXD
  • TXD

だけです。電源電圧は3.3Vなので注意。

UART 経由でコマンドを打てば良いので、モジュールとUSB-UART変換さえあればPCで簡単に試せます。

モジュールの仕様書などは「ROHM Sub-GHzシリーズ」サポートページというところから辿れる。

サンプルも用意されているし、コマンドリファレンスも親切に書いてある。

備考: Wi-SUN モジュールについて

Wi-SUN 自体は国際規格化されているけど、日本のスマートメータ用に産まれたというそもそもの経緯があるので、今のところ日本以外で需要がない。なのでモジュール自体が少ない。

Wi-SUN の認証を通っているのはウェブから一覧でみれる。ECHONET Route B から辿ればよさそう。ロームの以外にもあるはあるけど、手に入らない。

スマートメータからのデータ取得

アプリケーションレイヤーでのプロトコルは ECHONET Lite というものです。Wi-SUN の OSI参照モデルでの関係はWi-SUN対応通信制御ソフトウェア がわかりやすいです。

BP35A1 モジュールでは物理層からトランスポート層(TCP/UDP)及びセッション層(PANA : Protocol for Carrying Authentication for Network Access)までのサポートがありますので、実際の必要なのはアプリケーション層の実装のみです。

ECHONET Lite

仕様書は普通に公開されていて、しかも日本語です。とりあえず必要なのは「第2部 ECHONET Lite 通信ミドルウェア仕様」で、具体的には ECHONET Lite のフレーム構造を理解していればとりあえず通信できます。

ECHONET Lite は概念的には BLE の GATT に似たような仕組みです。「それぞれの機器のあるプロパティを読み書きする」ことができます。

サンプルコードと実行結果

全体的な処理の流れを Ruby で書いてみました。

このコード自体は例外を考慮しておらず全く応用性はありませんが、プロトコルの理解のためにはある程度有用だと思います。ECHONET Lite 部分に細かくコメントをつけています。

ハマりポイント

  • 接続後に「インスタンスリスト通知」というのがこちらから要求しなくても送られてきました
    • ちゃんと受信フレームをパースしないといけないですがこのコードではやってません
require 'serialport'

begin
	@port = SerialPort.new(
		"/dev/tty.usbserial-A500YQPG",
		115200,
		8,
		1,
		0
	)
rescue Errno::EBUSY
	sleep 1
	retry
end

puts "init"

def @port.send(line)
	$stdout.puts ">> #{line}"
	self.write(line + "\r\n")
end

def @port.wait(val)
	while
		line = self.gets.chomp
		$stdout.puts "<< #{line}"
		if val === line
			return Regexp.last_match
		end
	end
end


@port.set_encoding(Encoding::BINARY)

@port.send "SKVER\r\n"
@port.wait "OK"

# エコーバックをオフに
@port.send "SKSREG SFE 0\r\n"
@port.wait "OK"

# スペース区切りで通知されるが、実際は削除する
ROUTE_B_ID = "0000 0099 0210 0000 0000 0000 00XX XXXX".gsub(/ /, '')
ROUTE_B_PASS = "XXXX  XXXX  XXXX".gsub(/ /, '')

@port.send "SKSETPWD C #{ROUTE_B_PASS}"
@port.wait 'OK'

@port.send "SKSETRBID #{ROUTE_B_ID}"
@port.wait 'OK'

info = {}
@port.send 'SKSCAN 2 FFFFFFFF 6'
info[:sender] = @port.wait(/^EVENT 20 (?<sender>.+)/)[1]
@port.wait(/^EPANDESC/)
info[:channel]      = @port.wait(/^  Channel:(?<channel>.+)/)[1]
info[:channel_page] = @port.wait(/^  Channel Page:(?<channel_page>.+)/)[1]
info[:pan_id]       = @port.wait(/^  Pan ID:(?<pan_id>.+)/)[1]
# MACアドレス
info[:addr]         = @port.wait(/^  Addr:(?<addr>.+)/)[1]
info[:lqi]          = @port.wait(/^  LQI:(?<lqi>.+)/)[1]
info[:pair_id]      = @port.wait(/^  PairID:(?<pair_id>.+)/)[1]
p info
#<<   Channel:2F
#<<   Channel Page:09
#<<   Pan ID:A0E6
#<<   Addr:00XXXXXXXXXXXXXX
#<<   LQI:7D
#<<   PairID:00XXXXXX
@port.wait(/^EVENT 22/)

# macアドレスをipv6 アドレスへ変換
@port.send "SKLL64 #{info[:addr]}"
info[:ipv6_addr] = @port.wait(/[0-9A-F:]+/)

# channel
@port.send "SKSREG S2 #{info[:channel]}"
@port.wait "OK"

# pan id
@port.send "SKSREG S3 #{info[:pan_id]}"
@port.wait "OK"

@port.send "SKJOIN #{info[:ipv6_addr]}"
# 0x25:PANA による接続が完了した
@port.wait(/^EVENT 25/)

@tid = 0
while true

#    (1)Layer4 で UDP(User Datagram Protocol)、Layer3 で IP(Internet Protocol)、
#    を使用する場合
#    各 ECHONET Lite ノードは、それぞれ IP アドレスを持つ。IP アドレスの範囲、
#    取得方法は規定しない。1つの ECHONET Lite フレームは、1つの UDP パケッ
#    トにて転送する。UDP パケットにおける送信先 PORT 番号は、要求・応答・通知
#    等の種別に関わらず、常に 3610 とする。

    handle = 1
    port_num = 3610
    sec = 1 # 暗号化有効・有効でなければ送信しない

    # 上記の通り data は ECHONET Lite フレームとなる
    # ref. https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/ECHONET_lite_V1_12_jp/ECHONET-Lite_Ver.1.12_02.pdf
    ### ref. https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/Release/Release_G_revised/Appendix_G_revised.pdf
    @tid += 1
    data = [
        # EHD1 = ECHONET Lite 1 byte
        0b00010000,
        # EHD2 = 既定形式 1 byte
        0x81,
        # TID - トランザクションID 2 bytes
        @tid,

        # EDATA
        
        ## SEOJ - 送信元ECHONET Liteオブジェクト指定 3 bytes
        ### Class Group Code - 管理・操作関���機器クラスグループ
        0x05,
        ### Class Code - コントローラ
        0xFF,
        ### Instance Code
        0x01,

        ## DEOJ - 相手先ECHONET Liteオブジェクト指定 3 bytes
        ### Class Group Code - 住宅・設備関連機器クラスグループ
        0x02,
        ### Class Code - 低圧スマート電力量メータ
        0x88,
        ### Instance Code
        0x01,

        ## ESV - ECHONET Lite サービス 1 byte
        ## プロパティ値読み出し要求
        0x62,

        ## OPC - 処理プロパティ数
        0x01,

        ### EPC - プロパティ - 瞬時電力計測値
        #### 電力実効値の瞬時値を 1W 単位で示す。(結果は 4 bytes singed long)
        0xe7,
        ### PDC - EDTのバイト数
        0x00,
        ### EDT - プロパティデータ
        # なし
    ].pack("CCn CCC CCC C C CC".gsub(" ", ""))

    p data

    @port.send "SKSENDTO %s %s %04X %s %04X %s" % [
        handle,
        info[:ipv6_addr],
        port_num,
        sec,
        data.length,
        data
    ]

    # TODO use datalen to read
    res = @port.wait(/^ERXUDP (?<sender>\S+) (?<dest>\S+) (?<rport>\S+) (?<lport>\S+) (?<senderlla>\S+) (?<secured>\S+) (?<datalen>\S+) (?<data>\S+)/)
    p res
    # まず接続後にインスタンスリスト通知 がくる
    # \x10\x81\x00\x00
    # \x0E\xF0\x01 ノードプロファイル
    # \x0E\xF0\x01 ノードプロファイル
    # \x73 プロパティ値通知
    # \x01 1つ 
    # \xD5
    # \x04 4バイト
    # \x01\x02\x88\x01
    #
    # "\x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01"
    p res[:data][-4..-1].unpack("N")
    sleep 3
end

@port.send "SKTERM"
@port.wait "ENT 27"

実行すると以下のようになります。一部アドレスなどは念のため置き換えています。最後のほうに出てくる[1097]が瞬間消費電力です。

init
>> SKVER
<< SKVER
<< EVER 1.2.10
<< OK
>> SKSREG SFE 0
<< SKSREG SFE 0
<< OK
>> SKSETPWD C XXXXXXXXXXXX
<< OK
>> SKSETRBID 000000000000000000000000000000XX
<< OK
>> SKSCAN 2 FFFFFFFF 6
<< OK
<< EVENT 20 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX
<< EPANDESC
<<   Channel:2F
<<   Channel Page:09
<<   Pan ID:A0E6
<<   Addr:001C64000357XXXX
<<   LQI:84
<<   PairID:00AXXXXX
{:sender=>"FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX", :channel=>"2F", :channel_page=>"09", :pan_id=>"A0E6", :addr=>"001C64000357XXXX", :lqi=>"84", :pair_id=>"00AXXXXX"}
<< EVENT 22 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX
>> SKLL64 001C64000357XXXX
<< FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
>> SKSREG S2 2F
<< OK
>> SKSREG S3 A0E6
<< OK
>> SKJOIN FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
<< OK
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 02
<< EVENT 02 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0028 (����O�y
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0068 h����O�z$�r%^a�;H)��#L�8�8/�4+�u\-����&ѨSM00000099021000000000000000AXXXXX
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0054 T����O�{;�;/��4+�u\-����&Ѩ��?s�����r��2���0��D�R��
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0058 X����O�|�  Q�{��(F���.�[�<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< EVENT 25 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY


"\x10\x81\x00\x01\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< OK
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 001C64000357XXXX 1 0012 ���s��
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FF02:0000:0000:0000:0000:0000:0000:0001" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01">
[16943105]
"\x10\x81\x00\x02\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 ���r�Z
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x01\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04Z" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FE80:0000:0000:0000:021D:1290:0003:A4F1" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x01\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04Z">
[1114]
"\x10\x81\x00\x03\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< OK
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 ���r�I
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x02\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04I" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FE80:0000:0000:0000:021D:1290:0003:A4F1" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x02\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04I">
[1097]

実際はイベントや UDP の処理を適切に書く必要があります。ちゃんとやらないとダメなので、適切なライブラリがあると嬉しそうです。

  1. トップ
  2. tech
  3. スマートメータのBルートサービスで Wi-SUN モジュールを使って瞬間消費電力を読み出す
▲ この日のエントリ