プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

ラズパイからFirebaseのCloud Firestoreへpushする

ラズパイで測定した室内環境をwebでみれたら便利だな、と思ってラズパイからFirebaseにpushできるかやってみました。
データベースとしてはRealtime Databaseでも可能ですが、ここではFirestoreを使ってみました。

目的

ラズパイで測定した室内環境をwebで見れるようにしたい

tl;dr

・ラズパイで温湿度・気圧を測定
・FirebaseのCloud FirestoreにPythonでpush
Javascriptでhtmlに表示

温湿度・気圧の測定

ラズパイでの温湿度・気圧の測定は過去記事参照です。
s51517765.hatenadiary.jp
s51517765.hatenadiary.jp

FirebaseのCloud Firestoreを使う

Firebaseのプロジェクトは作成済みとします。
f:id:s51517765:20200813101149j:plain
Pythonからpushするので、秘密鍵を作成します。
秘密鍵Pythonスクリプトと同じフォルダに置いておくものとし、ファイル名はserviceAccountKey.jsonとします。

コマンドライン(ターミナル)でFirebase Admin SDKというPythonのクライアントライブラリをインストールします。

$pip3 install --upgrade firebase-admin

Windowsでもラズパイ(Raspbian)でもpip3一発ですが、ラズパイの場合は、アップデート・アップグレードをしておくほうがよさそうです。

$sudo apt-get update
$sudo apt-get upgrade
$pip3 install pip

ちなみにラズパイZeroではfirebase-adminのインストールがどうやってもうまくいきません。ググると解決済みのようですが…(ラズパイ3ではOKでどちらもOSとしては【Raspbian GNU/Linux 9.13 (stretch)】)

** ここで止まる **
Building wheels for collected packages: grpcio
  Running setup.py bdist_wheel for grpcio ... \

github.com
chinoppy.hatenablog.com
バイナリリンクも無くなってる(泣

Pythonスクリプトはサンプルを参考に↓のように作成しました。

import datetime
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore

# Use a service account
cred = credentials.Certificate('serviceAccountKey.json')
firebase_admin.initialize_app(cred)
db = firestore.client()

def setTemp(Temp=25, Hum=55, Pres=1000):
    Date = datetime.datetime.now()
    # キーを日付時刻で作成
    ref = db.collection('Database').document(str(Date))
    ref.set({
        u'Pres': Pres,
        u'Hum': Hum,
        u'Temp': Temp,
    })

maxLength = 20

def resizeDatabase():
    ref = db.collection('Database')
    docs = ref.stream()
    dataSize = 0
    for doc in docs:
        print(doc.id, doc._data)
        dataSize += 1
        if dataSize == 1:
            firstDateId = doc.id

    if dataSize > maxLength:
        deleteDoc(firstDateId)

def deleteDoc(id):
    db.collection('Database').document(id).delete()

if __name__ == '__main__':
    setTemp()
    resizeDatabase()

firebase.google.com
firebase.google.com

setTemp()では実際にはセンサーから取得した環境値を受け取ります(ここでは省略)。resizeDatabase()はデータが増えすぎても仕方がないので、一定数を超えたら古いものを削除するようにしました。
f:id:s51517765:20200813103456j:plain
コレクション名は”Database”とし、日付時刻をid(key)にデータを作成します。
コンソールからデータの削除はドキュメントを選択し、メニューを開くことでも可能です。

JavascriptでFirestoreのデータを呼び出す

このようにして格納したFirestoreのデータをwebページに表示します。
初期化はRealtime Databaseのときと同様で、インスタンスvar db = firebase.firestore();のように呼び出します。
データを取得するところもサンプルコードを参考にですが、データidはdoc.idですが、dataはdoc.data().Temp のように取得します。
このあたりがちょっとマニュアル見てもよくわからず試行錯誤しました。インスタンスの生成や初期化のところもだいぶ違うように思うのですが…。

<!DOCTYPE html>
<html>

<head>
  <title>室温推移</title>
  <meta http-equiv="content-type" charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1"><!-- スマホ用の表示拡大 -->
  <meta name="robots" content="noindex" />

  <link rel="stylesheet" type="text/css" href="css.css">

  <!-- The core Firebase JS SDK is always required and must be listed first -->
  <script src="https://www.gstatic.com/firebasejs/5.8.6/firebase.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-firestore.js"></script>

  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "******",
      authDomain: "*****.firebaseapp.com",
      databaseURL: "https://*****.firebaseio.com",
      projectId: "*****",
      storageBucket: "*****.appspot.com",
      messagingSenderId: "****",
      appId: "*****"
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);

    var db = firebase.firestore();
    function ListLoad()
    {
      var List1 = document.getElementById("List1");

      //データを取得
      db.collection("Database").get().then((querySnapshot) =>
      {
        querySnapshot.forEach((doc) =>
        {
          console.log(`${doc.id} : ${doc.data().Temp} ℃, ${doc.data().Hum} %RH, ${doc.data().Pres} hPa`);
          var element = document.createElement("li");
          element.innerHTML = doc.id + " : " + doc.data().Temp + "℃, " + doc.data().Hum + "%RH, " + doc.data().Pres + "hPa";

          List1.append(element);
        });
      });
    }
    window.onload = function ()
    {
      ListLoad();

    };
  </script>
</head>

<body>
  <h1>室温推移</h1>
  <form id="form1">
    <ul id="List1"></ul>
  </form>

</body>

</html>

firebase.google.com

完成

f:id:s51517765:20200813104935j:plain

あとは、グラフを表示するようにしたい。ラズパイゼロでもなんとか動くようにしたい。