Raspberry Piで取得したセンサーデータをBigQueryに投げてGoogle データポータルでグラフ化してみる

Raspberry Piで取得したセンサーデータをBigQueryに投げてGoogle データポータルでグラフ化してみる

こんにちは。阿形です。

しばらく前にオフィスの気温や湿度を記録しようと買ったRaspberry Piと気温・湿度・気圧センサーのBME280をそろそろ動かそうかなとやってみました。

ただ、最近炎上案件を抱えているので余裕が無いので、あまり時間をかけずやってみます。

Raspberry PiとBME280の接続と設定

この記事の主眼はBigQueryにデータを投げるところなので、このあたりは以下の記事を参考にやったので、そちらを参考にしてください。

https://deviceplus.jp/hobby/raspberrypi_entry_039/

とりあえずこんな感じでブレッドボードで接続しました。(よく見えないですね…)

データ取得とBigQuery送信プログラムの作成

ここからが本記事のメインです。

今回Raspberry Pi上で動かすプログラムはPython3で作成します。

先の参照URLにも書かれていますが、BME280からのデータ取得はI2Cで通信して行うため割とめんどくさいです。

ですが、そのあたりは先人の知恵を拝借するということで、公開されているパッケージを使用します。いくつか選択肢があるようなのですが、ここではRPi.bme280を使用しました。

https://pypi.org/project/RPi.bme280/

これをpipでインストールしておきます。

$ pip3 install RPi.bme280

続いてBigQueryのためのライブラリもインストールします。ここではGoogleオフィシャルのものを使用します。

$ pip3 install google-cloud-bigquery

BigQueryの設定

BigQueryの設定を行っておきます。

まず、使用するGCPのプロジェクトでBigQueryを有効にし、適当なデータセット、テーブルを作成します。ここではoffice_environmentというデータセットを作成し、その中にenvironment_tableというテーブルを作成しました。

テーブルのスキーマは以下のとおりです。

フィールド名タイプモード
timestampTIMESTAMPREQUIRED
temperatureFLOATREQUIRED
humidityFLOATREQUIRED
pressureFLOATREQUIRED

それぞれ日時データ、気温、湿度、気圧を格納します。

サービスアカウントの作成

プログラムからBigQueryにアクセスするため、サービスアカウントを作成します。

GCPのダッシュボードから「IAMと管理」>「サービスアカウント」を開き、上部の「+サービスアカウントを作成」をクリックします。

サービスアカウント名に適当な名前を入力し、「作成」をクリックします。(サービスアカウントID、サービスアカウントの説明は必要に応じて編集します)

続いてのページでは権限の設定を行います。プルダウンメニューから役割を洗濯します。

BigQueryの権限が必要ですので、「BigQuery」>「BigQuery データオーナー」や「BigQueryデータ編集者」の権限を選択し、「続行」をクリックします。

次のページでは、下部の「+鍵を作成」をクリックし、鍵を生成します。キーのタイプはJSONを使用します。

ダウンロードされた鍵のJSONファイルはプログラムの実行時に使用しますので、大切に保管しておきます。

鍵の生成が終わったら、「完了」を押して終了です。

ソースコード

さて、実際にBME280からデータを取得し、BigQueryにデータを保存するプログラムです。
とりあえず動作すればいいやと作ったのでかなりやっつけですが、以下のような感じです。

from google.cloud import bigquery
from pytz import timezone
import smbus2
import bme280


def main():
    # BME280で気温、湿度、気圧を取得
    data = get_bme280()
    # BigQueryにデータを送信
    bq_insert(data)


def get_bme280():
    """
    BME280からデータ取得
    :return:
    """
    port = 1
    address = 0x76
    bus = smbus2.SMBus(port)

    calibration_params = bme280.load_calibration_params(bus, address)
    data = bme280.sample(bus, address, calibration_params)

    return data


def bq_insert(data):
    """
    BigQueryにデータを送信
    :param data: BME280のデータ
    :return:
    """
    client = bigquery.Client()
    dataset_id = 'office_environment'
    table_id = 'environment_table'
    table_ref = client.dataset(dataset_id).table(table_id)
    table = client.get_table(table_ref)
    timestamp = timezone('Asia/Tokyo').localize(data.timestamp)
    rows = [{'timestamp': timestamp.isoformat(),
             'temperature': data.temperature,
             'humidity': data.humidity,
             'pressure': data.pressure}]
    errors = client.insert_rows_json(table, rows)

    assert errors == []


if __name__ == '__main__':
    main()

そんなに難しい内容ではないので、ソースを見ていただければわかるかと思います。
注意点としては、RPi.bme280で取得できるtimestampがdatetime型なのですが、ローカルタイムで設定されているので、UTCに変換してからBigQueryに送信しています。なぜかといえば、BigQueryは日時データは基本的にUTCとして扱うので、BigQueryで取り扱う際に混乱しないようにそうしています。

ただ、後ほど説明しますが、GoogleデータポータルがUTCから他のタイムゾーンに変更する仕組みを持たないため、ちょっと小細工が必要になります。それが面倒だという場合はUTCに変換せずローカルタイムのままBigQueryに保存してしまったほうがいいかもしれません。

プログラムの実行

作成したプログラムを実行する前に、先にダウンロードしてGCPの認証キーへのパスを環境変数に設定します。

export GOOGLE_APPLICATION_CREDENTIALS=./auth.json

この上でプログラムを実行するとBME280からデータを取得し、BigQueryに保存されます。

あとはこれを定期的に実行するようcronを設定するなどすれば良いと思います。

BigQueryのビューを設定

BigQueryで実際にデータが登録されているか確認します。コマンドでも確認できますが、GCPコンソールのほうがわかりやすいかと思いますので、コンソールを使用します。

コンソールでデータ登録用に作成したenvironment_tableを選択し、「プレビュー」タブをクリックするとこのようなリストが表示されます。

このままでデータポータルの設定に進んでもいいのですが、時刻がUTCのままなので、ちょっと直感的にローカルタイムでどうなの?っていうのがわかりにくいので、JSTに変換したビューを作成することで対応します。

ほんとならデータポータルでタイムゾーンを切り替えられる仕組みがあればいいんですけどねぇ…。

ビューの作成

BigQueryの画面の上部のクエリエディタに以下のクエリを入力します。(プロジェクトIDは自身のプロジェクトIDで読み替えてください)

SELECT FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', timestamp, 'Asia/Tokyo') AS timestamp_jst, temperature, humidity, pressure  FROM `プロジェクトID.office_environment.environment_table`

「実行」ボタンを押すと以下のようにタイムスタンプがtimestamp_jstとして変換されたものが表示されます。

「ビューを保存」をクリックして、このビューを保存します。保存先のテーブル名をここではenvironment_table_JSTとしておきます。Googleデータポータルからはこのビューを参照することにします。

Googleデータポータルの設定

Googleデータポータルにアクセスします。

「空のレポート」をクリックし、新しいレポートを作成します。

データソースを選択します。先程作成したビュー「environment_table_JST」を選択します。

データソースの編集

そのままだとtimestamp_jstが日付のみのデータとなっているかもしれません。まずはデータソースを編集します。上部メニューの「リソース」>「追加済みのデータソースの管理」を選択します。

表示されたリストの右側の「編集」をクリックします。

timestamp_jstの「タイプ」プルダウンメニューから、「日付と時刻」>「日付 時 (YYYYMMDDHH)」を選択します。選択したら、右上の「完了」ボタンをクリックします。

グラフの作成

続いてグラフを作成していきます。「グラフを追加」から、期間の下の「時系列グラフ」をクリックします。

「グラフを追加」から、期間の下の「時系列グラフ」をクリックします。

作成されたグラフの「指標」がRecord Countになっているのを、適当なデータに変更します。ここではtemperatureを設定してみます。

集計がSUMになっているので、1時間の間の値の合計値になってしまっています。ここでは平均に変更してみました。

「指標」のtemperatureの左のペンのアイコンをクリックし、「平均値」を選択します。

これで1時間平均の気温のグラフが作成できました。ただ残念なのは、うちではBigQueryには分単位でデータを取得していたんですが、Googleデータポータルは1時間単位でしかグラフ作成できないんですね…。

細かい時系列データの処理にはGoogle Datalabなんかもあるので、そちらを使ったほうがいいかもしれません。あるいは自前で作るかですね。

完成

とりあえずこんな感じのグラフができました。気温、湿度、気圧の変化を表示し、下の期間を変更すれば任意の期間のデータが表示できるようになっています。まだデータを取り始めて1日なので、1日分しか表示できてませんが、これからデータが溜まっていくのが楽しみです。

まとめ

あまり時間がないのでかなりざっくりとしたやり方ですが、一応環境データを取得、保存し、可視化するところまでかなり簡単にできました。Googleデータポータルはもうちょっと融通がきくともっと使いみちがありそうなんですが、このあたりは今後に期待したいところです。少なくともタイムゾーンの扱いや時系列データを秒単位ぐらいまではせめて処理できると助かるんですが。

タイトル

本文