LoginSignup
4

More than 1 year has passed since last update.

SwitchBot温湿度計の値を、WindowsでC#でBLEで直接受信する

Last updated at Posted at 2021-10-06

この記事は、

  • 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公式のドキュメント

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4