Edited at

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


タイトル通り、出来るかも?でしたが、出来たので投稿

スペック上では明記されてない使い方なので、賭けでしたが、

意外と簡単に繋げることが出来ました。

今後何かの参考になればと投稿します。


1.概要


TPMSとは

wikipediaより

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

車のタイヤ空気圧が中途半端に下がったまま高速走行して、

バースト・火事になったり事故になったり、アメリカではかなり問題になった為、装着が義務化

センサーをタイヤホイールに内蔵して随時監視するものです。

メーカーが標準で付けているのが安心ですが、もちろん外付けもあり、

今までは専用の表示器があって、独自の無線通信を使用していたものが多かったのですが、

ここ最近はBluetoothを使った製品も多く、これらはBLEを使用している可能性がある為、

出来るかな?ってことでやってみたら出来ましたという報告です。。


2.装備

Raspberry Pi 3B

BLE使用のため、Ver,4.0以降が必要です。

中華製 TPMSセット

本当はスマホで確認するものです。

エアコンプレッサー あるいは タイヤ。



赤枠のこの部分に放り込みました・・・

圧力がないと解析できないので。

普通に付いているタイヤで十分です。


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

どうやらセンサから、アドバタイズデータとして勝手に送りつけてくるようです。

あたりに撒き散らしているので、走行中に他の人のデータも取れる??

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

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: となっている16進を横並びにすると。(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とかは、

スマホのアプリでモニタリングしながら、大体で記録しているからで、センサー数値の方が正しい状態です。

ではもう一つ値が動いているのをお気づきでしょうか?

そう70094009ですね。

これは・・・

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

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


device.rssi

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


device.getScanData() -> Code

データにもアドレスはいくつで電波強度は・・・ってコードごとに1~255まで入ってきます。

欲しいデータは255番にあるので区別しましょう。


device.getScanData() -> desc

データの説明です。ほぼ使わない。


device.getScanData() -> value

これです欲しかったのは。

80eaca10077e28800000400900002f00

この文字列でデータが入ってますので、

value[16:22]で切り出して、リトルエンディアンを変換、16進から10進に、その後1000で割って、圧力[kPa]

value[24:28]温度も同じく切り出して変換、100で割って、温度[℃]

リトルエンディアン変換は、こちらの記事を参考にしました。ありがとうございます。

https://qiita.com/QUANON/items/e3d91a6f33536bd0de5a

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

def hex2int(_HEX):

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


終わり

これでスマホアプリに頼らない確認ができる。。。

OBD2も勉強中で、車載Raspにするかどうしようか・・・・

しかしこういったツールって中国の方が優勢なんですよね、

この辺のジャンキーな分野を国内で気軽に楽しめないと、

技術者って育たない気がするのは私だけなのでしょうかね・・・

以上、お粗末でした。