Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

ESP32開発ボードでSwitchbot温湿度計のデータを取得する

これまではラズパイで2台のSwitchbot温湿度計のデータを取得していたのですが(Switchbot温度計とラズパイで快適IoTライフ - 愛と工作の日々)、より安価で低消費電力のESP32開発ボードの使用を検討しました。開発ボードはESP32-DevKitC-VE ESP32-WROVER-E開発ボードを使用しました。
qiita.com
こちらの記事のコードをchatGPT(GPT-4)の協力の元モディファイしました。

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

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

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

int globalBattery;
float globalTemperature;
int globalHumidity;
bool newDataAvailable = false;
BLEAddress* detectedAddress = nullptr;

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {

      if(advertisedDevice.getAddress().equals(*addr01) || advertisedDevice.getAddress().equals(*addr02)){
        // OK
      } else {
        return;
      }

      if(!advertisedDevice.haveServiceUUID()) return;
      if(!advertisedDevice.getServiceUUID().equals(serviceUUID)) return;

      if(!advertisedDevice.haveServiceData()) return;

      std::string s = advertisedDevice.getServiceData();

      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;

      detectedAddress = new BLEAddress(advertisedDevice.getAddress());
      globalBattery = battery;
      globalTemperature = temperature;
      globalHumidity = humidity;
      newDataAvailable = true;
    }
};

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

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true);
  pBLEScan->setActiveScan(true);
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
}

void loop() {
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  pBLEScan->clearResults();

  if (newDataAvailable) {
    Serial.print("Address: ");
    Serial.println(detectedAddress->toString().c_str());

    Serial.print("Battery: ");
    Serial.print(globalBattery);
    Serial.println("%");

    Serial.print("Temperature: ");
    Serial.print(globalTemperature);
    Serial.println("°C");

    Serial.print("Humidity: ");
    Serial.print(globalHumidity);
    Serial.println("%");

    newDataAvailable = false;
    delete detectedAddress;
    detectedAddress = nullptr;
  }

  delay(2000);
}

このコードをアップロードすると、シリアルモニタに2つの温湿度計のデータが交互に表示されました。