プログラミング

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

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

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

no image

Google Apps Script(GAS)で自宅サーバーの死活監視をする

前置き 自宅サーバー使ってますか? 最近もう流行らないかな、と思ったらRaspberry Piの流行で機器も電気代も安価に組めるようになったりして、地味に持っている人も多いんじゃないかな、と思ってます …

no image

ロリポップでSQLite3を使うときはpythonでpysqlite3-binaryだ

このブログはロリポップで運用しています。 公式にSQLite3の使用も許可されていて、モジュール叩けば動くんですがいかんせんバージョンが低い。 確認するとバージョンが3.7.17。なかなかに古いです。 …

no image

Unityでメッシュをさわるノウハウ

ヒマなので覚書。ウラを取っていない経験則なので話半分で読んでください。 あと、3Dの基本概念とUnity固有の話の区別が付いていないのでごめんなさい。 もくじ Meshクラスの基本 Unityでポリゴ …

no image

ランダムな日本人データを生成するツールをつくった

前置き ダミーの名簿データが作りたい、という需要は稀にあるものです。 住所とか、年齢とか、職業とか、いい感じにランダムなデータが欲しいことがありますよね。 しかし、適当にデータを作ってしまうと、「東京 …