Python2.7.9+pySerialで実装。
ESP:EnOcean Serial Protocol
詳しいドキュメントはEnOceanのサイトからDLできる。EnOceanの電文は上記の図(ドキュメントから引用)のようになっている。
- Sync. Byte: 同期用の信号で、常に0x55で固定。
- header: 4byte固定。2番目のbyteにdataの、3番目にoptional dataの長さが書かれている。
- CRC8H: チェックサム。
- data: センサIDや動作内容が記載されている。
- センサid: dataの2~5番目に書かれている4byte。
- マグネットセンサ(STM429J): dataの6番目のbyteが0x08なら開、0x09なら閉。
- 温度センサ(STM431J): dataの8番目のbyteを元に算出する。例えば5dなら25.4℃。
temp = (255.0-val)/255.0*40.0 - optional data: 長さはheaderに書かれている。
- CRC8D: チェックサム。
Pythonのソースコード
CentOS環境でPython2.7.9/pySerialにより実装した例。シリアル通信で1byteずつ読み取る。
電文の先頭はかならず0x55になるので、それを起点としてカウントする。
# coding: UTF-8 from serial import * from sys import exit from datetime import datetime port = '/dev/ttyUSB0' # シリアルポートを開く try: ser = Serial(port, 57600) print('open serial port: %s' % port) except: print('cannot open serial port: %s' % port) exit(1) # 初期化 cnt,dataLen,optLen = 0,0,0 telegraph,headList,dataList,optList = [],[],[],[] ready = True # 電文開始のフラグ管理 # データの解釈とログの記録 while True: s = ser.read().encode('hex') # 1byteずつ読み込み if s == '55' and ready: # 電文開始 # 変数のリセット cnt,dataLen,optLen = 0,0,0 telegraph,headList,dataList,optList = [],[],[],[] ready = False print '==========' cnt += 1 telegraph.append(s) if 2 <= cnt <= 5: # header headList.append(s) if cnt == 5: # header終了, data length取得 dataLen = int(headList[1],16) optLen = int(headList[2],16) if 7 <= cnt <= (6+dataLen): # data dataList.append(s) if (7+dataLen) <= cnt <= (6+dataLen+optLen): # optional data optList.append(s) if cnt == (6+dataLen+optLen+1): # 電文終了 ready = True dt = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # ログ出力 print dt print ':'.join(telegraph) print 'head...', ':'.join(headList) print 'data...', ':'.join(dataList), '(length=%d)' % dataLen print 'opt ...', ':'.join(optList), '(length=%d)' % optLen sensorId = ':'.join(dataList[1:5]) # センサID取得 print 'sid ...', sensorId # マグネットセンサ if sensorId == '04:00:03:df': if dataList[5] == '08': action = 'open' elif dataList[5] == '09': action = 'close' print 'door...', action # 温度センサ elif sensorId == '04:00:7a:fc': val = int(dataList[7],16) temp = (255.0-val)/255.0*40.0 print 'temp...', temp # 上記以外のセンサIDは無視 else: continue出力結果は以下のとおり。
今のところ変な挙動もなく、ドア開閉や気温をきちんと読み取れている。
open serial port: /dev/ttyUSB0 ========== 2015-12-14 16:12:58 55:00:07:02:0a:0a:21:04:00:03:df:08:61:01:3a:b3 head... 00:07:02:0a data... 21:04:00:03:df:08:61 (length=7) opt ... 01:3a (length=2) sid ... 04:00:03:df door... open ========== 2015-12-14 16:13:05 55:00:07:02:0a:0a:21:04:00:03:df:09:66:01:3a:b3 head... 00:07:02:0a data... 21:04:00:03:df:09:66 (length=7) opt ... 01:3a (length=2) sid ... 04:00:03:df door... close ========== 2015-12-14 16:17:32 55:00:0a:02:0a:9b:22:04:00:7a:fc:00:00:5d:08:3f:01:37:90 head... 00:0a:02:0a data... 22:04:00:7a:fc:00:00:5d:08:3f (length=10) opt ... 01:37 (length=2) sid ... 04:00:7a:fc temp... 25.4117647059当初、pySerialのreadline()で1行ずつ受信しようとしたら上手くいかなかった。
面倒でもread()で1byteずつ読み取って、ヘッダ部分からデータ長など読み取りつつ処理する必要がある。
----
2016/6/21追記:プログラムにバグがあるという指摘を受けて修正。Bool型変数readyによる、電文開始フラグに関する処理を追加した。