SwitchBot温湿度計のデータをM5StickC(ESP32)+Arduinoで取得する


この小さいBLE温湿度計がBLEでデータが取れて電池もよく持つし安い!ということなので試しに買ってみました。

しかも、いまAmazonでセール中だということなので今すぐ買おう→→→→ https://amzn.to/2YFaSYx

M5StickC+Arduinoでデータが取れました、のところまで。

SwitchBotBleReader.ino.c
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

int scanTime = 5; //In seconds
BLEScan* pBLEScan;

//BLEAddress addr01       = BLEAddress("xx:xx:xx:xx:xx:xx");
//BLEAddress addr02       = BLEAddress("yy:yy:yy:yy:yy:yy");
BLEUUID serviceUUID     = BLEUUID("cba20d00-224d-11e6-9fb8-0002a5d5c51b");
BLEUUID serviceDataUUID = BLEUUID("00000d00-0000-1000-8000-00805f9b34fb");

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      /*
      if(advertisedDevice.getAddress().equals(addr01) || advertisedDevice.getAddress().equals(addr02)){
        // OK
      }else{
        return;
      }
      printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
      */
      if(!advertisedDevice.haveServiceUUID()) return;
      if(!advertisedDevice.getServiceUUID().equals(serviceUUID)) return;
      printf("SwitchBot Meter!\n");

      if(!advertisedDevice.haveServiceData()) return;
      printf("ServiceDataUUID=%s\n", advertisedDevice.getServiceDataUUID().toString().c_str());
      std::string s = advertisedDevice.getServiceData();
      printf("ServiceData len=%d [", s.length());
      for(int i=0; i<s.length(); i++){
        printf("%02X ", s.c_str()[i]);
      }
      printf("]\n");
      if(!advertisedDevice.getServiceDataUUID().equals(serviceDataUUID)) return;

      const char* servicedata = s.c_str();
      int battery = servicedata[2] & 0b01111111;
      bool isTemperatureAboveFreezing = servicedata[4] & 0b10000000;
      float temperature = ( servicedata[3] & 0b00001111 ) / 10.0 + ( servicedata[4] & 0b01111111 );
      if(!isTemperatureAboveFreezing){
        temperature = -temperature;
      }
      int humidity = servicedata[5] & 0b01111111;

      bool isEncrypted            = ( servicedata[0] & 0b10000000 ) >> 7;
      bool isDualStateMode        = ( servicedata[1] & 0b10000000 ) >> 7;
      bool isStatusOff            = ( servicedata[1] & 0b01000000 ) >> 6;
      bool isTemperatureHighAlert = ( servicedata[3] & 0b10000000 ) >> 7;
      bool isTemperatureLowAlert  = ( servicedata[3] & 0b01000000 ) >> 6;
      bool isHumidityHighAlert    = ( servicedata[3] & 0b00100000 ) >> 5;
      bool isHumidityLowAlert     = ( servicedata[3] & 0b00010000 ) >> 4;
      bool isTemperatureUnitF     = ( servicedata[5] & 0b10000000 ) >> 7;

      printf("----\n");
      printf("address:     %s\n",   advertisedDevice.getAddress().toString().c_str());
      printf("battery:     %d\n",   battery);
      printf("temperature: %.1f\n", temperature);
      printf("humidity:    %d\n",   humidity);
      printf("\n");
      printf("isEncrypted:            %d\n", isEncrypted);
      printf("isDualStateMode:        %d\n", isDualStateMode);
      printf("isStatusOff:            %d\n", isStatusOff);
      printf("isTemperatureHighAlert: %d\n", isTemperatureHighAlert);
      printf("isTemperatureLowAlert:  %d\n", isTemperatureLowAlert);
      printf("isHumidityHighAlert:    %d\n", isHumidityHighAlert);
      printf("isHumidityLowAlert:     %d\n", isHumidityLowAlert);
      printf("isTemperatureUnitF:     %d\n", isTemperatureUnitF);
      printf("----\n");
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true);
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
//  Serial.print("Devices found: ");
//  Serial.println(foundDevices.getCount());
//  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

データフォーマットはこちらの記事が詳しいです
https://qiita.com/warpzone/items/11ec9bef21f5b965bce3

参考ツイート
https://twitter.com/urekat/status/1272349274173407235