プログラミング

SwitchBotの温湿度計、防水かどうかでBluetoothのデータの取り方違うぞ

投稿日:

SwitchBotは機器のAPIを公開していて、ユーザーの自作プログラムからBluetooth(BLE)越しにデータが取れたりします。
特に温湿度計のデータを取りたいというニーズは強くて、安価で安定していてバッテリーの持ちが良いということで重宝されてます。

さて、通常の温湿度計については、以下のようなコード(M5 Stack想定)でデータが取れるんですが。かなり省略したので詳しくは先人の知恵を参照ください。
batteryとtemperatureとhumidityに値が入ります。

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

/* グローバル変数宣言 */
BLEScan *pBLEScan;
static const String TargetMacAddr = "ab:cd:ef:01:23:45";

/* 初期化処理内 */
pBLEScan = BLEDevice::getScan();
pBLEScan->setInterval(1000);
pBLEScan->setWindow(1000);
pBLEScan->setActiveScan(true);

/* ループ内 */
BLEScanResults foundDevices = pBLEScan->start(1, false);
uint32_t dev_count = foundDevices.getCount();
for (uint32_t iDevNo = 0; iDevNo < dev_count; iDevNo++)
{
  BLEAdvertisedDevice device = foundDevices.getDevice(iDevNo);
  BLEAddress address = device.getAddress();
  if (TargetMacAddr.compareTo(address.toString().c_str()) == 0)
  {
    std::string s = device.getServiceData();
    const char* data = s.c_str();
    int8_t battery = data[2] & 0b01111111;
    bool tempSign = data[4] & 0b10000000;
    float temperature = ( data[3] & 0b00001111 ) / 10.0 + ( data[4] & 0b01111111 );
    if (!tempSign)
    {
      temperature *= -1;
    }
    float humidity = (float)((int8_t)(data[5] & 0b01111111) * 1.0);
  }
}

防水温湿度計はデータの配置が変わってまして、元々はService Dataだけで全部取れていたものが、Manufacturer Specific Dataも取らないといけなくなってます。
詳しくはAPIの公式ドキュメントにありますが、
Manufacturer Specific Dataの10,11,12バイト目にデータが動いています。
上記のコードでいうとif文内を以下のように書き換える必要があります。

  if (TargetMacAddr.compareTo(address.toString().c_str()) == 0)
  {
    std::string s = device.getServiceData();
    const char* data = s.c_str();
    int8_t battery = data[5] & 0b01111111;
    s = device.getManufacturerData();
    data = s.c_str();
    bool tempSign = data[11] & 0b10000000;
    float temperature = ( data[10] & 0b00001111 ) / 10.0 + ( data[11] & 0b01111111 );
    if (!tempSign)
    {
      temperature *= -1;
    }
    float humidity = (float)((int8_t)(data[12] & 0b01111111) * 1.0);
  }

こういうの地味にハマるんだよなぁ、という感じで終わりです。

-プログラミング

執筆者:

関連記事

no image

BlueskyのAPI制限が厳しくなったぞ

以前、Blueskyのbotを作る記事を書いたんですが、そのbotがいつの間にかひどくエラーを吐くようになっていました。 で、調べたところ、API制限が厳しくなっていると。 詳しく言うと、Rate L …

GeoJSONで市町村境界をマージして都道府県境界にしたい(その2)

GeoJSONのPolygonをマージしたい第2回です。 前回、純粋な多角形の統合ではなくて、領域が被らない多角形の統合になるのでグラフ問題として解くことができるという説明をしました。 今回はどうやっ …

SHOWROOMのガチイベをGoogleスプレッドシートでグラフにしよう

もくじ1 まえがき2 みほん3 だいじな注意事項3.1 Google Apps Scriptの制限3.2 SHOWROOMの仕様4 てじゅん4.0.1 1.4.0.2 2.4.0.3 3.4.0.4 …

GeoJSONで市町村境界をマージして都道府県境界にしたい(その1)

前回の続きで、国土地理院の「国土数値情報」っていうオープンデータで遊んでいます。独立した記事なので前回のは読まなくても良いです。 もくじ1 やりたいこと2 問題の整理3 「穴」の考慮4 つづく やりた …

no image

例え話をしないC言語のポインタの説明

もくじ1 まえおき2 Hello, Worldより簡単に2.1 サンプルコード2.2 変数の置き場所2.3 変数が入っているところを見てみる3 C言語とメモリ3.1 変数cの「まわり」を見てみる3.2 …