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);
}
こういうの地味にハマるんだよなぁ、という感じで終わりです。