Top View


Author Yuhei Okazaki

SwitchBotをM5Stackで制御してレトロフィットな制御を実現する

2020/04/02

IoTにおける"制御"は難しい

例えば、弊社オフィスのエアコンをIoT化したいとします。

温度が高いときは自動的にエアコンをOFFに、低いときは自動的にエアコンをONにする簡単なシステムです。この場合、温度は温度センサーを使うことで計測ができます。

一方、エアコンのON/OFFはどのように実現できるでしょうか?ちなみに、弊社のエアコンはこのようなコントローラからしか制御できません。赤外線リモコンもありません。

エアコンのコントローラ

SwitchBotで「スイッチを押す」を実現する

そんな時に役立つのがSwitchBotです。この製品は粘着テープでスイッチに設置して使います。

スマホアプリからスイッチを押すと...

SwitchBotの動き

このようにスイッチを押してくれます。

AlexaやIFTTTとも連携可能なので、これだけで簡単なIoTシステムを実現できます。

SwitchBotをM5Stackで制御する

SwitchBotをオフィスのあらゆるスイッチに設置する場合、1台1台スマホアプリと連携するのは手間です。また、連携できるサービスも限られるので、少々不便です。

そこで、M5Stackを使ってスマホアプリを使わずにSwitchBotを制御してみることにしました。

M5Stack

SwitchBotはBLEで制御できる

SwitchBotとスマホアプリはBLEで通信しています。GithubにPythonのライブラリが公開されているので、これを読んで通信部分の仕様を理解します。

SwitchBotがBLEのAdvertiseをしているのでそれをスキャンして、 CBA20002-224D-11E6-9FB8-0002A5D5C51B というCharacteristicに 570100 というコマンドを書き込むことで制御できるようです。

最終的にM5Stackのプログラムは以下となりました。

#include "BLEDevice.h"
#include "Free_Fonts.h"
#include <M5Stack.h>
 
static BLEUUID serviceUUID("CBA20D00-224D-11E6-9FB8-0002A5D5C51B");
static BLEUUID characteristicUUID("CBA20002-224D-11E6-9FB8-0002A5D5C51B");
 
static BLEAdvertisedDevice* myDevice;
static uint8_t cmdPress[3] = {0x57, 0x01, 0x00};
 
void pressSwitchBot() {
  BLEClient*  pClient  = BLEDevice::createClient();

  M5.Lcd.fillScreen(TFT_RED);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_RED);
  M5.Lcd.drawString("Connecting...", 160, 120, GFXFF);
  
  pClient->connect(myDevice);

  BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
  if (pRemoteService == nullptr) {
    pClient->disconnect();
    return;
  }
 
  BLERemoteCharacteristic* pCharacteristic = pRemoteService->getCharacteristic(characteristicUUID);
  if (pCharacteristic == nullptr) {
    pClient->disconnect();
    return;
  }
  
  pCharacteristic->writeValue(cmdPress, sizeof(cmdPress), false);

  pClient->disconnect();
  
  M5.Lcd.fillScreen(TFT_BLUE);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLUE);
  M5.Lcd.drawString("Pressed.", 160, 120, GFXFF);

  delay(2000);

  M5.Lcd.fillScreen(TFT_GREEN);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_GREEN);
  M5.Lcd.drawString("Push button.", 160, 120, GFXFF);
}
 
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
        BLEDevice::getScan()->stop();
        myDevice = new BLEAdvertisedDevice(advertisedDevice);
      }
    }
};
 
void setup() {
  M5.begin();
  M5.Power.begin();
  M5.Lcd.setTextDatum(MC_DATUM);
  M5.Lcd.setFreeFont(FF44);

  M5.Lcd.fillScreen(TFT_RED);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_RED);
  M5.Lcd.drawString("Searching...", 160, 120, GFXFF);
  
  BLEDevice::init("");
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);

  M5.Lcd.fillScreen(TFT_GREEN);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_GREEN);
  M5.Lcd.drawString("Push button.", 160, 120, GFXFF);
}
 
void loop() {
  if (myDevice == NULL) {
    return;
  }
  
  M5.update();
  if (M5.BtnA.wasReleased()) {
    pressSwitchBot();
  }
}

SwitchBotをM5Stackから制御

M5StackのAボタン(一番左のボタン)を押してみます。

M5StackでSwitchBotを制御

SwitchBotが動きました!!!

まとめ

M5StackからSwitchBotを制御できたことで、IoTシステムにレトロフィットな制御を簡単に組み込めます。例えばこんな活用方法が想定されます。

  • Alexaと連携してオフィスの照明や空調を一斉にON/OFFしたい
  • 会議室に人が入退出したタイミングで、照明をON/OFFしたい
  • Webアプリやモバイルアプリでスイッチ付きのデバイスをON/OFFしたい

みなさんもぜひお試しください。

Yuhei Okazaki

Yuhei Okazaki

Twitter X

2018年の年明けに組込み畑からやってきた、2児の父 兼 Webエンジニアです。 mockmockの開発・運用を担当しており、組込みエンジニア時代の経験を活かしてデバイスをプログラミングしたり、簡易的なIoTシステムを作ったりしています。主な開発言語はRuby、時々Go。