ダイソー BLE リモートシャッター で SwitchBot を操る ~ NimBLE バージョン~

 平成の時代に
wakwak-koba.hatenadiary.jp
という記事を書きました。
 書いたこともすっかり忘れかけていましたが、最近になって、この記事をご覧になった方から


というリプライを頂き思い出しました。


 この記事で参照してるリポジトリを消してしまったではないか!


 いやぁ、ESP32_BLE_Arduino(のお守りをしてるコミッター)があまりにポンコツすぎて愛想が尽きたんですよ。
 細かい話は気が向いたらするとして、あれはオワコンです。


 その代替えというか救世主というか、そんな立ち位置のところに NimBLE-Arduino なるものが爆誕しました。
 arduino_esp32 の次か次の次くらいのメジャーアップデートで ESP32_BLE_Arduino は追放され、NimBLE-Arduino に置き換わることはほぼ間違いないです。


 ということで、2年も前に書いた「ダイソー BLE リモートシャッター で SwitchBot を操る」のほうも ESP32_BLE_Arduino ではなく NimBLE-Arduino に対応させるべく修正を施すことにいたしました。


http://dl.ftrans.etr.jp/?eac9464fe8764c31be87d1af847d74b3073a769b.jpg


 導入する NimBLE-Arduino ですが、今回もまた 本家 をベースに私のほうで修正を加えており、そちらを使っていただきます。
https://github.com/wakwak-koba/NimBLE-Arduino/tree/developgithub.com


 メインのスケッチは以下のとおり。

//#include "BLEDevice.h"
#include <NimBLEDevice.h>

static BLEUUID UUID_ABSHUTTER((uint16_t)0x1812);
static BLEUUID UUID_SWITCHBOT("cba20d00-224d-11e6-9fb8-0002a5d5c51b");
static BLEUUID CHAR_SWITCHBOT("cba20002-224d-11e6-9fb8-0002a5d5c51b");

static BLEClient* BLEC_ABSHUTTER = NULL;
static BLEClient* BLEC_SWITCHBOT = NULL;

static uint16_t clicked_button = 0;

class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
  void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
    if (advertisedDevice->haveServiceUUID()) {
      if(advertisedDevice->getServiceUUID().equals(UUID_ABSHUTTER))  {
        BLEC_ABSHUTTER = BLEDevice::createClient(advertisedDevice->getAddress());
        Serial.print("registered:");
      } else if(advertisedDevice->getServiceUUID().equals(UUID_SWITCHBOT))  {
        BLEC_SWITCHBOT = BLEDevice::createClient(advertisedDevice->getAddress());
        Serial.print("registered:");
      } else
        Serial.print("           ");
        
      Serial.printf("%s %s", advertisedDevice->getServiceUUID().toString().c_str(), advertisedDevice->getName().c_str());
      Serial.println();

      if(BLEC_ABSHUTTER && BLEC_SWITCHBOT)
        advertisedDevice->getScan()->stop();
    }
  }
};

static void notifyCallback(BLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify)
{
  if(length == 2 && !clicked_button)
      clicked_button = pData[0] << 8 | pData[1];
}

void setup() {
  Serial.begin(115200);
  BLEDevice::init("");

  auto pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);  
  pBLEScan->start(30);
}

void loop() {
  if(BLEC_ABSHUTTER && !BLEC_ABSHUTTER->isConnected())
    if(BLEC_ABSHUTTER->connect()) {
      Serial.println("connected:ABShutter");
      auto pServices = BLEC_ABSHUTTER->getServices(true);      
      for(auto pService : *pServices)
      {
        auto pCharacteristics = pService->getCharacteristics(true);
        for(auto pCharacteristic : *pCharacteristics)
          if(pCharacteristic->canNotify())
            pCharacteristic->registerForNotify(notifyCallback);
      }
    }

  if(BLEC_SWITCHBOT && !BLEC_SWITCHBOT->isConnected() && BLEC_ABSHUTTER && BLEC_ABSHUTTER->isConnected())
  {
      BLEC_SWITCHBOT->connect();
      Serial.println("connected:SwitchBot");
  }
  
  if(BLEC_SWITCHBOT && BLEC_SWITCHBOT->isConnected() && clicked_button)
  {
    Serial.printf("button pressed:%04x", clicked_button);
    Serial.println();
    uint8_t buf[] = {0x57, 0x01, 0x00};
    switch(clicked_button)  {
      case 0x0100:  // Volume Up
        buf[2] = 0x03;
        break;
      case 0x0200:  // Volume Down      
      case 0x0028:  // Enter
        buf[2] = 0x04;
        break;
    }
    BLEC_SWITCHBOT->getService(UUID_SWITCHBOT)->setValue(CHAR_SWITCHBOT, std::string((char *)buf, sizeof(buf)));
    clicked_button = 0;
  }
}