pythonでTWE-Liteのシリアルを受け取る

安価で低消費電力の無線マイコン、[TWE-Lite](http://mono-wireless.com/jp/products/TWE-Lite-DIP/index.html)のシリアルデータをRaspberry Pi上のpythonで受け取るメモ。


## 構成

　　| TWE-Lite | - | raspberry Pi |

まず、Raspberry Piのシリアルを使えるようにする。
この辺を見るといいです。
http://qiita.com/ryugyoku/items/bf5fd10512c84a55d030

## テスト

TWE-LiteのTX,RDをRaspberry Piのシリアルポートに接続します。
試しにminicomで読み込んでみましょう。

~~~ shell

$ sudo minicom -b 115200 -o -D /dev/ttyAMA0

~~~

minicomはsudo apt-get install minicomでインストールできます。

-Dオプションがターミナルの場所。
USBシリアル変換を使用している場合はここを/dev/ttyUSB0とかに変えればいいです。

~~~

minicom へようこそ 2.7

オプション: I18n
コンパイルされた日時は:  Jan 12 2014, 05:42:53.
ポート /dev/ttyAMA0, 01:54:51

CTRL-A Z を押すと、説明画面になります。

:0F8115015481012CFB00A387000BB0150101FFFFFFFFFF66
:0F8115015181012CFB00A389000BB0150101FFFFFFFFFF67
:0F8115015481012CFB00A38B000BAC150101FFFFFFFFFF66
:0F8115015181012CFB00A38D000BAC150101FFFFFFFFFF67
:0F8115015481012CFB00A38F000BB0150101FFFFFFFFFF5E
:0F8115014E81012CFB00A393000BAC150101FFFFFFFFFF64

~~~

このような物が出たら接続は正常です。
Ctrl+A,Qで終了。

こいつをPythonで受け取ってパースしましょう


## シリアル受け取り

シリアルの取得は[pyserial](https://github.com/pyserial/pyserial)を使用します。

~~~ shell

$ pip3 install pyserial

~~~

~~~ python3

Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> ser = serial.Serial('/dev/ttyAMA0',115200)
>>> ser.readline()
b':0F8115014E81012CFB00A437000BAC150101FFFFFFFFFFBF'
>>> ser.close()
<bound method Serial.close of Serial<id=0xb68fd550, open=True>(port='/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)>
>>>

~~~

## チェックサム計算
公式によると、コードの最後の1バイトがチェックサムとなっています。
計算方法は、先頭行から1バイトずつ加算していき、和の下位1バイトの補数がチェックサムとなっています。
つまり、':0F8115014E81012CFB00A437000BAC150101FFFFFFFFFFBF'の場合のチェックサムは最後のBFで、
0x0f+0x81+....0xff+0xff = 0x941　これの下1バイトの0x41 + 0xBF = 0xa00となります。

ということは、最初の":"を除く全桁を1バイトずつ加算した総和の下1バイトはかならず0になるということです。


python的な計算をすると、

~~~python3

Python 3.5.2 (default, Jun 28 2016, 08:46:01) 
[GCC 6.1.1 20160602] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> string = ':0F8115014E81012CFB00A437000BAC150101FFFFFFFFFFBF'
>>> string = string[1:] #冒頭の:を除く
>>> lst = [ int(string[i:i+2], 16) for i in range(0, len(string), 2) ]　#二桁ずつ切り取って16進数として数値化
>>> s = sum(lst) #総和を取る
>>> hex(s & 0b1111)
'0x0'
>>>

~~~

0になりましたね。話のわかるやつだ


## パース

データフォーマットは[マニュアル](http://mono-wireless.com/jp/products/TWE-Lite-USB/monitor.html)を参照。

~~~ python3
# coding: utf-8
#!/usr/bin/env python3

def parse(string):
    if string[-2:] == b"\r\n"  : string = string[:-2]
    if string[0]   == ord(':') : string = string[1:]
    lst = [ int(string[i:i+2], 16) for i in range(0, len(string), 2) ]
    if sum(lst) & 0xff == 0:
        return lst

    return False

if __name__ == '__main__':
    import serial
    s = serial.Serial('/dev/ttyAMA0',115200)

    l = s.readline()
    lst = parse(l)

    print (lst)

    SOURCE_DEVIDE = lst[0]
    COMMAND = lst[1]
    PACKET = lst[2]
    PROTOCOL = lst[3]
    LQI = (7 * lst[4] - 1970 ) / 20
    SN = lst[5] << 24 | lst[6] << 16 | lst[7] << 8 | lst[8]
    DESTINATION_ID = lst[9]
    TIMESTAMP = lst[10] << 8 | lst[11]
    RELATED = True if lst[15] % 1 else False
    VOLTAGE = lst[13] << 8 | lst[14]
    NONE = 0
    DIN = lst[16]
    DCHANGE = lst[17]
    ACOMP = lst[22]
    AD1 = (lst[18] * 4 + ACOMP) * 4
    AD2 = (lst[19] * 4 + ACOMP) * 4
    AD3 = (lst[20] * 4 + ACOMP) * 4
    AD4 = (lst[21] * 4 + ACOMP) * 4
    SUM = lst[-1]

    D1 = True if lst[16] & 0b0001 else False
    D2 = True if lst[16] & 0b0010 else False
    D3 = True if lst[16] & 0b0100 else False
    D4 = True if lst[16] & 0b1000 else False

~~~

あとはご自由に。

ライブラリですが、今見たら酷い出来だったのでそのうち改造します