TPMS(タイヤ空気圧センサ)とRaspberry Piを繋げて、データを取得する。

# タイトル通り、出来るかも？でしたが、出来たので投稿
スペック上では明記されてない使い方なので、賭けでしたが、
意外と簡単に繋げることが出来ました。
今後何かの参考になればと投稿します。

## 1.概要
####TPMSとは
wikipediaより
`TPMS (タイヤ・プレッシャー・モニタリング・システム　Tire Pressure Monitoring System)とは、自動車のタイヤ空気圧を常時モニタリングするシステム。`

車のタイヤ空気圧が中途半端に下がったまま高速走行して、
バースト・火事になったり事故になったり、アメリカではかなり問題になった為、装着が義務化
センサーをタイヤホイールに内蔵して随時監視するものです。

メーカーが標準で付けているのが安心ですが、もちろん外付けもあり、
今までは専用の表示器があって、独自の無線通信を使用していたものが多かったのですが、
ここ最近はBluetoothを使った製品も多く、これらはBLEを使用している可能性がある為、
出来るかな？ってことでやってみたら出来ましたという報告です。。

## 2.装備
Raspberry Pi 3B
BLE使用のため、Ver,4.0以降が必要です。

中華製 TPMSセット
本当はスマホで確認するものです。
![4_Pieces_Sensors_TPMS_Bluetooth_4_0_Car_Inner_Outer_TPMS_Tire_Pressure_Monitoring_BLE_TPMS_Low_Energy_For_Android_WRTRST50_TPMS-in_Tire_Pressure_Alarm_from_Automobiles___Motorcycles_on_Aliexpress_com___Alibaba_Group_-_Vivaldi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178507/065babd6-111f-82aa-1111-4f8b6d00b87e.png)


エアコンプレッサー　あるいは　タイヤ。
![Amazon_co_jp：_ウェーブ_コンプレッサー_317__ホビー_-_Vivaldi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178507/b7f792af-20f0-9ab1-17e3-83308a4b151e.png)
赤枠のこの部分に放り込みました・・・

圧力がないと解析できないので。
普通に付いているタイヤで十分です。

## 3.プロトコル解析
早速ですが、海外でもおんなじことを考えた人が昔いたようで、
途中で止まってますが、こちらに書いてありました。

[How to Decode TPMS Sensor data through RPi3 Bluetooth]
https://raspberrypi.stackexchange.com/questions/76959/how-to-decode-tpms-sensor-data-through-rpi3-bluetooth

どうやらセンサから、アドバタイズデータとして勝手に送りつけてくるようです。
あたりに撒き散らしているので、走行中に他の人のデータも取れる？？

とりあえず以下でデータ確認

```terminal
sudo bluetoothctl
scan on
```

これで待っていると周りのBT製品が表示されて行きます。
この状態でセンサーをタイヤに付けたり外したりすると、データが変わってくると思います。
このデータを回収して解析です。

まず分かったこと。

- ペアリングは無しで、アドバタイズデータとして送られてくる。
- 圧力もしくは温度変化があった時に送ってきている。
- データ上にアドレスがあるため、識別できる。

次にデータ構造の解析です。
以下がこの製品で送られてきたscan onでの結果です。

``` copy.txt

300kPa の時
Device 80:EA:CA:10:07:7E RSSI: -69
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Key: 0x0100
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x80
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0xea
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0xca
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x10
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x07
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x7e
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0xa9
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x23
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x05
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x6b
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x09
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x2f
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x01


30kPa　の時
[CHG] Device 80:EA:CA:10:07:7E RSSI: -58
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Key: 0x0100
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x80
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0xea
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0xca
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x10
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x07
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x7e
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x28
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x80
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x40
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x09
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x2f
[CHG] Device 80:EA:CA:10:07:7E ManufacturerData Value: 0x00
```
各Value: となっている１６進を横並びにすると。(0xは略)

```
300kPa --> 80 ea ca 10 07 7e a9 23 05 00 6b 09 00 00 2f 00
 30kPa --> 80 ea ca 10 07 7e 28 80 00 00 40 09 00 00 2f 00
```
はい、もうざっくりですがお判りの人もいるかと思います。
先頭から80〜7eまでは固定、というかデバイスのアドレスですね。
その先、300kPa側で見てみましょう。

`a9 23 05`

このままだと、11084549となり意味をなしません。
そこでリトルエンディアンと考えて、`05 23 a9`とすると。
336809、はい。桁が違いますが、約336kPaですね。

では30kPaは？？
`00 80 28 = 32808 = 32kPa`
大丈夫、合致してますね。

少しずれているのが気になるかも知れませんが、300kPaとか30kPaとかは、
スマホのアプリでモニタリングしながら、大体で記録しているからで、センサー数値の方が正しい状態です。

ではもう一つ値が動いているのをお気づきでしょうか？
そう`7009`や`4009`ですね。

これは・・・
`0970 = 2416 = 24.16`
`0940 = 2368 = 23.68`
はい、温度ですね。ちゃんと摂氏で出てきてくれています。

ここまで来たら、Pythonでこのデータを回収しちゃえばいい。
手順としては。

 - アドレスで振り分け
 - 内容の内、圧力と温度を抽出
 - リトルエンディアンから整数、桁合わせ
 - 完成！

このイメージで進めます。

## 4.実装

bluepyを使用します。
参考にさせて頂いたのは、こちらの会社の社員さんブログから。

「bluepyで始めるBluetooth Low Energy(BLE)プログラミング」
https://www.ipride.co.jp/blog/2510

```
from bluepy import bt

scan = bt.Scanner(0)

# 10秒スキャン
devs = scan.scan(10.0)

for device in devs:
  print(device.addr)
  print(device.rssi)

  for (Code,desc,value) in device.getScanData():
    print(Code)
    print(desc)
    print(value)

    Press = value[16:22]
    Temp = value[24:28]
```

ほぼ、丸コピーで申し訳ありませんが、得られるデータを説明します。
こちらを一度実行してからで十分です。

#### device.addr
こちらはセンサーのアドレス値が入ります、ですので４つあるタイヤの区別はこのアドレスで行います。

#### device.rssi
電波強度です。使用しませんが、電池切れの時に落ちてくるのか否か・・・・

#### device.getScanData() -> Code
データにもアドレスはいくつで電波強度は・・・ってコードごとに1~255まで入ってきます。
欲しいデータは255番にあるので区別しましょう。

#### device.getScanData() -> desc
データの説明です。ほぼ使わない。

#### device.getScanData() -> value
これです欲しかったのは。
`80eaca10077e28800000400900002f00`
この文字列でデータが入ってますので、
`value[16:22]`で切り出して、リトルエンディアンを変換、１６進から１０進に、その後1000で割って、圧力[kPa]
`value[24:28]`温度も同じく切り出して変換、100で割って、温度[℃]

リトルエンディアン変換は、こちらの記事を参考にしました。ありがとうございます。
https://qiita.com/QUANON/items/e3d91a6f33536bd0de5a

１０進変換まで、関数でこんな感じに、一行に書けって話かもしれませんが・・・

```
def hex2int(_HEX):
  _BIN=bytes.fromhex(_HEX) #バイナリへ
  _Rev=_BIN[::-1]　　　　　　#反転
  _HEX=_Rev.hex()　　　　　　#１６進へ
  return int(_HEX,16)　　　 #１０進へ
```

## 終わり
これでスマホアプリに頼らない確認ができる。。。
OBD2も勉強中で、車載Raspにするかどうしようか・・・・

しかしこういったツールって中国の方が優勢なんですよね、
この辺のジャンキーな分野を国内で気軽に楽しめないと、
技術者って育たない気がするのは私だけなのでしょうかね・・・

以上、お粗末でした。