はじめに
- 京セラ製太陽光発電システムが稼働している関係で、エコノナビット(PMD47A)という発電状況をモニタする装置(以下、モニタ)を設置しています。
- このモニタはPCとシリアル通信ポートで繋がっていて、京セラから提供されている通信ソフトを使うと、モニタから収集したデータがCSVファイルで出力されます。
- 定期的にモニタからのデータ収集を行いたいのですが、それだとPCを常時稼働させる必要があります。
- このデータ収集をラズパイで行いたいと思い、その通信内容を把握することが今回の目的となります。
UART通信のキャプチャ
-
ラズパイと秋月電子製USB-シリアル2ch変換モジュールを使って、モニターPC間のUART通信をキャプチャし、解析してみることにしました。
-
回路図
-
プログラム
- 2chのUART受信を行い、そのデータを標準出力するだけのものです。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import datetime
import threading
import serial
event = threading.Event()
lock = threading.Lock()
def cap(dev, baud, ch) :
ser = serial.Serial(dev, baud, timeout=5)
while event.is_set() != True :
data = ser.read()
if data.__len__() > 0 :
lock.acquire()
try :
if ch == 0 :
print("{0:02X},".format(ord(data)))
else :
print(",{0:02X}".format(ord(data)))
finally :
lock.release()
def wait(msg) :
code = raw_input("")
event.set()
thread1 = threading.Thread(target=cap, args=('/dev/ttyUSB0', 38400, 0,))
thread2 = threading.Thread(target=cap, args=('/dev/ttyUSB1', 38400, 1,))
thread3 = threading.Thread(target=wait, args=('>>> ',))
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
解析結果
- プロトコル
- 下記の流れでやり取りされる。(全データを送り終わるまで、5と6が繰り返される)
- PCからの要求電文
- モニタからのACK電文
- モニタからの開始電文
- この電文から、全データ数を抽出できる。
- PCからのACK電文
- モニタからのデータフレーム
- PCからのACK電文
- モニタからの終了電文
- PCからのACK電文
- とりあえず、全データを取得するには、下記の電文フォーマットを把握できれば問題なさそう。
- PCからの要求電文(1)
- モニタからの開始電文(3)
- PCからのACK電文(4,6)
- モニタからのデータフレーム(5)
- 下記の流れでやり取りされる。(全データを送り終わるまで、5と6が繰り返される)
-
PCからの要求電文構成
- STX(02h)から始まり、ETX(03h)で終わる電文。
- STX, CMD1000FFFF50, ETX
- 何度かキャプチャして比較したが、毎回同じだった。固定文字列でよさそう。
- STX(02h)から始まり、ETX(03h)で終わる電文。
-
PCからのACK電文構成
- STX(02h)、ACK(06h)、ETX(03h)の3バイト。
-
モニタからの開始電文構成
- STX(02h)から始まり、ETX(03h)で終わる電文。
- STX, CMD01000000214FCB, ETX
- この電文から、全データ数214Fh(8527byte)が得られる。
- 何度かキャプチャして比較したが、毎回同じだった。
- 8527byte固定でよいかもしれないが、電文から取得すべきと思われる。
- 具体例
- STX(02h)から始まり、ETX(03h)で終わる電文。
02434D44303130303030303032313446434203
2. モニタからのデータフレーム構成
- フレームの正常性確認は、BCCを含めたn+2バイトを加算して、下位8ビットがFF(16進値)となるかどうかで判定。
- データ長が1バイト、ペイロードがnバイト、BCCが1バイト。
- 具体例
- データ長=21h(33byte)
- BCC=93h
- チェックサム(16進)=21+45+43+4E+56+00+01+00+68+21+4F+00+68+00+14+00+7C+00+03+00+23+00+E5+00+02+06+90+0E+05+00+02+06+90+93=5FFh
```
2145434E5600010068214F00680014007C0003002300E5000206900E050002069093
- データ・レイアウト
- データフレームのペイロードを抽出して、順に並べたもの。
- 30分毎のデータ、日毎のデータ、月毎のデータが下表に示すようなレイアウトで配置されている。
項番 | 種別 | アドレス範囲 | 備考 |
---|---|---|---|
1 | 30分毎のデータの日付 | 007C〜00E4 | 年月日の3バイトが、35日分 |
2 | 30分毎の発電データ | 00E5〜0E04 | 10倍した値が2バイト(16進値)で1データ、48データが1日分で35日。未取得の時間帯は、7530hとなっている。 |
3 | 30分毎の買電ー売電データ | 0E05〜1B24 | 10倍した値が2バイト(16進値)で1データ、48データが1日分で35日。未取得の時間帯は、7530hとなっている。 |
4 | 日毎のデータの日付 | 1B48〜1C73 | 年月日の3バイトが100日分 |
5 | 日毎の発電データ | 1C74〜1D3B | 1日分が2バイト(16進値)で、100日分 |
6 | 日毎の買電ー売電データ | 1D3C〜1E03 | 1日分が2バイト(16進値)で、100日分 |
7 | 月毎のデータの日付 | 1E04〜1EB7 | 年月日の3バイトが、60ヶ月分 |
8 | 月毎の発電データ | 1EB8〜1F2F | 1月分が2バイト(16進値)で、60ヶ月分 |
9 | 月毎の買電ー売電データ | 1F30〜1FA7 | 1月分が2バイト(16進値)で、60ヶ月分 |