知的好奇心 for IoT

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

ATOM Socket KitとBlynkで洗濯機や乾燥機の動作状況が見れて終了を通知してくれるシステムがお手軽に作れるようになった

シェアハウスに住んでいるぼくにとって、洗濯物放置問題の解決はライフワークみたいになっていて、これまでいくつかシステムを作って来ました。

しかし、どれも一般の人が作るにはハードルが高い部分が存在していて、もっと簡単に作ることができないかずっと考え続けていたんです。

 

ATOM Socket Kit

最近、M5Stack社の製品を使うことが多くなったこともあって、ちょくちょくオフィシャルサイトを覗きに行っていたら、ある日、いいものがラインナップに追加されていました。

ATOM Socket Kit (HLW8023) - JP&US

f:id:IntellectualCuriosity:20210603170444j:plain

パッと見、ごついテーブルタップにAtom Liteをくっ付けた感じですよね。

5年くらい前からスマートプラグを見かけるようになりましたが、今までプログラマブルな製品は無かったので、見た瞬間、これだ!って思いました。

 

到着までの長い日々

M5Stack社は中国の深圳にある会社で、オフィシャルサイトでオーダーすると会社の所在地辺りから発送されるようです。

配送手段にDHLを使えば早いのはわかっていますが、$22.90の商品に$23.53の送料は払えないですよね!

f:id:IntellectualCuriosity:20210603173019j:plain

以前からAliExpressなどで中国から発送される商品を購入していて、郵便でも10日から15日ぐらいで届いていたのでその感覚で「Post Air Mail」で注文しました。

しかし、今回は注文してから到着するのに24日かかりました。

f:id:IntellectualCuriosity:20210604135729j:plain

ラッキングナンバーの末尾の2桁は発送国を示していて、日本だとJPで中国だとCNなのですが、今回のトラッキングナンバーはシンガポールを示すSGになっています。

いつもそうなのかはわかりませんが、4PXが中国からシンガポールまで運んで、シンガポールで郵便として出されていた感じです。

当分の間は商品が届くまでこのくらいの時間がかかる覚悟をした方が良さそうです。

 

Blynkの動作画面と注意点

この画面は動作テスト用の画面で、シェアハウスや寮に住んでいる人に公開するウィジットに加えて、洗濯機や乾燥機の動作状況を表示するTerminalウィジットとTerminalウィジットの表示内容を消去するButtonウィジットが追加されています。

f:id:IntellectualCuriosity:20210604192422j:plain

洗濯が終了するとBlynkアプリの通知機能を使って知らせてくれます。

f:id:IntellectualCuriosity:20210604193930j:plain

 

乾燥機に使うときには注意が必要! 

ATOM Socket Kitの定格電流は10Aですが、大抵の乾燥機は10Aを超える電流が流れる動作モードを持っています。

今住んでいるシェアハウスには日立のDE-N40WXという衣類乾燥機が置いてあって、仕様を見ると「消費電力 強:1,180W 弱:710W 」と書いてあります。

日本は電圧が100Vなので、強の1,180Wだと11.8A、弱の710Wだと7.1A電流が流れることになり、「強」だとATOM Socket Kitの定格電流をオーバーしてしまいます。

そのため、いろんな人がいるシェアハウスや寮では15Aに対応したATOM Socket Kitが出るまで、乾燥機に使うのは止めた方がいいと思います。

 

Blynkの設定とプロジェクトの共有方法

各ウィジットの設定 

 Image Galleryウィジット(洗濯機や乾燥機の動作状況表示用)

f:id:IntellectualCuriosity:20210604204304j:plain

ON・OFFなどの動作状況を知らせるウィジットには「LEDウィジット」がありますが、「LEDウィジット」はOFF状態の時に本当に何も表示されないので不特定多数の人に使ってもらうにはわかり難いと感じたため、今回初めて「Image Galleryウィジット」を使ってみました。

機器のOFF状態とON状態のイメージを作って直リン可能なサイトにアップロードし、「1」が指定されたときにOFFの画像、「2」が指定されたときにONの画像が表示されるようにしています。

 

Notificationウィジット(機器の終了通知用)

f:id:IntellectualCuriosity:20210604205710j:plain

このウィジットをプロジェクトに配置することで、通知が表示されるようになります。

 

次の2つは動作テスト用で、動作が確認できたら削除します。

Terminalウィジット(動作状況確認用)

f:id:IntellectualCuriosity:20210604223807j:plain

 

Buttonウィジット(Terminal表示の消去用)

f:id:IntellectualCuriosity:20210604225115j:plain

 

複数のデバイスマイコン)を使えるようにするには

Blynkのプロジェクトには複数のデバイスマイコン)を割り当てることができるようになっています。

まずは、プロジェクトをウィジットが配置できる状態にして(止めて)、ナットのようなアイコンをタップします。

f:id:IntellectualCuriosity:20210604232304j:plain

Project Settingsで「DEVICES」をタップします。

f:id:IntellectualCuriosity:20210604233144j:plain

「+ New Device」をタップすると、デバイスマイコン)をプロジェクトに追加することができます。(下図は既に乾燥機を追加しています。)

f:id:IntellectualCuriosity:20210604233522j:plain

 

プロジェクトの共有方法

まずは、プロジェクトをウィジットが配置できる状態にして(止めて)、ナットのようなアイコンをタップします。

f:id:IntellectualCuriosity:20210604232304j:plain

Project Settingsを表示して、「SHARED ACCESS」のスイッチを「ON」にします。

f:id:IntellectualCuriosity:20210604234840j:plain

「Generate Link」をタップするとプロジェクト共有用のQRコードが表示されます。

f:id:IntellectualCuriosity:20210605002326j:plain

このQRコードをBlynkアプリのログイン画面に表示されているQRコードアイコンをタップしてスキャンすると、共有したプロジェクトを表示することができます。

f:id:IntellectualCuriosity:20210605003309j:plain

 

プログラム

プログラムは洗濯機と乾燥機で共通になっています。

9行目の「電源OFF通知メッセージ」を繋げる機器に応じて変更してください。

#include <M5Atom.h>             // M5 Atomライブラリ
#define BLYNK_PRINT Serial      // コメントにするとBlynkのログが出力されなくなります
#include <BlynkSimpleEsp32.h>   // Blynkライブラリ

#define AUTH_TOKEN  "この文字列をメールで通知されたAuth Tokenと置き換えます"
#define WIFI_SSID   "この文字列をWiFiSSIDで置き換えます"
#define WIFI_PASS   "この文字列をWiFiのパスワードで置き換えます"

#define NOTIFY_MSG    "洗濯が終わりました!" // 電源OFF通知メッセージ
#define POWER_ON_CNT  6         // 電源ONのカウント数下限値
#define POWER_OFF_CNT 78        // 電源OFFのカウント数下限値
#define POWER_LIMIT   1.0       // カウントする上限値(W)

BlynkTimer Timer;               // Blynkタイマー用オブジェクト
WidgetTerminal Terminal(V2);    // Terminalウィジットオブジェクト
int count = 0;                  // 電源状態カウンター
bool flag_power;                // 電源状態フラグ ON:true OFF:false
bool flag_first = true;         // 初回フラグ
float max_current = 0.0;        // 電流最大値
float max_power = 0.0;          // 電力最大値

// ターミナル消去ボタン
BLYNK_WRITE(V3) {
  if (param.asInt()) {
    Terminal.clear();           // Terminal消去
  }
}

// HLW8032(エネルギー計測IC)の生データ取得用変数
uint32_t CurrentPar;    
uint32_t CurrentData;     
uint32_t powerPar;
uint32_t powerData;
byte buff[24];

// 電流を取得する(A)
float getCurrent() {
  return (float)CurrentPar / (float)CurrentData;
}

// 電力を取得する(W)
float getPower() {
  return (float)powerPar / (float)powerData * 1.88;
}

// HLW8032のデータのチェックサムを計算する
bool checksum() {
  byte sum = 0;
  for (int i=2; i<=22; i++) {
    sum += buff[i];             // 3Byte目から23Byte目までを足す
  }
  if (sum == buff[23]) {
    return true;                // 足した値が24Byte目と同じ場合
  } else {
    return false;
  }
}

// HLW8032(エネルギー計測IC)のデータ取得
bool serialReadLoop() {
  bool ret = false;
  if (Serial2.available() > 0) {     // HLW8032からのデータがあるとき
    delay(55);                       // 55ms待つ
    if (Serial2.available() == 24) { // データサイズが24バイトのとき
      for (int i=0; i<24; i++) {
        buff[i] = Serial2.read();    // 24バイト分データを読み込む
      }
      if (buff[1] == 0x5A && checksum()) { // この条件を満たした場合生データを計算する
        CurrentPar  = ((uint32_t)buff[8]  << 16) + ((uint32_t)buff[9]  << 8) + buff[10];
        CurrentData = ((uint32_t)buff[11] << 16) + ((uint32_t)buff[12] << 8) + buff[13];   
        powerPar    = ((uint32_t)buff[14] << 16) + ((uint32_t)buff[15] << 8) + buff[16];
        powerData   = ((uint32_t)buff[17] << 16) + ((uint32_t)buff[18] << 8) + buff[19];
        ret = true;
      }
    } else {
      while (Serial2.read() >= 0); // なくなるまでデータを捨てる
    }
  }
  return ret;                      // 正しくデータが取得できたらtrueを返す
}

// 電源OFFをカウントする
void countPower() {
  float current = getCurrent();
  float power = getPower();
  if (power < POWER_LIMIT) count++; // 上限値より下ならカウントする
  if (current > max_current) max_current = current; // 電流の最大値取得
  if (power > max_power) max_power = power;         // 電力の最大値取得
}

// 電源状態を確認する
void checkPower() {
  if (flag_first) {                // 初回のときだけ
    flag_first = false;            // 初回フラグOFF
    if (count < POWER_ON_CNT) {    // カウント数が下回っていたら
      flag_power = true;           // 電源状態フラグをONにする
      Blynk.virtualWrite(V1, 2);   // ONの画像を表示
    } else {
      flag_power = false;          // 電源状態フラグをOFFにする
      Blynk.virtualWrite(V1, 1);   // OFFの画像を表示
    }
  } else {
    if (flag_power) {              // 電源状態フラグがONのとき
      if (count > POWER_OFF_CNT) { // カウント数が上回っていたら
        flag_power = false;        // 電源状態フラグをOFFにする
        Blynk.virtualWrite(V1, 1); // OFFの画像を表示
        Blynk.notify(NOTIFY_MSG);  // メッセージ通知
        Terminal.println("===== POWER OFF =====");
      }
    } else {                       // 電源状態フラグがOFFのとき
      if (count < POWER_ON_CNT) {  // カウント数が下回っていたら
        flag_power = true;         // 電源状態フラグをONにする
        Blynk.virtualWrite(V1, 2); // ONの画像を表示
        Terminal.println("===== POWER ON  =====");
      }    
    }
  }
  Terminal.printf("Count   : %d\n", count);          // カウント数表示
  Terminal.printf("Current : %.3f\n", max_current); // 電流(A)の最大値表示
  Terminal.printf("Power   : %.3f\n", max_power);   // 電力(W)の最大値表示
  Terminal.flush();             // 全てのデータを送信する
  count = 0;                    // カウンターをリセット
  max_current = 0.0;            // 電流の最大値をリセット
  max_power = 0.0;              // 電力の最大値をリセット
}

void setup() {
  M5.begin(true, false, true);  // 初期化 シリアルする、I2Cしない、LEDする
  M5.dis.drawpix(0, 0x008000);  // LEDを赤で点灯
  pinMode(23, OUTPUT);          // リレー制御ピン(GPIO 23)を出力に設定
  digitalWrite(23, HIGH);       // リレーをONにする
  Serial2.begin(4800, SERIAL_8E1, 22, -1); // HLW8023用のUARTを初期化(GPIO 22)
  Blynk.begin(AUTH_TOKEN, WIFI_SSID, WIFI_PASS); // Blynkの初期化
  Timer.setInterval(100, countPower);   // 100ms毎に電源OFFをカウントする
  Timer.setInterval(20000, checkPower); // 20s毎に電源状態を確認する
  M5.dis.drawpix(0, 0x000080);  // LEDを青で点灯
}

void loop() {
  serialReadLoop();             // HLW8032(エネルギー計測IC)のデータ取得
  Blynk.run();                  // Blynkライブラリの処理
  Timer.run();                  // Timerライブラリの処理
}

 

電源OFFの検出方法

電力が0だったら電源OFFとみなす方法が使えれば非常に簡単だったのですが、ATOM Socket Kitでは使用しているエネルギー計測IC HLW8032の出力が低負荷時に不安定になるという欠点がありました。

分かりやすく説明すると、ATOM Socket Kitに何も接続していない状態でも、電流や電力が波がある感じで検出されてしまうのです。

そのため、このプログラムでは電力が1W未満だった数を100ms毎に20秒間計測し、その数が閾値以上であれば電源OFFとみなす方法を取っています。

同様に電源ONの検出も電力が1W未満だった数で判断していて、それぞれ10行目と11行目で閾値を定義しています。

 

エネルギー計測IC HLW8032からのデータ取得

HLW8032は中国製のICで日本では流通していなく情報が殆どありません。

一応M5Stackからサンプルコードが公開されていたので、サンプルコードを参考に少し改良して使っています。