M5Stack

M5Stackで作る!最先端スマート洗濯バサミ

第4回(最終回):省電力化して最先端スマート洗濯バサミの完成!

第1回:洗濯物の取り込みを教えてくれるスマートな洗濯バサミを作ろう!
第2回:M5Stickに水分センサを付けて洗濯物乾き具合をチェック
第3回:インターネットに接続して天気予報から取り込みタイミングをお知らせ!

 

こんにちは、ヨシケンです!

今回の連載では小型のM5Stick-Cシリーズを使って、最先端洗濯バサミを作っています。最終回の今回は、洗濯バサミとして使っている時に、定期的にセンサ情報をクラウドに送信してグラフ化できるようにします。また、外で洗濯物が乾くまでの時間使っても電源がもつような、省電力化もしてみたいと思います!

smart-clothespin-with-m5stack-04-01

smart-clothespin-with-m5stack-0-0203

M5Stickを使って最先端スマート洗濯バサミ作り

 

今回の記事で必要な物一覧

今回のM5Stick-Cを使ったもの作りに必要な部品はこちらになっています。

M5Stick-C

ESP32に小型ディスプレイを搭載したArduino互換機。ボタン、BLE、Wi-Fiおよびモーションセンサなども始めから入っている。

smart-clothespin-with-m5stack-01-03

 

水分センサ

赤外線により接触物の水分量を計測

smart-clothespin-with-m5stack-02-03

 

DHT11 温湿度センサ

温度と湿度を同時に計測できる安価なデジタルセンサ

smart-clothespin-with-m5stack-02-04

 

電池ボックス

(単三乾電池3個形)

smart-clothespin-with-m5stack-04-07

 

洗濯バサミ、外装など

百均などで手に入れて下さい

 

今回の記事の流れ

  1. 計測データをクラウドに送ってグラフ化
  2. バッテリ追加と電源対策
  3. 省電力化を図って、最先端スマート洗濯バサミの完成!
  4. まとめ

 

1. 計測データをクラウドに送ってグラフ化

洗濯バサミを外で使っている時に、計測したデータをグラフなどにして外部から見ることができたら使い勝手が向上します。クラウド上にデータ保持、グラフが作れるAmbientというサービスがあるので、これを使ってみます。
https://ambidata.io/

Ambientを使うと、IoT機器などから簡単にデータが送れ、グラフ化できるので、洗濯バサミと連携させてみましょう。それにはまずこちらのAmbientサイトに行って、アカウントを作成します。

https://ambidata.io/usr/signup.html

アカウントが作成されたら、チャネル一覧ページに遷移します。「チャネルを作る」ボタンを押して、新たなチャネルを作成します。新しいチャネルができると、以下の画面のようにライトキーが生成されるので、これをコピーしておきます。

次にM5StickにAmbientのライブラリを追加します。Arduino IDEで ツール>ライブラリマネージャ からambient ライブラリを検索し、インストールします。

ライブラリのインストールが済むと、スケッチ例のところにAmbient ESP32のプログラムが追加されています。

それではこのAmbient_BME280などのサンプルを使って、洗濯バサミからAmbientにデータを送ってみましょう。

以前作ったM5Stick_Laundryスケッチに、Ambient_BME280を参考にして、以下プログラムを作ります。

[M5Stick_Laundry_Ambient.ino]

#include <M5StickC.h>
#include <Wire.h>
#include <DHT.h>

const int PIN_DHT = 0;
DHT dht(PIN_DHT,DHT11);
#include "Ambient.h"
WiFiClient client;
Ambient ambient;

const char* ssid = "XXXX";
const char* password = "YYYY";
unsigned int channelId = 00000; // AmbientのチャネルID
const char* writeKey = "AAAA"; // ライトキー

void setup(){
    M5.begin();
    M5.Lcd.setRotation(3);
    M5.Lcd.setTextSize(2);
    dht.begin();

    Serial.begin(74880);
    delay(100);
    Serial.println("\r\nM5Stick+Temp->Ambient test");
    WiFi.begin(ssid, password); 
    while (WiFi.status() != WL_CONNECTED) { 
        delay(100);
    }
    Serial.print("WiFi connected\r\nIP address: ");
    Serial.println(WiFi.localIP());
    ambient.begin(channelId, writeKey, &client); 
}

void loop() {
  delay(3000);
  
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(10, 0); //文字表示の左上位置を設定
  M5.Lcd.setTextColor(WHITE); // (WHITE, BLACK, RED, GREEN, BLUE, YELLOW...)
  M5.Lcd.printf("Temp");
  M5.Lcd.setCursor(10, 20); 
  M5.Lcd.setTextColor(GREEN);
  M5.Lcd.print("Humid: ");
  M5.Lcd.print(humidity,0); 
  M5.Lcd.print("%");
  M5.Lcd.setCursor(10, 40); 
  M5.Lcd.setTextColor(RED);
  M5.Lcd.printf("Temp: ");
  M5.Lcd.print(temperature,0);
  M5.Lcd.print("C");
  float laundry_index = ( 0.81*temperature+0.01*humidity*(0.99*temperature-14.3)+46.3 );
  M5.Lcd.setCursor(10, 60);
  M5.Lcd.setTextColor(YELLOW);
  M5.Lcd.printf("LAUNDRY: ");
  M5.Lcd.print(laundry_index,0);

  ambient.set(1, String(temperature).c_str());
  ambient.set(2, String(humidity).c_str());
  ambient.send();

}

7行から14行、22行から31行、60行から62行が、M5StickからAmbientに接続するための記述です。channelIdに先ほど作成したチャネルの数字のIDを指定します。またwriteKeyの”AAAA”の部分にAmbientのライトキーを設定します。setupのところで、ambient.beginを宣言します。そしてloopの最後に、ambient.setとambient.sendをすることで、外気の温度、湿度を転送することができます。

それではこれを流し込んで、結果を見てみましょう。

少し待ってから先ほど作ったAmbientのチャネルに行ってみてください。そうすると以下のようなグラフが見えてくるはずです。

https://ambidata.io/ch/channels.html

外に設置した洗濯バサミから気温と湿度の情報が送られて来ています。30秒毎に更新され、左側が気温、右側が湿度のグラフになっています。インターネット上からもログインしたら見ることができるので、ときどきチェックしてみてくださいね。

 

2. バッテリ追加と電源対策

洗濯バサミから定期的にデータを送信できるようになりましたが、洗濯物が乾くまでの数時間この洗濯バサミを稼働させる必要があります。M5Stickには内蔵バッテリがありますが、80mAhのリチウムイオンポリマー電池なので少し心許ないです。

そこで、単三電池を3つセットできる電池ボックスを用意して、M5Stickにつないで追加のバッテリとします。

smart-clothespin-with-m5stack-04-1314

今回使ったニッケル水素充電池は一つが1.2Vなので3つで3.6V相当ですが、M5Stickの5V IN(下の図で一番右側)につないで、給電することができました。

smart-clothespin-with-m5stack-04-15

電池ボックスとM5Stickを接続

それでは先ほどのAmbientにデータを定期的に送るスケッチを使って、バッテリの持ちを測ってみます。

まず追加バッテリなしの状態で、常時画面をオンにし、Wi-Fiにずっとつながった状態で30秒に一回Ambientにデータを送ってみます。M5Stickの内蔵バッテリだけですと、約30分で電源が落ちてしまいました。

次に、この単三電池3本の電源を追加して計測をしてみます。この時は約1時間M5Stickで計測、データ送信を続けることができました。

smart-clothespin-with-m5stack-04-1617

温度センサと共に接続

ただ、これだけですと日中洗濯物を干しておく時間には物足りません。M5Stickではプログラムで各種設定を変更できるので、これにより省電力化を図りたいと思います。

まず、M5.Axp.ScreenBreath()という設定で、画面の輝度を調整することができます。デフォルトは12という明るい設定なので、これを下げるとバッテリの持ちが良くなります。

次にM5.Axp.begin()というコマンドで、M5Stickで使っていない電源出力を止めることができます。

また、M5StickにはDeepSleep()というモードがあり、ほとんどバッテリを使わずに稼働させることができるのですが、今回のように常時計測やWi-Fiに接続する場合は、それが使えません。

そこで、setCpuFrequencyMhz()というコマンドを使うとM5Stickの動作周波数を変更することができます。これにより、Wi-Fiに接続してデータ転送する時だけ周波数を上げ、それ以外の時は周波数を下げ、電力消費を抑えることができます。また周波数が高いままだと、追加バッテリーからの電圧が弱い場合にM5Stickに給電できなくなるので、周波数の調整により給電をコントロールします。

このようにM5Stickで消費電力を抑える仕組みがあるので、次節でそれをプログラムの中に設定して、省電力化させた洗濯バサミを完成させます。

 

3. 省電力化を図って、最先端スマート洗濯バサミの完成!

まず洗濯バサミとセンサ、バッテリなどを全て接続します。

smart-clothespin-with-m5stack-04-1819

次に先ほどの省電力化のためのチューニングを、プログラムに記述して、バッテリの持ちを良くするようにしましょう。まず、setupの記述のところに、ディスプレイのM5.Axp.ScreenBreath(9) という設定を追加し、輝度を9に落とします。

smart-clothespin-with-m5stack-04-2021

左が輝度12で、右側が輝度9に設定した場合

また、M5Stickは通常240MHzで稼働しており、常時Wi-Fiに接続、送信をおこなっています。ここでは何もない時は、M5Stickの最低限の電圧10MHzで稼働させ、定期的(この場合5分毎)にWi-Fi接続とデータ送信する時だけ240MHzに戻して、終わったらWi-Fiを切断するようにします。これにより大幅に節電ができると思います。

それでは最終的に、省電力化の設定も追加したスケッチを以下のように作りました(22〜25、91〜93、98〜105、112〜116、152〜156、167〜170)。また、洗濯物が乾いた時などに、LINEで乾いたことをお知らせする機能も付けました(158〜166)。

[M5Stick_Laundry_Weather_Line_Ambient_Low.ino]

#include <M5StickC.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h> 

#define WATER_SENSOR 33
int prevWATER;
#include <DHT.h>
const int PIN_DHT = 0;
DHT dht(PIN_DHT,DHT11);

#include "Ambient.h"
WiFiClient client;
Ambient ambient;
unsigned int channelId = 0000047074;;
const char* writeKey = "AAAA";
const char* ssid     = "XXXX”;
const char* password = "YYYY”;
const String endpoint = "http://api.openweathermap.org/data/2.5/weather?q=tokyo,jp&APPID=";
const String key = "ZZZZ”;

unsigned long measInterval = 10;
unsigned long sendInterval = 1000*300;//5分待機
unsigned long prevMeasTime = 0;
unsigned long prevSendTime = 0;

void send(String message) {
  const char* host = "notify-api.line.me";
  const char* token = "WZ64OhBVEfpaSpLDlPUPuJxbT24bCnikVfMTm3q3YHk";
  WiFiClientSecure client;
  Serial.println("Try");
  client.setInsecure();
  if (!client.connect(host, 443)) {
    Serial.println("Connection failed");
    return;
  }
  Serial.println("Connected");
  String query = String("message=") + message;
  String request = String("") +
                   "POST /api/notify HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "Authorization: Bearer " + token + "\r\n" +
                   "Content-Length: " + String(query.length()) +  "\r\n" +
                   "Content-Type: application/x-www-form-urlencoded\r\n\r\n" +
                   query + "\r\n";
  client.print(request);
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r") {
      break;
    }
  }
  String line = client.readStringUntil('\n');
  Serial.println(line);
}

String getWeather(){
  HTTPClient http;
  http.begin(endpoint + key); //URLを指定
  int httpCode = http.GET();  //GETリクエストを送信
  String weather="Error";
  if (httpCode > 0) { //返答がある場合
      String payload = http.getString();  //返答(JSON形式)を取得
      Serial.println(httpCode);
      Serial.println(payload);
      //jsonオブジェクトの作成
      DynamicJsonBuffer jsonBuffer;
      String json = payload;
      JsonObject& weatherdata = jsonBuffer.parseObject(json);
      //パースが成功したかどうかを確認
      if(!weatherdata.success()){
        Serial.println("parseObject() failed");
      }
      //各データを抜き出し
      weather = weatherdata["weather"][0]["main"].as<char*>();
      const double temp = weatherdata["main"]["temp"].as<double>();
  }
  return weather;
}

void setup() {
  Serial.begin (9600);
  pinMode(WATER_SENSOR, INPUT);
  prevWATER = 1;
  dht.begin();  
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.setTextSize(2);

  M5.Axp.begin(false, false, false, false, true);
  setCpuFrequencyMhz(10);
  M5.Axp.ScreenBreath(9);
}

void loop(){
 M5.update();
 unsigned long durationTime = millis();
 unsigned long currentTime = millis();
 if(currentTime-prevMeasTime >= measInterval) {
  prevMeasTime = currentTime;

  if(currentTime-prevSendTime >= sendInterval) {
    prevSendTime = currentTime;
    setCpuFrequencyMhz(240);

    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();
  
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(10, 0);
    M5.Lcd.printf("WIFI START: %s ", ssid);
    WiFi.begin(ssid, password);
    while(WiFi.status() != WL_CONNECTED) {
          delay(500);
          M5.Lcd.print(".");
    }
    M5.Lcd.printf("WIFI READY\n");
      
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(10, 0); //文字表示の左上位置を設定
    M5.Lcd.setTextColor(WHITE); // (WHITE, BLACK, RED, GREEN, BLUE, YELLOW...)
    M5.Lcd.printf("W: ");
    String weather = getWeather();
    Serial.println(weather);
    M5.Lcd.print(weather);    
    M5.Lcd.setCursor(10, 20);  
    M5.Lcd.setTextColor(BLUE); 
    M5.Lcd.print(digitalRead(WATER_SENSOR));
    if ( digitalRead(WATER_SENSOR) == 0 ) {
        M5.Lcd.printf(": Wet ");
        prevWATER = 0;
    } else {
        M5.Lcd.printf(": Dry! ");
    }
    Serial.println(digitalRead(WATER_SENSOR));    
    M5.Lcd.setCursor(10, 40);
    M5.Lcd.setTextColor(GREEN);
    M5.Lcd.print("H:");
    M5.Lcd.print(humidity,0); 
    M5.Lcd.print("%"); 
    M5.Lcd.setTextColor(RED);
    M5.Lcd.printf(" T:");
    M5.Lcd.print(temperature,0);
    M5.Lcd.print("C");  
    M5.Lcd.setCursor(10, 60);
    float laundry_index = ( 0.81*temperature+0.01*humidity*(0.99*temperature-14.3)+46.3 );
    M5.Lcd.setTextColor(YELLOW);
    M5.Lcd.printf("Laundry: ");
    M5.Lcd.print(laundry_index,0);

    ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
    ambient.set(1, String(temperature).c_str());
    ambient.set(2, String(humidity).c_str());
    ambient.set(3, String(laundry_index).c_str());
    ambient.send();

    if ( (prevWATER == 0) and (digitalRead(WATER_SENSOR) == 1) ){
      send("気温は"+String(temperature,0)+"C、湿度は"+String(humidity,0)+"%です。");
      send("乾いたから取り込んで!");
      prevWATER = 1;
    }    
    if (weather == "Rain"){
      send("気温は"+String(temperature,0)+"C、湿度は"+String(humidity,0)+"%です。");
      send("雨が降るので取り込んで!");
    }
    // Wi-Fi切断
    WiFi.disconnect(true);
    // 動作周波数を下げる
    setCpuFrequencyMhz(10);
  }
 }      
}

スケッチ中、省電力化のために、5分に一回Wi-Fiに接続し、その時にセンサでの計測を行い、それをAmbientに送信しています。また、同じタイミングでお知らせ機能の記述として、洗濯物が乾いた時にLINEでメッセージを送っています。天気予報から雨が降る時にそのワーニングもLINEに送っています。

それでは洗濯バサミを外で使ってみて、動きを確認してみましょう。

smart-clothespin-with-m5stack-04-2223

下の部分の水分センサにより洗濯物の乾き具合をチェック

このような省電力設定にしたことにより、通常であれば8時間に渡ってM5Stickを稼働し続けることができるようになりました。5分に一回、以下のようにAmbientにデータを送り続け、グラフを作ることができています。

また、洗濯物が乾いたところで、このようにLINEにメッセージが送られ、取り込み時を知ることができます。

これでM5Stickを使って、センサから温湿度を計測し、洗濯物の乾き具合をチェックできるスマート洗濯バサミの完成です。日中、日のある時間ずっと使用できるような省電力化も実現しました。今回は単三電池を使いましたが、もっと小さなバッテリにすれば、小型化も可能だと思います。

smart-clothespin-with-m5stack-04-25

 

4. まとめ

今回の連載では、M5Stickを使った最先端スマート洗濯バサミに様々な機能を着けて完成させました。

まず温室度センサ、水分センサを付け、洗濯物の状況が分かる様にしました。これで水分量を測って、洗濯物が乾いたら、センサ値が変わり、それが分かります。また、気温と湿度から洗濯指数を出して、洗濯に適した状態かも分かります。

次にインターネットに接続して、外からでもその状況が分かるようにしました。洗濯物が乾いたかをLINEに送信して、取り込みタイミングをお知らせします。

さらに、天気予報のサイトに接続して、天気情報を取得できるようにしました。天気予報が雨ならそれを取得して、これもLINEにメッセージとして、「雨が降るから取り込んで!」などとして、天気の急変を伝えます。

最後に、M5Stickのバッテリだけですと洗濯物を干している間、電源が持たないので、バッテリを追加し、省電力化の仕組みも導入しました。これで丸一日使えるようになりました。1日使うことができるので、その間取得したデータを、Ambientに送って、グラフ化もおこないました。

M5StackシリーズのM5Stick-Cは小さくて、数多くのセンサ、ハードウェアを付けることができるので、様々なものを作ることができます。これからもM5Stackシリーズを使って、電子工作、IoTを楽しんでください!

 

 

今回の連載の流れ

第1回:洗濯物の取り込みを教えてくれるスマートな洗濯バサミを作ろう!
第2回:M5Stickに水分センサを付けて洗濯物乾き具合をチェック
第3回:インターネットに接続して天気予報から取り込みタイミングをお知らせ!
第4回:省電力化して最先端スマート洗濯バサミの完成!(今回)

普通の会社に勤めるサラリーマンですが、モノ作りが好きな週末メイカーで、電子書籍MESHBOOKを出したり、ブログを書いたりしています!

http://blog.ktrips.net

スマホでコントロールできるロボットを作ろう