知的好奇心 for IoT

IoT関連の知的好奇心を探求するブログです

BlynkのWebHookとIFTTTとスマートプラグで簡単スマートホーム!CO2濃度の上昇を検知して換気扇を動かす!

中華製の2,000円程度で購入できる安価なCO2センサーを前回の記事で使えるようにしたので、応用編としてCO2の濃度によってスマートプラグをコントロールできるようにしてみます。


スマートプラグ

スマートプラグをAmazonで検索すると1個2,000円以下でいろんな種類のものが出てきます。スマートプラグを作っているメーカーは沢山ありますが、小さなメーカーは日本ではソフトバンク C&Sが窓口となって展開している中国の「Tuya Smart」のプラットフォームを使っていることが多くて、「Smart Life」というスマホアプリでコントロールできるようになっているんです。

ぼくはメーカーの違うスマートプラグを3つ持っています。

f:id:IntellectualCuriosity:20200107180345p:plain

全てSmart Lifeアプリに対応していて、Smart Lifeアプリではこんな風に表示されます。

f:id:IntellectualCuriosity:20200107125033p:plain
このアプリの機能だけでも結構スマートなことができるようになっていますが、Smart Lifeアプリは他のサービスと連携して機能を拡張できるようになっています。対応しているサービスの中にIFTTTも含まれていて、IFTTTを介してSmart Lifeアプリに対応していないサービスと連携させることができるようになっています。

f:id:IntellectualCuriosity:20200107125211p:plain
 

IFTTT

IFTTTはサービスとサービスを繋ぐ老舗サービスで使っている方も多いのではないかと思います。

 IFTTTでは「Webhooks」と「Smart Life」のサービスを繋ぎます。

Webhooksサービス

f:id:IntellectualCuriosity:20200107114839j:plain

Smart Lifeサービス

f:id:IntellectualCuriosity:20200107114900p:plain

これらのサービスを使ってCO2濃度が高くなったときに換気扇を回すアプレットと、CO2濃度が下がったときに換気扇を止めるアプレットを作ります。

換気扇を回すアプレット

f:id:IntellectualCuriosity:20200107133124p:plain

これで、Webhooksで「co2_high」イベントを受け取ったら、「WP6ミニスマートプラグ」の電源を入れるという意味になります。

換気扇を止めるアプレット

f:id:IntellectualCuriosity:20200107133552p:plain

同様にこのアプレットは、Webhooksで「co2_low」イベントを受け取ったら、「WP6ミニスマートプラグ」の電源を切るという意味になります。

Webhooksへの「co2_high」と「co2_low」イベントの送り方を知るには、Webhooksの設定画面に表示されるuser_urlをタップします。

f:id:IntellectualCuriosity:20200107135853p:plain

するとブラウザが開いて、Webhooksでリクエストを送信するためのキーとURLが表示されます。

f:id:IntellectualCuriosity:20200107141401p:plain

URLの{event}の部分をイベント名に置き換えると、そのイベント用のリクエストとなります。

「co2_high」イベント用リクエス

https://maker.ifttt.com/trigger/co2_high/with/key/自分のキー

「co2_low」イベント用リクエス

https://maker.ifttt.com/trigger/co2_low/with/key/自分のキー

そして、このリクエストをBlynkのWebHookに設定することで、Blynk経由でスマートプラグに繋いだ換気扇の制御が行えるようになります。

 

Blynkプロジェクト

換気扇の制御を実現するために用意したBlynkプロジェクトはこんな感じです。

f:id:IntellectualCuriosity:20200107153104p:plain

①CO2リアルタイム表示用Gaugeウィジット

f:id:IntellectualCuriosity:20200107153938p:plain

②CO2下限値設定用Step Hウィジット

CO2がここで設定した値以下になると、⑤のCO2_LOW WebHookを呼び出すようにスケッチでプログラミングしています。

f:id:IntellectualCuriosity:20200107155140p:plain

③CO2上限値設定用Step Hウィジット

CO2がここで設定した値以上になると、⑥のCO2_HIGH WebHookを呼び出すようにスケッチでプログラミングしています。

f:id:IntellectualCuriosity:20200107162115p:plain

④CO2値読取エラー表示用LEDウィジット

実際に色々とMH-Z19Bを使っていて気付いたのですが、計測の1発目やキャリブレーションを行った後に読取エラーが起きるんです。また、ときどき電源投入後にずっと読取エラーになることがあったので、読取エラーの状態がわかるようにこのウィジットを付けました。

f:id:IntellectualCuriosity:20200107163222p:plain

⑤「co2_low」イベントリクエスト用WebHookウィジット

IFTTTで設定した「co2_low」イベントリクエストを送信するためのウィジットです。

URLには以下を記述します。

https://maker.ifttt.com/trigger/co2_low/with/key/自分のキー

f:id:IntellectualCuriosity:20200107164549p:plain

⑥「co2_high」イベントリクエスト用WebHookウィジット

IFTTTで設定した「co2_high」イベントリクエストを送信するためのウィジットです。

URLには以下を記述します。

https://maker.ifttt.com/trigger/co2_high/with/key/自分のキー

f:id:IntellectualCuriosity:20200107170039p:plain

キャリブレーション用WebHookウィジット

CO2センサーを400ppmでキャリブレーションするトリガーを送信するためのボタンです。外であれば特殊な状況でない限りどこで実行してもそんなに変わらないと思います。外で実行するときはモバイルバッテリーから電源を取って、スマホテザリングを部屋(CO2センサーの実際の設置場所)と同じ設定にしておくと面倒くさくなくて良いと思います。f:id:IntellectualCuriosity:20200107170600p:plain


Arduinoスケッチ(プログラム)
スケッチはこんな感じです。

CO2の値を読み出す部分以外は小難しいことをしていないので、Blynkプロジェクトで説明した各ウィジットのバーチャルピンがどこで使用されているか見ていくと、プログラムの動きがわかると思います。

※2020年1月19日追加 ボードマネージャーでインストールするESP8266のバージョンを最新の2.6.xにするとセンサーの情報が正常に取得できなくなります。バージョンを2.5.2にすると正常に動作するようになります。

/*
 * Easy smart home CO2 and fan edition
 * January 7, 2020
 * By Hiroyuki ITO
 * http://intellectualcuriosity.hatenablog.com/  
 * MIT Licensed.
 */
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
#include >BlynkSimpleEsp8266.h>
#include >SoftwareSerial.h>

// Blynk Auth Token and WiFi credentials
#define AUTH_TOKEN "YourAuthToken"
#define WIFI_SSID  "YourNetworkName"
#define WIFI_PASS  "YourPassword"

// Define ESP8266 TX RX pin
#define ESP8266_TX 12
#define ESP8266_RX 13

// MH-Z19 Commands
byte cmd_read_co2[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
byte cmd_calibrate_zero[9] = {0xFF,0x01,0x87,0x00,0x00,0x00,0x00,0x00,0x78};
byte cmd_Self_calibration_off[9] = {0xFF,0x01,0x79,0x00,0x00,0x00,0x00,0x00,0x86}; // Self-calibration OFF
byte cmd_Self_calibration_on[9] = {0xFF,0x01,0x79,0xA0,0x00,0x00,0x00,0x00,0x86};  // Self-calibration ON
byte cmd_detection_range_2000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x07,0xD0,0x8F}; // 0~2000ppm
byte cmd_detection_range_5000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x13,0x88,0xCB}; // 0~5000ppm
byte cmd_detection_range_10000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x27,0x10,0x2F}; // 0~10000ppm

// Global Objects
int co2ThresholdHigh;
int co2ThresholdLow;
boolean stateChangeHigh = true; // Control WebHook co2_high
boolean stateChangeLow = true;  // Control WebHook co2_low 
SoftwareSerial co2Serial(ESP8266_RX, ESP8266_TX);
WidgetLED led(V4); // Error status LED
BlynkTimer timer;

/*
 * Requests all stored on the server latest values for all widgets.
 */
BLYNK_CONNECTED() {
    Blynk.syncVirtual(V2, V3);
}

/*
 * Threshold Low
 */
BLYNK_WRITE(V2) {
  co2ThresholdLow = param.asInt();
}

/*
 * Threshold High
 */
BLYNK_WRITE(V3) {
  co2ThresholdHigh = param.asInt();
}

/*
 * Calibration
 */
BLYNK_WRITE(V7) {
  if (param.asInt()) {
    co2Serial.write(cmd_calibrate_zero, 9);
  }
  BLYNK_LOG("Calibrated");
}

/*
 * Send sensor data to Blynk
 */
void sendSensor() {
  // Get data from MH-Z19B sensor
  unsigned char response[9];        // for answer
  co2Serial.write(cmd_read_co2, 9); // request PPM CO2
  co2Serial.readBytes(response, 9);
  if (response[0] == 0xFF && response[1] == 0x86){
    led.off(); // Error status LED
    unsigned int high = (unsigned int) response[2];
    unsigned int low = (unsigned int) response[3];
    int co2 = (256 * high) + low;
    Blynk.virtualWrite(V1, co2);
    BLYNK_LOG2("CO2: ", co2);

    // WebHook
    if (co2 > co2ThresholdHigh) {
      if (stateChangeHigh) {
        Blynk.virtualWrite(V6, co2); // Kick WebHook co2_high
        BLYNK_LOG("Kick WebHook co2_high");
      }
      stateChangeHigh = false;
      stateChangeLow = true;
    } else if (co2 > co2ThresholdLow) {
      if (stateChangeLow) {
        Blynk.virtualWrite(V5, co2); // Kick WebHook co2_low
        BLYNK_LOG("Kick WebHook co2_low");
      }
      stateChangeHigh = true;
      stateChangeLow = false;
    }
  } else {
    led.on(); // Error status LED
    BLYNK_LOG("CO2: read error");
  }
}

void setup() {
  Serial.begin(74880);
  co2Serial.begin(9600);

  // Initialize MH-Z19
  co2Serial.write(cmd_Self_calibration_off, 9);
  co2Serial.write(cmd_detection_range_2000, 9);

  // Initialize Blynk
  Blynk.begin(AUTH_TOKEN, WIFI_SSID, WIFI_PASS);

  // Initialize BlynkTimer
  timer.setInterval(2000, sendSensor); // every 2 seconds
}

void loop() {
  Blynk.run();
  timer.run();
}

 

おしまい