プログラミング

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);
  }

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

-プログラミング

執筆者:

関連記事

【Unity】GPUを使ってパンツを隠すスクリプトができた

かわいいスカートを履きたい!でもパンチラしたくない! それは誰もが抱く夢です。もちろん、3Dモデルだってパンチラしたくないと思っているハズです。 というわけで偉大なる先人がいます。 Unityでパンツ …

no image

プログラミングとアルゴリズムのはなし

みんなー!小学校でプログラミングの授業がはじまるよー!! プログラミングってなんだろう? プログラミングって、コンピューターに「○○をしなさい」って命令して、なにかの問題を解いたり、ゲームをつくったり …

no image

M5StickC Plusの明るさ(M5.Axp.ScreenBreath)、0~100かもしれない

M5StickC Plusで画面の明るさを調整するM5.Axp.ScreenBreath()という関数があります。 日本語リファレンスでは指定値7~12ということになっています。 また、公式ドキュメン …

GeoJSONで市町村境界をマージして都道府県境界にしたい(実践編)

前々回と前回で問題を整理して、ようやく実践編です。 まず実物のリンク貼りましょう。GitHubに上げました。 今回はGo言語で書いてますが、ポイントがいくつかあります。 ちなみに言語としてGoを選択し …

no image

C言語のポインタに関する補足説明

前回、C言語のポインタに関する解説記事を書きまして、そこそこの反響を貰うとともにいくつかの指摘を受けました。 前回の記事では幾つか「ウソではないけど真実と違う」記述がありまして、その点を補足としていく …