この記事は、
- SwitchBot温湿度計(SwitchBotMeter)の値を、
- Windows10以降で、
- C#(.Net5.0以降)で、
- BluetoothLEのAdvertisementを受信して直接読み込む
方法に関するものです。
Windows10以外では動かないし、SwitchBot以外の温湿度計では使えません。
Hubのシステムが変わったり、温度計のファームウェアが更新したりして、記事の内容が古いです。
パケットをフィルタする部分を書き直さないと、動かなくなりました。
一旦、新しいファームウェアでも動くように修正しましたが、後で新しい記事にするかも。
記事を書いたときの温湿度計のファームウェア→v2.6
記事修正時点のファームウェア→v2.7
はじめに
SwitchBotの温湿度計の値を、Hubを介して、WEBから取得する方法はある。
しかし、Hubを介すと、30分くらい間隔でしか取得できない。(現在はもっと短いスパンでできるかも。)
BLEで直接取得したい。
受信する手順
C#でBLEのクラスを使えるようにする
WindowsでBLEを使うには、Windowsが提供するAPIを使うのがよいでしょう。C#でも、そのAPIを使うためのクラスが提供されています。
しかし、.Net5.0はクロスプラットフォームなので、そのままではWindowsAPIを使ったBLEのクラスにアクセスできません。実行環境をWindowsに限定することで、そのクラスにアクセス可能になります。
実行環境を限定するには、TFM(ターゲットフレームワークモニカー)を変更します。
TFMを変更する
プロジェクトファイルを直接編集して、TFMを書き換えます。
(VisualStudio2022では、TFMの変更が、GUIでできるようになっています。プロジェクトのプロパティを開いて、ターゲットOSとかターゲットOSバージョンとかを変えると便利。)
プロジェクトファイル内の、
<TargetFramework>net5.0</TargetFramework>
とか書いてあるのが、TFMです。Windows10に限定するにはこう↓
<TargetFramework>net5.0-windows10.0.17763.0</TargetFramework>
これで、BLEのクラスにアクセス可能になります。
Advertisementパケットを受信する
あとはプログラムを書くだけ。
温湿度計は、温湿度情報をアドバタイズでブロードキャストしてるので、それを受信します。
BLEのアドバタイズパケットを受信するには、BluetoothLEAdvertisementWatcher
というクラスを使います。
_watcher = new BluetoothLEAdvertisementWatcher();
_watcher.Received += OnReceived;
_watcher.ScanningMode = BluetoothLEScanningMode.Active;
//_watcher.AdvertisementFilter.Advertisement.ServiceUuids.Add(new Guid("cba20d00-224d-11e6-9fb8-0002a5d5c51b"));
// ↑ServiceUuidが無くなったため、これでフィルタ出来なくなった
using var dataWriter = new DataWriter();
//dataWriter.WriteBytes(new byte[] { 0x00, 0x0d, 0x54 });
// ↑おまじないが変わった↓
dataWriter.WriteBytes(new byte[] { 0x3d, 0xfd, 0x54 });
// ↓温湿度計プラスを使う場合はこっち
//dataWriter.WriteBytes(new byte[] { 0x3d, 0xfd, 0x69 });
_watcher.AdvertisementFilter.Advertisement.DataSections.Add(new BluetoothLEAdvertisementDataSection(0x16, dataWriter.DetachBuffer()));
_watcher.Start();
ポイント
- アクティブスキャンモードにする
- ベンダーデータとかは常にブロードキャストしているんですが、温湿度情報まで常にしているわけではありません。BLEは、アクティブスキャンすることでブロードキャストの追加データをゲットできます。その中に温湿度情報があります。
-
ServiceUuidでフィルタリングするSwitchBotの、データのサービスIDはcba20d00-224d-11e6-9fb8-0002a5d5c51b
です。これでフィルタリングしておかないと、関係ないデータがどしどし来ます。- ServiceUuidが送信されなくなったので、これでフィルタ出来なくなりました。
- データの先頭の値でフィルタリングする
- 温湿度計のデータは、
0x16
のセクションで提供され、(おまじないが変わりました。0x000d54
で始まります。0x000d
はおまじない。0x3dfd54
で始まります。)0x54
は温湿度計を表します。これで温湿度計のデータだけゲットできます。 - 温湿度計プラスの場合は、
0x3dfd69
で始まります。普通の温湿度計と違うので注意。
- 温湿度計のデータは、
受信したパケットから、データを取り出す
private void OnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
var section = args.Advertisement.GetSectionsByType(0x16)[0];
var buffer = ArrayPool<byte>.Shared.Rent(8);
section.Data.CopyTo(buffer);
var temperature = (buffer[6] & 0x7f) + (buffer[5] & 0x0f) * 0.1f;
if ((buffer[6] & 0x80) == 0) temperature *= -1;
var humidity = buffer[7] & 0x7f;
ArrayPool<byte>.Shared.Return(buffer);
StatusChanged?.Invoke(args.BluetoothAddress, args.Timestamp, temperature, humidity);
}
ポイント
受信したデータの先頭に2バイト、0x000dがくっついているので無視しましょう。- 受信したデータの先頭に2バイト、0x3dfdがくっついているので無視しましょう。
- 受信したデータの中に、温湿度情報がバラバラに格納されています。公式のドキュメントを参考に、集めましょう。
- バッテリー残量も入っています。
- 氷点下のところで計測したことないので、氷点下の計算方法が合ってるのかどうか自信ない。
まとめ
SwitchBot温湿度計のデータを、Hubを介さず直接BLEで受信してみた。
2秒間隔でアドバタイズパケット送ってるみたいだけど、温湿度計とPCをかなり近づけないと、普通に1分間隔くらいになる。
でも30分間隔よりははるかに良い。
参考
SwitchBot公式のドキュメント