Bluetooth経由でInkbirdの温度計から温度と湿度の履歴データを取得する

Bluetooth温湿度計を買って自力でIoT対応出来るようにした。
SDK配布はおろか仕様も非公開だったけど、自力でBLE接続してデータを抜くことに成功した。
Inkbird IBS-TH1 PLUSってやつ、Amazonのタイムセールで3,600円。

メーカー公式のアプリを使えば温度/湿度の履歴をCSV形式でスマホに保存出来るけど、直接Bluetooth経由で生の履歴データが欲しかった。
リアルタイムのデータしか取れないと近くにずっとスマホを置いておかなきゃいけないし、かといってメーカーのアプリ使ってCSVエクスポートするのも不便なので。

ググった感じ、アドバタイズパケットを見てリアルタイムに温度と湿度を取っている人は見かけたけど、ちゃんとGATT接続してデータ取得している人は見かけていない。
なので一応誰かのためになるかもしれないのでメモ。

アドバタイズパケット

Manufacturer Specificの先頭2byteに企業の識別子がついていない。
AndroidのBluetoothLeScannerのcallbackでscanResult.getScanRecord().getManufacturerSpecificData()すると、先頭の2byte(温度)を企業の識別子として勝手にKeyValueにされてしまうので嬉しくなかった。

Manufacturer Specificのフォーマット。

0-1: temp
2-3: hum
4: 外部温度センサーが接続されているか
5-6: ?
7: battery
8: ?

実際の値。

A308 CC10 002F 8664 08

ServiceとCharacteristic

Service: 00001800-0000-1000-8000-00805f9b34fb
Service: 00001801-0000-1000-8000-00805f9b34fb
Service: 0000180a-0000-1000-8000-00805f9b34fb
Service: 0000fff0-0000-1000-8000-00805f9b34fb
 Characteristic: 0000fff1-0000-1000-8000-00805f9b34fb ←デバイスの設定(RW)
 Characteristic: 0000fff2-0000-1000-8000-00805f9b34fb ←リアルタイムデータ(R)
 Characteristic: 0000fff3-0000-1000-8000-00805f9b34fb ←?(RW)
 Characteristic: 0000fff4-0000-1000-8000-00805f9b34fb ←?(R)
 Characteristic: 0000fff5-0000-1000-8000-00805f9b34fb ←?(R)
 Characteristic: 0000fff6-0000-1000-8000-00805f9b34fb ←通知(N)
 Characteristic: 0000fff7-0000-1000-8000-00805f9b34fb ←?(RW)
 Characteristic: 0000fff8-0000-1000-8000-00805f9b34fb ←履歴取得(RW)
 Characteristic: 0000fff9-0000-1000-8000-00805f9b34fb ←履歴削除(W)

0000fff1 デバイスの設定

更新する時はreadで取得できるものと同じフォーマットのbyte配列を書き込む。

0: ?
1-2: 内部温度センサーの補正値、摂氏の100倍のshort値
3-4: 外部温度センサーの補正値、摂氏の100倍のshort値
5-6: 内部湿度センサーの補正値、100倍のshort値
7-8: 記録する間隔、秒数
9-10: ?
11: 温度計のメジャーバージョン、ASCII code
12: ?
13: 温度計のマイナーバージョン、ASCII code
14-19: ?

実際の値。

0064 002C 01C8 003C 0000 0032 2D30 963D 0000 0000

0000fff8 履歴取得、0000fff9 履歴削除

valueがコマンドみたいな感じで1byteだけ書き込む。
書き込むとonCharacteristicChangedでなんやかんや取れる。

0000fff8
 0x01: temp content
 0x02: temp header
 0x03: hum content
 0x04: hum header
 0x07: temp content crc
 0x08: hum content crc

0000fff9
 0x01: 履歴削除

温度計の時間

温度計本体はデータを記録した時間を保持していない。

データを記録した時間は、スマホ側でスマホの日時を使ってデータのindexから相対的に計算してる。
こんな感じ。

記録した時間 = スマホのunixtime - ((温度計の内部データ.length - 1 - i) * 温度計の内部interval)

じゃあ電池抜いたらどうなるのか?とやってみたら案の定ズレた。
整合性を考えるなら、一旦電池抜いたら履歴が全部消えるのが理想だなとは思う。

問題点。
・電池を抜いたら、抜いていた時間分ズレる。(電池を抜いていた/電池が切れていたことを検知出来ない)
・平常時から最大でinterval秒ズレるので日時をキーにしづらい。

せめて前回記録したのが何秒前なのかってデータがあればまぁまぁの精度で日時を一致させられるのになぁと。