Firebase Realtime Database のデータ保存、取得、ストリーミング受信実験( ESP32 , M5Stack )

記事公開日:2018年9月1日


スポンサーリンク

8.Firebase Realtime Database から EventSource / Server-Sent Eventsによるストリーミングデータ取得

さて、Firebase Realtime Database の最もスゴイところは、データをストリーミング配信してくれることです。
そして、データベース内のデータが更新されたデータだけを抽出して送信してくれるところです。
これは、メチャメチャ便利な機能です。

実は、Firebase Realtime Database には、ストリーミング受信の EventSource / Server-Sent Events がサポートされています。
そのドキュメントはRealtime Database の REST 使用の以下のリンクに書いてあります。

https://firebase.google.com/docs/database/rest/retrieve-data?hl=ja

この、EventSource / Server-Sent Events というのは、私も以前、Arduino や ESP-WROOM-02 ( ESP8266 ) を使って以下の複数の記事で試したことがあります。

https://www.mgo-tec.com/tag/server-sent-events

この当時はホントに感動しました。
マイコンからのデータがストリーミングでスマホへ配信してくれるんです。
ただし、EventSource / Server-Sent Events は、一方向のみです。
今回は、Firebase サーバーからの受信方向のみとなります。

そして、EventSource / Server-Sent Events の素晴らしい機能がもう一つあります。
ブラウザを閉じても、再度起動すると自動的に再接続してストリーミング受信をしてくれるというところです。
これは便利ですね。

この EventSource / Server-Sent Events はとっても簡単な命令で実現可能なのです。

HTTP GET リクエストを送る時、HTTP ヘッダに以下を加えるだけです。

Accept: text/event-stream

それを加えた、Firebase Realtime database への最低限の HTTP GET リクエストは以下のようになります。
auth や Host 、そしてtest_user1 は各個人のプロジェクトによって異なります。

GET /test_user1.json?auth=xxxxxxxxxxxxxxxxx HTTP/1.1
Host: testproject01-439eb.firebaseio.com
Accept: text/event-stream
Connection: close
(空行)

これだけで、auth認証が通ってしまうのは、Twitter API より遙かに簡単ですね。

最後の空行は必ず必要です。
空行と言っても、”¥r¥n”というコードを送ります。
“¥r” は ASCII コードが 0xAh のラインフィードです。
ラインフィードは次の行へ移動という制御です。
“¥n”は ASCII コードで 0xDh でキャリッジリターンというもので、行の先頭へ移動という制御です。
要するに、”¥r¥n” はEnterキーを押したようなものです。

この GET リクエストを M5Stack や ESP32 などのマイコンで送り、Firebase サーバーからのデータを常時待ち受けていれば、マイコンでストリーミング受信可能です。

では、次は実際に M5Stack や ESP32 で Firebase からのストリーミングデータを受信してみます。

9.ESP32 および M5Stack による、Firebase Realtime database からのストリーミングデータ取得

では、Wi-Fi & Bluetooth マイコン ESP32 を搭載したモジュールを使って、Firebase Realtime database からのデータをストリーミング受信してみます。

ESP32 モジュールの準備

まず、手元にWi-Fi マイコン、ESP-WROOM-32 ( ESP32 )開発ボードまたは M5Stack を用意します。
以下のようにいろいろな種類の ESP32 マイコンボードがありますが、どれでも良いです。

● M5Stack

Amazon.co.jp
M5Stack Basic
スイッチサイエンス

Amazon.co.jp
M5Stack Gray(9軸IMU搭載)
スイッチサイエンス

これについては、以下の記事も参照してください。

M5Stack ( ESP32 搭載 ) を分解したり電源を入れてみて、いろいろ思ったこと

● ESP-WROOM-32 ( ESP32 )開発ボード

Amazon.co.jp

Amazon.co.jp
ESPr Developer 32
スイッチサイエンス(Switch Science)

ESPr Developer 32 については、以下の記事を参照してください。
ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました

Arduino – ESP32 のインストール

Arduino IDE で開発します。
Arduino IDE は ver 1.8.6 で動作確認しています。

Arduino core for the ESP32 ( 以下 Arduino – ESP32 )は Stable 版のver 1.0.0 で動作確認しています。
Arduino – ESP32 のインストール方法は以下の記事を参照してください。

Arduino core for the ESP32 のインストール方法

Wi-Fi環境の確認

Wi-Fiルーターを起動しておき、事前に ESP32 ( ESP-WROOM-32 )がインターネットに接続できるように設定しておいてください。
ファイアウォールや MACアドレスフィルタリングの設定を確認しておいてください。
ESP32 の MACアドレスを調べる方法は以下の記事を参照してください。

ESP-WROOM-32 ( ESP32 ) チップ・メモリ・MACアドレス情報取得方法

スケッチ(ソースコード)入力

では、先で述べた HTTP GET リクエストを踏まえて、以下のスケッチを入力していきます。

Arduino – ESP32 には、HTTPClient という便利なライブラリがありますが、アマチュアの私としては、逆にしくみが解りにくくなってしまうので、最低限のWiFi および WiFiClientSecure ライブラリだけ使います。
因みに、Firebase はhttps の SSL 通信です。

#include <WiFi.h>
#include <WiFiClientSecure.h>

const char* ssid = "xxxxxxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxxxxxx"; //ご自分のルーターのパスワードに書き換えてください

const char* host = "xxxxxx-xxxx.firebaseio.com";
const char* firebase_auth = "xxxxxxxxxxxxxxxxxxxxxxxxx"; //database secrets

String user_path = "test_user1";

WiFiClientSecure client;

//*****セットアップ******************
void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  Serial.print( "connecting" );
  while ( WiFi.status() != WL_CONNECTED ) {
    Serial.print( "." );
    delay(500);
  }
  Serial.println();
  Serial.print( "connected: " );
  Serial.println(WiFi.localIP());

  delay(2000);
  getServerSentEvents();
}
//****メインループ********************
void loop() {
  checkServerRespons();
}
//***********************************
void getServerSentEvents(){
  Serial.println( "\nStarting connection to server..." );
  if( !client.connect( host, 443 ) ){
    Serial.println( "Connection failed!" );
  }else{
    Serial.println( "Connected to server!" );
    String req_url_str;
    req_url_str = "GET /";
    req_url_str += user_path + ".json?auth=";
    req_url_str += String( firebase_auth ) + " HTTP/1.1\r\n";

    String req_header_str;
    req_header_str = "Host: ";
    req_header_str += String( host ) + "\r\n";
    req_header_str += "Accept: text/event-stream\r\n";
    req_header_str += "Connection: close\r\n";
    req_header_str += "\r\n"; //空行

    Serial.println( "Send Server-Sent Events GET request." );
    //FirebaseサーバーへGETリクエスト送信
    client.print( req_url_str );
    client.print( req_header_str );

    Serial.print( req_url_str );
    Serial.print( req_header_str );
  }
}
//***********************************
void checkServerRespons(){
  while( client.available() ){
    char c = client.read();
    if( c == '\r' ) Serial.print( "\\r"); //キャリッジリターン
    if( c == '\n' ) Serial.print( "\\n"); //ラインフィード
    Serial.print( c );
  }
}

かなり簡単なスケッチだと思います。

4-5行目で、各自の Wi-Fiルーターの SSID とパスワードに書き換えてください。

7-10行目ではご自分の Firebase プロジェクトに合わせて書き換えてください。
7行目の host は下図の様に Firebase console 画面を開き、アドレスをコピペしてください。

firebase_realtime_database40.jpg


auth は先ほど述べた Database secrets ( データベースシークレット )です。

GET リクエストヘッダも最低限です。

コンパイル書き込み実行、およびシリアルモニタで確認

では、上記のスケッチを Arduino IDE でコンパイル書き込み実行してみてください。
そして、シリアルモニタを 115200bps で起動してください。

すると、下図の様に表示されると思います。

firebase_realtime_database37.jpg


このように、GET リクエストデータを送ってから、Firebaseサーバーから HTTP レスポンスヘッダが返ってきます。

レスポンスヘッダを良く見ると、”¥r¥n” というキャリッジリターン(CR)とラインフィード(LF)というコードが各行にあり、レスポンスヘッダが終了する時には”¥r¥n”のみの行、つまり空行が入ります。

その後、Server-Sent Events のストリーミングデータが送られてきます。

event は、初回時は必ず PUT となっています。
初回の data は

{"path":"/","data":{"color":"red","text":"hello world"}}

という形で送られてきます。

そして、Firebase Realtime database を何も操作していない場合は、30秒毎に Firebase サーバーから

event: keep-alive\n
data: null\n

というデータが送られてきます。

そして、ブラウザなどで、Firebase Realtime Database の color のところを書き換えると、

event: put\n
data: {"path":"/color","data":"blue"}\n

という感じで、変更されたデータのみが、即、送られてきます。
これは便利ですね。

パソコン画面の動画ではこんな感じです。

「動画」

なかなかイイ感じですよね。
Firebase console 画面の Realtime database の値が変わっていることが分かると思います。

そして、Server-Sent Events のストリーミングデータを受信している時に”¥n”のラインフィード(LF)しか送られていないことに注目してください。
ヘッダではキャリッジリターンも送られてきましたが、ここではラインフィードのみです。

このことを利用して、ヘッダ情報とストリーミングデータ情報を振り分けるプログラミングすると良いと思います。

以上をうまく利用すると、M5Stack のディスプレイには素早いデータ表示ができると思います。

この EventSource / Server-Sent Events は、HTML上で JavaScript プログラムを書いて、ブラウザで表示させると、一度ブラウザを閉じても、次に起動したときに自動でコネクション接続して自動でストリーミング受信してくれます。
とっても便利です。
JavaScript の書き方は次回の記事で紹介したいと思います。


スポンサーリンク


「Firebase Realtime Database のデータ保存、取得、ストリーミング受信実験( ESP32 , M5Stack )」への6件のフィードバック

  1. 突然のコメントにて失礼します。
    Firebase Realtime Databaseの内容でもないので申し訳ないのですが、
    ESP32でキーマトリクス回路を作りたいと思い、
    ESP32DEVkitCに74HC138のデマルチプレクサをつないで
    作ったのですが、ちとうまくいかないところがありまして、
    もしESP32でデマルチプレクサかマルチプレクサを使われた経験が
    ございましたら、伺いたいことがございます。
    いかがでしょうか。
    ※Arduinoではうまくいったキーマトリクス回路を
    そのままESP32に流用しようとしています。

    1. Yosukeさん

      コメント投稿ありがとうございます。
      ただ、残念ながら、デマルチプレクサとかマルチプレクサは使ったことがありません。
      それとはかなり異なるかも知れませんが、ESP8266でSPI通信で、I/Oエキスパンダを使って、GPIOを増設したことがあります。
      以下の記事です。
      ESP-WROOM-02 ( ESP8266 )の GPIO を増設して キャラクタディスプレイ 8bitモード制御してみた
      GPIO 増設した ESP-WROOM-02 ( ESP8266 )で、8bitモードのグラフィックディスプレイ を制御してみた
      視認性クッキリ! 大き目ドットの OLED WS0010 で日本語漢字フォント電光掲示板風スクロール&スマホ操作
      大き目ドットの有機EL, WS0010 で Yahoo ニュース リアルタイム 電光掲示板を作ってみた

      とりあえず、この程度です。
      お役に立てず、すみません。
      m(_ _)m

  2. mgo-tecさん

    ご返信いただきまして誠ありがとうございます。
    リンクして頂いたページを中心に、
    SPI通信を勉強してみようと思います。

    すみませんが、もう1点伺いたいことがございます。
    Arduino(ATmega328p)に74HC138をつなげば、
    キーマトリクス回路を正常に組めています。
    そこで、ESP32と74HC138の間にATmega328pを噛ませて、
    ESP32 – ATmega328p – 74HC138 – ボタン達のようにつなぎ、
    ESP32とATmega328pで何らかの通信をする方法を
    素人考えで考えてみたのですが、
    SPI通信などを利用して、ATmega328pからESP32に値を送る
    ようなことは可能でしょうか?

    お忙しいところ恐れ入りますが、何かご存知でしたら、
    ご返信いただければ助かります。

    1. Yosukeさん

      多分、ESP32 と Arduino で SPI データ通信は可能だと思いますが、そのデバイス間ではシリアル通信しかやったことがありませんので、アドバイスできません。
      私が個人的に思うには、Arduino を噛ませないでも、ESP32 だけで十分可能ではないかと思います。
      ESP32 のクロックの方が高速ですし・・・。
      ということで、あまりお役に立てず、申し訳ございません。

  3. mgo-tecさん

    ご返信頂きましてありがとうございます。
    EPS32にマルチプレクサやデマルチプレクサをつなぎますと、
    押していないボタンが押されたような反応になってしまう等、
    笑ってしまうほど意図しない挙動になってしまい、
    Arduinoで出来ていたことがこんなにできないのかと困っておりました。
    ただ、やはり安価にBluetooth通信が出来るの機能は捨てがたいので、
    アドバイス頂いた通り、EPS32のみでもう少し試行錯誤を
    続けてみようと思います。

    EPS32ユーザーの方とお話できただけでも嬉しかったです。
    本当にありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください