LoginSignup
6
2

More than 1 year has passed since last update.

M5Stack UnitV2 とFirebaseとenebularで、一定時間現れないとLINEにお知らせを作ってみた。

Last updated at Posted at 2021-12-15

はじめに

「M5Stack UnitV2で顔認識して、一定時間その人が現れなかったらお知らせ」を作ります。「一定時間その人が現れなかったら」の部分はenebularを使って、一定時間が任意に遠隔で変更できるようにします。

M5Stack UnitV2の準備

ラズベリーパイとM5Stack UnitV2をUSBケーブルでつなぐ。
image.png
ラズベリーパイのブラウザChromiumを立ち上げて、http://10.254.239.1/
にアクセス。

なお、今回使用する人物写真は、photoACのAI人物素材(ベータ版)で、AIが生み出した実在しないモデルです。
https://www.photo-ac.com/main/genface
image.png
この実在しない6人のモデルの顔を、Face Recognition modeで、学習させた。
image.png

学習させる前
image.png
学習させた後
image.png

Firebaseの準備

田中正吾さんの記事「M5StackとFirebaseを使ってenebularとつないでみよう」
https://blog.enebular.com/firebase/m5stack-firebase-enebular-collaboration/
を参考に Firebaseを設定する。
Google Developerログインを済ませて、Firebaseにアクセス。
コンソールに移動する。
プロジェクトを追加を押してプロジェクト作成。
image.png
プロジェクトに名前をつける。
image.png
image.png

ウェブアプリに Firebase を追加する。
image.png
アプリニックネームを入力
image.png

scriptタグを使用するを選択
コンソールに進む
image.png

Realtime Databaseを作成する。
image.png

ロケーションの設定で米国を選択する
image.png

テストモードで開始するを選択する。
image.png

この画面の赤四角部分 https://xxxxxxxxxxxxxxxxxxxxxx-default-rtdb.firebaseio.com/
をコピペで保管しておく。
image.png

M5StickCの準備

M5StickCに以下のスケッチを書き込み、M5Stack UnitV2とM5StickCをGroveケーブルでつなぐ。
image.png

書き込む前の準備として、必要なライブラリをインストールする。
1. Firebaseライブラリをインストール。
https://github.com/ArtronShop/IOXhop_FirebaseESP32
からZIPをダウンロードして、ArduinoIDEにインストールする。
image.png
2.ArduinoJsonはバージョン6.18.5が最新である(2021.12.16現在)が、バージョン6では動かないので、バージョン5.13.5をライブラリマネージャーから、インストールする。
image.png

3.プログラムをM5StickCに書き込む。
プログラムは以下の3つの記事を参考にした。
Takahiro MITSUOKAさんの記事「M5UnitV2の検出結果をAmbientに送信するメモ」
https://zenn.dev/tmitsuoka0423/articles/15fcd13dc5334365e7ab
田中正吾さんの記事「M5StackとFirebaseを使ってenebularとつないでみよう」
https://blog.enebular.com/firebase/m5stack-firebase-enebular-collaboration/
スラニューさんの記事「M5StickCからFirebase Realtime Databaseに値を書き込んじゃうよ。」
https://slanew.com/news/819

//これはArduinoJsonはVer5を使用する
#include <IOXhop_FirebaseESP32.h>
#include <M5StickC.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <Ambient.h>

WiFiClient client;
const char *ssid = "xxxxxxx";
const char *password = "xxxxxxxxxxxxx";

Ambient ambient;
unsigned int channelId = xxxxx; // CHANNEL ID
const char *writeKey = "xxxxxxxxxxxxx";

#define FIREBASE_DATABASE_URL "xxxxxxxxxxxxxxxxxxxx-default-rtdb.firebaseio.com"

int lastSendTime = 0;
//DynamicJsonDocument doc(1024);
DynamicJsonBuffer jb;
float x;


void setup(){

  M5.begin();
  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, 33, 32);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);  

  // connect to wifi.
  WiFi.begin(ssid, password);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();

  // WiFi Connected
  Serial.println("\nWiFi Connected.");
  Serial.println(WiFi.localIP());
  M5.Lcd.println("WiFi Connected.");
  M5.Lcd.println("");

  Firebase.begin(FIREBASE_DATABASE_URL);
  Firebase.stream("/M5Stack/message", [](FirebaseStream stream) {
    String eventType = stream.getEvent();
    eventType.toLowerCase();

    Serial.print("event: ");
    Serial.println(eventType);
    if (eventType == "put") {
      String path = stream.getPath();
      String data = stream.getDataString();
      Serial.print("data: ");
      Serial.println(stream.getDataString());
    }
  });

  Firebase.setString("/M5Stack/message", "start");
  ambient.begin(channelId, writeKey, &client);

}

void loop()
{
  if (Serial2.available())
  {
    String receiveString = Serial2.readStringUntil('\n');

    // JSONをデシリアライズ
    //deserializeJson(doc, receiveString);
    JsonObject& obj = jb.parseObject(receiveString);
   if (!obj.success()) {
   Serial.println("parseObject() failed");
   return;
   }

    // こんな感じで中身を取り出せる
    String name = obj["face"][0]["name"];
    Serial.println(name);


   if(name == "sato"){
    x=1;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("sato");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 1);
    }
    else if (name == "suzuki"){
    x=2;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("suzuki");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 2);
    }
    else if (name == "takahashi"){
    x=3;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("takahashi");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 3);
    }
    else if (name == "tanaka"){
    x=4;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("tanaka");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 4);
    }
    else if (name == "ito"){
    x=5;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("ito");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 5);
    }
    else if (name == "watanabe"){
    x=6;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("watanabe");
    // Firebaseへ送信
    Firebase.setInt("//M5Stick/personID", 6);
    }
    else if (name == "unidentified"){
    x=7;
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("unidentified");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 7);
    }
    delay(2000);
    M5.Lcd.fillRect(0,20,160,60,BLACK);
    M5.Lcd.setCursor(20,20);
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.print("no person");
    // Firebaseへ送信
    Firebase.setInt("/M5Stick/personID", 8); //when no person, send 8
    delay(1000);
    Serial.println(x);

    // 一定間隔でAmbientに送信
    if (millis() - lastSendTime > 60000)
    {
      ambient.begin(channelId, writeKey, &client);
      ambient.set(1, x);
      //ambient.send();
      lastSendTime = millis();
    }
  }
}

人物認識結果を確認

M5Stack UnitV2とM5StickCをGroveケーブルで接続して、M5StackUnitV2のカメラで人物写真を写す。
その認識結果を以下の3か所で確認する。
image.png

  1. シリアルモニタで人物認識結果を確認する。
    image.png

  2. M5StickCのディスプレイで人物認識結果を確認する。
    image.png

  3. FirebaseのRealtime Databaseで人物認識結果を確認する。例えばsuzukiは、2と表示される。
    image.png

enebularを準備する。

Firebaseのデータをenebularで取得します。

「Firebaseにデータ連携できるノード」https://blog.enebular.com/nodes/firebase-nodes/
を読んで、node-red-contrib-firebase-data を使います。

以下にアクセス(プロジェクト名を入れる)。
https://console.firebase.google.com/u/0/project/`[your-project]`/settings/serviceaccounts/adminsdk
左上のプロジェクトの概要の右にある歯車ボタンを押して、プロジェクトの設定→サービスアカウントタブでもこの画面に行けます。
image.png

新しい秘密鍵の生成ボタンを押す。
image.png
!image.png
生成してダウンロードした秘密キーの中で、 "private_key", "client_email" の部分を次のAdd Firebaseノード内で入力します。

enebularのパレットの管理から node-red-contrib-firebase-data という名前のノードを追加する。
node-red-contrib-line-messaging-api ノードも追加する。
一定時間現れないとお知らせ部分は、triggerノードとswitchノードを組み合わせる。

全体フローはこれ。
image.png

フローの初めはinjectノードで2秒ごとにAdd Firebaseノードを刺激
image.png

Add Firebaseノード
image.png

Add Firebaseノードの中のFirebaseCertificateノード
上述のFirebaseで生成してダウンロードした秘密キーの中で、 "private_key", "client_email" の部分をコピペする。
image.png

Switchノード(人物で分岐)
image.png

triggerノード
ここで一定時間を指定する。この図では、48時間と設定している。
image.png

switchノード。
image.png

Notifyノード
image.png

これで、satoさんが初回現れてから48時間現れないと、satoさんが現れないというメッセージがpayloadとLINE Notifyノードに流れる。
image.png

動作確認

satoさんとsuzukiさんが一定時間現れないと、LINE Notifyにお知らせがきた。
image.png

まとめ

全体像
image.png

これで、一定時間現れなかったらLINEにお知らせ、さらに、enebularを使って一定時間を任意に遠隔で変更できて、ガッツポーズ。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2