RaspberryPi
RaspberryPiでスマート電力メータを読む
 自宅の消費電力量をリアルタイムに計測するため、スマートメータと通信するスステムをRaspberryPiでつくりました。以前、分電盤の電線からもれる磁力線を電流トランス形のセンサーにより補足する方式で電力計を作りましたが、少々危ない工事をしなければならず、今回、安全なシステムを作りました。これは電力会社が設置したスマートメータと通信し、リアルタイムに電力をよみとる方法で、HEMS(Home Energy Management System)コントローラに相当するものです。(2021/04/10公開)

スマートメータのBルート
 
    
スマートメータ(例)
    

 「電力小売」が全面自由化され、私たち一般家庭でも、電気をどこから購入するのかを選べるようになりました。これを実現するために、遠隔検針が必要となり、電気メーターに通信機能を搭載したものがスマートメーターです。当地区でも昨年メータの交換工事が行われ、紙の検針票は廃止され、Webで電力料金確認となりました。

  

 上の図には、スマートメーターを中心に、A、B、Cの3つの矢印が記載されています。この矢印はスマートメーターの測定値データの経路を表しており、それぞれスマートメーターの「Aルート」「Bルート」「Cルート」と呼ばれています。電力会社の検針はAルートを用います。一方私たち電気の消費者もスマートメーターから直接データを取得できるのが特長で、それがBルートです。今回Bルートを用いて電力量をよみとるものです。
 Bルートの無線通信方式は920MHz 帯のWi-SUN (Wireless Smart Utility Network IEEE802.15.4 ARIB STD-T108)、を用います。障害物があっても電波が届きやすいので、データ収集機器を屋内に設置しても、屋外にあるメーターと通信できるといいます。
 上位レイヤの通信プロトコルはECHONET コンソーシアムで規格化された、ECHONET Lite という仕様に従います 。パケットのレイヤは、IPv6、UDPを用います。

 また、電気の消費データはプライバシーに関わるデリケートな情報なので、不特定多数に向けて晒されてはいけません。このため、メーター 1 台ごとに異なる ID とパスワードが設定されています。この認証やセッション管理を行うために、IETFのPANA (Protocol for Carrying Authentication for Network Access RFC 5191) というプロトコルが使用されています。
   
PANA:Protocol for Carrying Authentication for Network Access
6LoWPAN: IPv6 over Low-Power Wireless Personal Area Networks

Bルートサービスの申込み
 初めにやることはBルートサービスの申込です。申込先は東京の場合は電力会社を乗り換えていても、送配電を担当している東京電力パワーグリッド株式会社です。電力メーター情報発信サービス(Bルートサービス)というページから申し込みます。スマートメーターが設置されていない場合でも申し込めます。費用は掛かりません。申し込みのために「供給地点番号」が必要です。「取り換え完了のお知らせ」あるいは紙の検針票の左上にある22桁の数字です。紙の検針票をなくしてしまった場合は電話で問い合わせる必要があります。
 申し込みが完了すると次のようなメールがきます。その後、認証IDを郵送にて、パスワードをメールにて送られてきます。

 このたびは、電力メーター情報発信サービス(Bルートサービス)利用開始のお申込みをいただき、誠にありがとうございます。
 お客さま情報の照合を完了し、お申込みを受け付けましたので、お知らせいたします。

■ 今後の流れについて
<すでにスマートメーターが設置されているお客さま>
@弊社にてスマートメーターへ利用開始の設定を遠隔にて実施いたします。
 通信環境が悪く遠隔での設定が困難な場合は、事前にご連絡のうえお客さまのお宅にお伺いし作業をさせて頂きます。
A認証IDを郵送にて、パスワードをメールにて、それぞれ本日より1〜2週間程度でお知らせいたします。
 なお、遠隔での設定が困難な場合等の事情により、遅延することもございますので、何卒ご理解頂きますようお願い申し上げます。

<スマートメーターが設置されていないお客さま>
@弊社にてスマートメーターの設置工事をいたします。作業日を事前にお客さまへお知らせいたします。
Aスマートメーターへ利用開始の設定を遠隔にて実施いたします。
 通信環境が悪く遠隔での設定が困難な場合は、事前にご連絡のうえ、お客さまのお宅にお伺いし作業をさせて頂きます。
B認証IDを郵送にて、パスワードをメールにて、それぞれ本日より2〜3週間程度でお知らせいたします。
 なお、スマートメーター設置工事の日程調整や、遠隔での設定が困難な場合等の事情により、遅延することもございますので、何卒ご理解頂きますようお願い申し上げます。

東京電力パワーグリッド株式会社 コンタクトセンター

ROHM製 BP35A1
 Bルートを使ってスマートメーターに接続するためには、セキュリティ及び相互接続性の担保を目的に第三者認証を取得したHEMS機器が必要となります。HEMS機器を通じて、瞬時電力測定値(W)、瞬時電流測定値(A)、積算電力量測定値(kWh)などのデータを取得することができます。
 ROHM社が2014年4月から販売しているBP35A1というモジュールを用いることでBルートに対応した機器を容易に作ることができます。モジュールはアンテナを内蔵し、Wi-SUNに対応可能な無線機と、HEMSに適したファームウェアが搭載されています。国内電波法認証、ECHONET Profile認証取得済みです。
 
BP35A1 ワイヤレスLANモジュール 802.15.4g/e
内蔵アンテナ
受信感度: -103 dBm
UARTインターフェイス
Wi-SUN対応 - Wi-SUNファームウェア内蔵
ラピスセミコンダクタ(LAPIS Semiconductor)製ML7396B無線通信LSI搭載
MACアドレス書き込み済み
国内電波法認証取得済み
ECHONET Profile認証取得済み
技術資料
BP35A1 ハードウェア仕様書
BP35A1 スタートアップマニュアル
BP35A1 コマンドリファレンス (ダウンロードにIDとパスワード必要 BルートのID・パスワードとは別 下記参照)

BP35A1はコネクタ実装タイプで0.4mmピッチ20pinの特殊なコネクタで接続するようにできていますので、2.54mm ピッチ変換アダプターボードBP35A7Aが必要です。またネジ、スペーサなどのアクセサリも購入します。これら部品は、Chip1のサイトで、1個から対応してくれます。
BP35A1  7,490円
BP35A7A 750円
BP35A7-accessories  190円

BP35A7A BP35A7-accessories

このほか、Raspberry Pi Zero WH 、 RaspberryPi Zero用のユニバーサル基板 、 ピンソケット (メス) 2×20、  USB電源アダプター 5V/2A 、マイクロSDカードを準備します。

組み立て
 BP35A1を変換基板BP35A7AにアクセサリのM2ネジとスペーサで取り付けます。アンテナ部は配線禁止領域で、ここと重なる領域にはGND ベタや配線を引いてはいけません。BP35A7Aにはピンヘッダを2個半田付けし、それをさらにRaspberryPi Zero用のユニバーサル基板に半田付けします。ユニバーサル基板にはピンソケットを半田付けし、BP35A7Aの端子と下の表のように4本の配線をします。
 これらをRaspberry Pi Zero WHのGPIOにさしこみます。
Raspberry Pi Zero WH         BP35A7A
 8p GPIO14 TXD CN2 4p RXD
10p GPIO15 RXD CN2 5p TXD
3.3V CN2 3.3V
GND CN2 GND

      
RaspberryPi Zero用のユニバーサル基板の上にBP35A7Aを
ピンヘッダで半田付け。その上にBP35A1
Raspberry Pi Zero WHに取り付け
これだけでHEMSコントローラとして動く



Raspberry Piの準備
 RaspberryPi ZeroのSDカードにはRaspberry Pi OS Lite ( Raspbian GNU/Linux 10 buster)をインストールします。まだBP35A1/BP35A7Aのユニバーサル基板は取り付けません。
(1) 準備
ディスプレイ、キーボードを接続し、5V電源を加えます。miniHDMIをHDMIに変換するケーブル、microUSB を USB Type-Aのキーボードにつなぐアダプタも必要です。

$ sudo raspi-config 
により、Password 、Hostnameを設定します。 SSHが使えるようにします。

(2) WiFi
RaspberryPi ZeroはWiFiが使えますので、/etc/dhcpcd.conf を編集しWiFiが使えるようにします。
ここまでで、リブートすると、WindowsからPuttyでリモート(SSH)ログインできるはずです。

(3) SambaScreenをインストールしておきます。

(4)  RaspberryPi ZeroでBP35A1とシリアル通信UARTをおこなうため準備をします。RaspberryPi Zeroではbluetoothにシリアルがアサインされているようで、次のようにします。
ステップ1  /boot/cmdline.txtを次のように編集
$ sudo nano /boot/cmdline.txt

console=tty1 root=PARTUUID=0568b868-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
のように編集。すなわちconsole=serial0,115200という部分を外します。
ステップ2  config.txtを次のように編集
$ sudo nano /boot/config.txt
config.txtの最後に
dtoverlay=disable-bt
を追加
ステップ3 リブートして/devディレクトリのなかに、ttyAMA0 があるのを確認します。このデバイス名は、後ほどプログラムに必要です。
ステップ4 つぎにPythonからUARTを使えるようにするために、シリアルポート操作ライブラリpython-serialをインストール
$ sudo apt-get install python-serial

(5) BP35A1を基本動作させるために、ターミナルエミュレータ(minicom)をインストールしておきます。
$ sudo apt-get install minicom


BP35A1の動作確認


 ここでBP35A1と正しく通信できているか確認したいと思います。RaspberryPiのコンソール、あるいはPuttyのコンソールから操作します。BP35A1/BP35A7Aのユニバーサル基板を取り付け電源をいれます。
minicomコマンドでminicomを起動しBP35A1と通信可能とします。

$ minicom -D /dev/ttyAMA0 -b 115200


SKVERと打ってみます
SKVER
EVER 1.2.10
OK

“EVER xxx”が表示されるということは、無事にminicom とBP35A1 が接続されているということになります。またファームウェアのバージョンが確認できました。次にSKINFOコマンドを試します。
SKINFO
EINFO XXXX:0000:0000:0000:YYYY:1290:xxxx:xxxx 001D1290xxxxxxx 3B FFFF FFFE
OK

応答は次のような内容です。

EINFO <IPADDR><ADDR64><CHANNEL> <PANID><ADDR16>

<IPADDR> : 端末に設定されているIPv6アドレス
<ADDR64> : 端末のMAC アドレス
<CHANNEL> : 現在使用している周波数の論理チャネル番号
<PANID> : 現在のPAN ID
<ADDR16> : FFFE が表示されます


IPv6アドレスは、128ビットを16ビットずつの8つのグループに区切ってそれぞれのグループを4桁の16進数で表記し、グループとグループの間をコロンで仕切ります。そして、1グループXXXXと5グループYYYYをメモしておいてください。これがBP35A1 のソフトウェア関連情報を入手するためのユーザーID とパスワードとなります。これでコマンドリファレンスが手に入ります。


さらにBP35A1 の出力設定をつぎのコマンドで変更しておきます。
WOPT 1
OK

これにより、スマートメーターから受信したバイナリデータが16進ASCII文字で表示さるようになります。初めこれがわからず、苦労しました。本コマンドは、実行する度に設定が内部FLASH メモリに書込み保存され、電源を切っても設定は保存されています。FLASH メモリへの書込み回数には制限がありますので、設定時に一度だけ本コマンドを実行するようにしてください。

minicomを終了するときは、Ctrl-aを押した後、zを押して、xを押して、Enterです。


今回使用するコマンドは下記のとおりですべてSKで始まります。BP35A1 コマンドリファレンス参照
コマンド         説明
SKSETPWD 指定したパスワードからPSK(Pre-Shared Key)を生成して登録します
SKSETRBID 指定されたID からRoute-B ID を生成して設定します
SKSCAN 指定したチャネルに対してアクティブスキャンまたはED(Energy Detect) スキャンを実行します
SKSREG 仮想レジスタの内容を表示・設定します
SKLL64 MAC アドレスからIPv6 リンクローカルアドレスへ変換した結果を表示します
SKJOIN 指定した接続先IPv6 アドレスに対してPaC(PANA 認証クライアント)としてPANA 接続シーケンスを開始します
SKSENDTO 指定した宛先にUDP でデータを送信します


コマンドに対する通知として、EVENTが返されます。次のとおりです。

EVENT <イベント番号> <発信元アドレス> <イベント固有の引数> 

おもなイベント番号は次のとおり
イベント番号         説明
0x20 ビーコン を受信した
0x21 UDP 送信処理が完了した
0x22 アクティブスキャンが完了した
0x24 PANA による接続過程でエラーが発生した
0x25 PANA による接続が完了した


PythonによるHEMSプログラム

コマンドリファレンスの59ページにWi-SUN デバイスの起動シーケンス例があります。これにしたがってコマンドのシーケンスをPythonにより発生させていきます。
いろいろな方の開発事例があり、こちらを参考にさせていただきました。


 HEMSプログラム  HEMS.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 2021/03/21 (C) Dr.Hiroshi Ishikawa  2021/05/01バグ修正
import sys
import serial
import time
import datetime

#(13)タイムアウト処理のためtimeout_decoratorをimport
#sys.path.append('/home/pi/.local/lib/python2.7/site-packages')
from timeout_decorator import timeout, TimeoutError

def setup(msg):#(1) 
	global ser
	global ipv6Addr

	print(timestamp() + " setup start")

	# (2)シリアルポート初期化
	ser = serial.Serial('/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', timeout=2, xonxoff=0)

	# (3)キー設定 ご自身の値で要修正
	# Bルート認証ID
	rbid  = "00112233445566778899AABBCCDDEEFF"
	# Bルート認証パスワード
	rbpwd = "0123456789AB"

	# Bルート認証ID設定
	ser.write("SKSETRBID " + rbid + "\r\n")
	waitOK(msg)
	# Bルート認証パスワード設定
	ser.write("SKSETPWD C " + rbpwd + "\r\n")
	waitOK(msg)

	# (4)ネットワーク検出
	duration = 4;   # スキャン時間
	response = {} # スキャン結果
	while not response.has_key("Channel") :
		ser.write("SKSCAN 2 FFFFFFFF " + str(duration) + "\r\n")
		endline = False
		while not endline :
			line = ser.readline()
			sys.stdout.write(line)
			if line.startswith("EVENT 22") :
			 	endline = True
			elif line.startswith("  ") :# 以下PAN 情報
 	 		 	#  Channel:39
 	 		 	#  Channel Page:09
 	 		 	#  Pan ID:FFFF
 	 		 	#  Addr:FFFFFFFFFFFFFFFF
 	 		 	#  LQI:A7
 	 		 	#  PairID:FFFFFFFF
 	 		 	PAN = line.strip().split(':')
 	 		 	response[PAN[0]] = PAN[1]
		duration += 1 #スキャン失敗の場合、スキャン時間を増やしてリトライ

	# (5)スキャン結果からチャネル設定
	# Channelを設定
	ser.write("SKSREG S2 " + response["Channel"] + "\r\n")
	waitOK(msg)
	# Pan IDを設定
	ser.write("SKSREG S3 " + response["Pan ID"] + "\r\n")
	waitOK(msg)
	# MACアドレス(64bit)をIPV6アドレスに変換。
	ser.write("SKLL64 " + response["Addr"] + "\r\n")
	ser.readline()
	ipv6Addr = ser.readline().strip()
	print("ipv6Addr = " + ipv6Addr)

	# (6)PANA 認証
	ser.write("SKJOIN " + ipv6Addr + "\r\n")
	waitOK(msg)
	PANAconnected = False
	while not PANAconnected :
		line = ser.readline()
		if msg:
			sys.stdout.write(line)
		if line.startswith("EVENT 24") :
			print(timestamp() + " PANA failure")
			sys.exit()  
		elif line.startswith("EVENT 25") :
			print(timestamp() + " PANA Connected")
			PANAconnected = True
	print(timestamp() + " ECHONET Light start")

@timeout(5) #(14)
def ECHONETLite(msg):#(7)
		ECHONETframe = "\x10\x81\x00\x01\x05\xFF\x01\x02\x88\x01\x62\x01\xE7\x00" #(8)
		command = "SKSENDTO 1 {0} 0E1A 1 {1:04X} {2}".format(ipv6Addr, len(ECHONETframe), ECHONETframe)
		ser.write(command)
		waitOK(msg)

		#(9)データの受信処理
		line = ser.readline() 	 	 # ERXUDPが来るはず
		if msg:
			sys.stdout.write(line )
		if line.startswith("ERXUDP") :
			udp = line.strip().split(' ')
			DATA = udp[8]   #ERXUDPの8番目がデータ
			SEOJ = DATA[8:8+6]
			ESV = DATA[20:20+2]
			if SEOJ == "028801" and ESV == "72" :# スマート電力量メーター(028801)から来た応答(72)なら
				EPC = DATA[24:24+2] 	 	   
				if EPC == "E7" :#瞬時電力
					hexPower = line[-8:] 	# 最後の4バイト(16進数で8文字)が瞬時電力計測値
					intPower = int(hexPower, 16)
					outputdata = timestamp() + "," + str(intPower) + "\n"#タイムスタンプをつけて出力
					datafile(outputdata)

def waitOK(msg):#(10)
	while True :
		line = ser.readline()
		if msg:
			sys.stdout.write(line)
		if line.startswith("OK") :
			break

def timestamp():
	return datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")

def datafile(line):#(11)
	filename = 'data/' + datetime.datetime.now().strftime("%Y%m") + 'data.txt'
	file_data = open(filename , "a" )
	file_data.write(line)
	file_data.close() 


if __name__ == '__main__':#(12)
	setup(True)#コンソールメッセージが不要の場合は msg=False

	while True:
		try:
			ECHONETLite(False)
			time.sleep(4)
		except TimeoutError:#(15)ECHONETLite()からの応答が@timeout(5)を超えた場合
			print(timestamp() + " timeout")


 

(1) 開始時に1度だけ実行するプログラムをsetup()関数にまとめて記述します。この関数のパラメータとして、 msgをTrueあるいは Falseで指定します。これはコマンド、レスポンスをすべてコンソール上に出力すると、煩雑になるので、動作確認の必要な時にこの値をTrueとします。

(2) BP35A1とシリアル通信するための設定を行います。BP35A1コマンドリファレンス43ページによれば、「ボーレート =115200、キャラクター間インターバル=なし、 フロー制御 =無効、」と規定されています。さらに「SK コマンド実行後は、必ずその応答を待ってから、次のSK コマンドを実行してください。なお、応答の待機時間は発行するコマンドによって異なり、数秒〜数十秒程度を要することがあります。」という注意書きがあります。

 一方、Pythonのシリアル通信pySerial APIでreadline()の際のtimeoutは次のような動作となっています。

timeout = None:要求された行が受信されるまで待つ(デフォルト)

timeout = 0:ノンブロッキングモード、どのような場合でもすぐに戻る

timeout = x:タイムアウトをx秒に設定すると、行末になるとすぐに戻る。それ以外の場合は、タイムアウトになるまで待機し、それまでに受信したすべてのバイトを返す。

したがって、デフォルトのままにしておくと、条件によってプログラムは待ち続ける可能性があり、かならず、timeoutに値を設定しておきます。

以上により次のようにしています。
ser = serial.Serial('/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', timeout=2, xonxoff=0)

(3) 認証キー設定

電力会社から郵送された認証ID(16進ASCII32桁)とメールで通知されるパスワード(英数字12桁)を設定します。区切りのスペースは不要です。(以下値は仮)

次のようなコマンドをシリアルに送信するため、Pythonからser.writeしOKを待ちます。
SKSETRBID 00112233445566778899AABBCCDDEEFF   
OK
SKSETPWD C 0123456789AB
OK

(4)ネットワーク検出
Wi-SUNネットワークではいくつかの周波数があり、そのなかのどの周波数がつかわれているか、アクティブスキャンコマンドをもちいてネットワークの検出を行います。スキャン時間を変えながら見つかるまで繰り返します。 見つかるとEVENT 20が返り、接続先(スマートメータ)のPAN 情報が出力されます。
SKSCAN 2 FFFFFFFF 2
EVENT 20 XXXX:0000:0000:0000:YYYY:1290:xxxx:xxxx
EPANDESC
  Channel:21
  Channel Page:09
   Pan ID:1234
   Addr:001D129012345678
   LQI:A7
   PairID:FFFFFFFF
EVENT 22 XXXX:0000:0000:0000:YYYY:1290:xxxx:xxxx

ここで
Channel : 発見したPAN の周波数(論理チャネル番号)
Channel Page : 発見したPAN のチャネルページ
Pan ID : 発見したPAN のPAN ID
Addr : アクティブスキャン応答元のアドレス
LQI : 受信したビーコンの受信RSSI
PairID:相手から受信したPairing ID

(5)チャネル設定 (33ch(0x21)(922.5MHz)の例)

アクティブスキャンの完了(EVENT 22)を待ってから、以下のコマンドを送信します。

PAN 情報からチャネルとPAN ID を取得して、それをS2 とS3 に設定します。
SKSREG S2 21
SKSREG S3 1234

さらにAddr(Macアドレス)からIPv6 アドレス変換します。
SKLL64 001D129012345678


(6)PANA 認証(PaC)
発見したスマートメータに対してPANA 認証クライアントとして、SKJOINコマンドによりPANA接続シーケンスを開始します。
SKJOIN FE80:0000:0000:0000:021D:1290:1234:5678

PANA による接続完了(EVENT 25)を確認したら、初期設定を終了します。

(7)データ受信 のためのECHONETLite()関数

スマートメータとのデータ送受信 のためのECHONETLite()関数を準備します。setup()関数と同様にコンソールメッセージの要不要を指定できます。

データの送受は、IP 通信(PANA暗号化UDP)によって行います。コマンドはSKSENDTOを用います。電文のフォーマットは、ECHONETLite 規格にしたがった図のような構成です。汎用性・拡張性のためか、かなり冗長です。


(8) 第2部 ECHONET Lite 通信ミドルウェア仕様により、次の内容のフレームを指定します。

ECHONETframe = "\x10\x81\x00\x01\x05\xFF\x01\x02\x88\x01\x62\x01\xE7\x00"

ここで EPCには0xE7としていますが、瞬時の電力値を要求しています。
Header Value 説明
EHD1 10 ECHONET Lite規格 を表す
EHD2 81 形式1 を指定
TID 0001 トランザクションID
SEOJ 05FF01 送信元ECHONET Liteオブジェクト指定
DEOJ 028801 受信元ECHONET Liteオブジェクト指定
ESV 62 読み出し要求(GET)
OPC 01 処理プロパティ数
EPC E7 瞬時電力計測値
PDC 00 EDTのバイト数

SKSENDTO コマンドを用い、上記フレームをスマートメータに送信します。SKSENDTOコマンドの書式は次のとおりです。 UDPのポート番号はECHONET Lite 用の3610(0x0E1A)を使用します。セキュリティフラグで暗号化指定します。<DATA>には上記フレームが入ります。

SKSENDTO 1 <IPv6アドレス > <PORT番号> <セキュリティフラグ> <データ長> <DATA>

上の例ではスマートメータ(例FE80:0000:0000:0000:021D:1290:1234:5678)に対して
SKSENDTO 1 FE80:0000:0000:0000:021D:1290:1234:5678 0E1A 1 000E 1081000105FF010288016201E700

なお最後のデータ部分はコンソール上は表示(エコーバック)されません。 

(9)データの受信処理
SKSENDTOコマンドに対してのレスポンスとして、ERXUDPで始まる次のような応答があります。
ERXUDP <送信元IPv6 アドレス> <送信先IPv6 アドレス> <送信元ポート番号> <送信先ポート番号> <送信元のMAC 層アドレス> 1 <受信したデータの長さ> <受信データ>

<受信データ>の内容は次のとおりです。
Header Value 説明
ECHONET Liteヘッダ1 10 ECHONET Lite規格 を表す
ECHONET Liteヘッダ2 81 形式1 を指定
TID 0001 トランザクションID
SEOJ 028801 送信元 スマート電力量メーター
DEOJ 05FF01 受信元オブジェクト
ESV 72 読み出し応答
OPC 01 処理プロパティ数
EPC E7 瞬時電力計測値
PDC 04 EDTのバイト数
EDT 000000A0 160W

このメッセージは長いですが、最後からPDCで示されるバイト数をとりだせば、瞬間の電力値が得られます。
 なお瞬時電力計測値以外の積算電力量、瞬時電流計測量、定時積算電力量などの計測については、まだやっていません。スマート電力量メータクラス規定 (APPENDIX ECHONET機器オブジェクト詳細規定) を参考。

(10)コマンドを送信した後、”OK"を待つ場合が多くあります。そのための関数を定義しておきます。

(11)読み取った瞬間電力量にタイムスタンプをつけて、ファイルに書き込みます。いつトラブルが起きてもいいように、open、closeをそのつど行います。

(12)メインはECHONETLite()を無限ループで呼びます。(13)でのべるECHONETLite()がタイムアウトしたときにも、強制的に繰り返します。
最大1.5秒に1度データが得られるので、time.sleep(4)を入れています。

タイムアウト処理
 BP35A1 コマンドリファレンスによると、「必ずその応答を待ってから、次のSK コマンドを実行してください。なお、応答の待機時間は発行するコマンドによって異なり、数秒〜数十秒程度を要するこ」とあります。また、先人たちも「連続計測できない。なんだか不安定です」などの記述があり、定期的にLINUXのcronコマンドで、Pythonプログラムの再起動をするなど工夫をしています。
 上に述べたシリアル通信のタイムアウトの指定で、この問題はかなり解決できましたが、それでも連続運転が長くなると、ECHONETLite()関数から応答が返らない場合がまれにあり、ストールしてしまいます。そのためECHONETLite()からの応答が一定時間帰らないときは、強制的に再度実行するようタイムアウトの処理を入れることにしました。
具体的にはtimeout_decoratorを使ってみたところ、確実に連続運転が可能となりました。

timeout_decoratorのインストール
timeout_decoratorはpipでインストールします。私の場合、pipがうまく働かず、pipのインストールから行いました。
$ sudo apt-get install update
$ sudo apt-get install python-pip
その後
$ python -m pip install timeout-decorator
つぎに
$ pip show timeout-decorator
により、timeout_decoratorがどこのディレクトリにインストールされているか確認します。

(13)プログラムでは
from timeout_decorator import timeout, TimeoutError
でimportします。
importエラーが発生した場合
sys.path.append('/home/pi/.local/lib/python2.7/site-packages')
のように、timeout_decoratorのインストール先を明示する必要があります。

(14)ECHONETLite()の直前で@timeout(5) でデコレートし、タイムアウトの秒数を5秒に指定します。

(15)もし、ECHONETLite()からの応答がこの秒数で返らなければ、TimeoutErroが発生します。呼ぶ側で例外を検知し、whileループに戻します。

実行
 このHEMSコントローラは、入力出力とも無線ですので、5Vが得られれば自由に設置できます。スマートメータの位置から遠くない室内に設置します。
親パソコンのコンソールから次のように起動します。
$ sudo python HEMS.py

 RaspberryPiのdataディレクトリに月に1本のファイルができます。親PCからEXCELで開けます。このファイルを定期的に読みに行き、gnuplotで作図します。たとえば5時間分をグラフ化したものを以下に示します

要因は推定

 詳細な使用電力量変化をみることができます。照明やテレビのような電力消費のほかに、細かなスパイク状の変動があることがわかりました。周期的なスパイクはIH炊飯器の保温、ウォシュレットの保温です。冷蔵庫、湯沸かしポット、テレビの待機電力など意外なところで電気を消費しているのが、明白になりました。これをみながらどの器機が電気を食っているか下手人探しを行い、省エネにつとめることといたします。

お断り
セキュリティ対策のため、測定結果をWebへのリアルタイム表示は行っていません。


top