はじめに
こんにちは、Stackdriver担当者です。同僚の @proppy と Pimoroni 見てたら、便利そうなHATとセンサーがあったので買って遊んでいます。
Pimoroni Breakout Garden pHAT - ブレークアウト ガーデン pHAT
- 出版社/メーカー: Pimoroni
- メディア: エレクトロニクス
- この商品を含むブログを見る
Pimoroni BME680 ブレークアウト - 空気汚染 温度 湿度 気圧 センサー
- 出版社/メーカー: Pimoroni
- メディア: エレクトロニクス
- この商品を含むブログを見る
TL;DR
BME680で取得したデータをStackdriver Monitoringでダッシュボード作って見てみると楽しい。
BME680
BME680とは
BME680は、BOSCH製の空気質センサーで、この3mm四方の小さなセンサーだけで気温、湿度、大気圧、空気質が測定できます。
さらにこのセンサーのブレイクアウトがPimoroniから販売していて、I2Cを使って簡単に数値を読み取れるというわけです。
セットアップ
RaspberryPi Zero W は Raspbian (Stretch) が動いている前提です。
$ sudo apt-get install python3-venv i2c-tools read-edid libi2c-dev python3-smbus $ python3 -m venv --system-site-packages .venv $ .venv/bin/pip install bme680 $ wget https://raw.githubusercontent.com/pimoroni/bme680-python/master/examples/read-all.py $ .venv/bin/python3 read-all.py
これでちゃんと数値が表示されたらBME680を無事に認識しているので準備完了。 これを使って部屋の気温、湿度、気圧、空気室などを記録してみます!
Stackdriver Monitoring へのデータの送信
Stackdriver Monitoringとは
Stackdriver Monitoringは、通常Monitoring Agentと呼ばれるエージェントをインスタンス上で実行し、システムやアプリケーションのメトリクスをサンプリングすることを想定しています。特によく利用されるデータベースやミドルウェアに関しては事前定義のメトリクスを簡単にStackdriver Monitoringに送信できます。
カスタム指標(カスタムメトリクス)
そして、もちろん自分のアプリケーションの状況を伝えるためのカスタム指標をエージェント経由で送信することもできますが、今回は別の方法としてStackdriver Monitoring API v3 を使って送信してみます。
今回は上のようにBME680のデータをPythonで取ってきているので、そのままPythonクライアントを使って送信しようと思います。
ライブラリセットアップ
上記に加えて google-cloud-monitoring
のパッケージをインストールする必要がありますが、ここで一つ嵌りどころとして依存先の grpcio
パッケージのインストールがあります。Raspberry Pi はSDカード上でOSを走らせているので、なるべくSDカードの寿命を延命させるために /tmp
や /var/tmp
を tmpfs 上でマウントしたりします。自分も何も考えずにそうしていたのですが、これが grpcio
パッケージのインストール時にネックとなります。
google-cloud-monitoring
パッケージが依存している grpcio
パッケージの最新バージョンは本記事執筆時当時は 1.19.0 です。執筆時の Raspbian Stretch でのデフォルトのPython 3のバージョンは 3.5 なのですが、上のPyPIのページを見るわかるように 1.19.0 には CPython 3.5 の ARMv6ターゲットの wheel がありません。
また piwheels を見ても 1.18.0 までは CPython 3.5 の ARMv6 ターゲットの wheel があるのですが、1.19.0 はありません。
そうなると手っ取り早い方法としては選択肢は2つなります。*1
- constraints.txt などで
grpcio
パッケージは 1.18.0 以前に固定(依存的には 1.8.0 以上であればよい)し、--extra-index-url=https://www.piwheels.org/simple
のオプションをpip install
に加える grpcio
1.19.0 をローカルでビルドすることに決めて、pip
に--build
と--cache-dir
のオプションを/tmp
以外の場所に設定する
自分は新しいライブラリで問題ないかも確認したかったので grpcio
1.19.0 をローカルでビルドすることにして、何も設定せずにそのまま google-cloud-monitoring
パッケージをインストールしました。(結構時間がかかる)
$ TMPDIR=$HOME/tmp .venv/bin/pip install --cache-dir=$TMPDIR/cache --build=$TMPDIR/build google-cloud-monitoring
1. メトリクスの作成
先に挙げたドキュメントのとおりなのですが、カスタムメトリクスを記録するためには、まずカスタムメトリクス自体をStackdriver Monitoringに登録する必要があります。 流れとしては
- Stackdriver Monitoringのクライアントのインスタンスを作成
MetricDescriptor
のインスタンスを作成し、カスタムメトリクス名、メトリクスのタイプ、メトリクスの値の型、メトリクスの説明書き、メトリクスのラベルを設定- クライアントに今作成した
MetricDescriptor
のインスタンスを渡して、メトリクスを作成
のようになります。次は temperature
というカスタムラベルを作成しています。実際にはセンサーが取得できる presssure
、humidity
、 gas_resistance
についても同様に作成しています。
client = monitoring_v3.MetricServiceClient() project_name = client.project_path(project_id) descriptor = monitoring_v3.types.MetricDescriptor() descriptor.type = "custom.googleapis.com/temperature" descriptor.metric_kind = ( monitoring_v3.enums.MetricDescriptor.MetricKind.GAUGE) descriptor.value_type = ( monitoring_v3.enums.MetricDescriptor.ValueType.DOUBLE) rainfall_label = descriptor.labels.add() rainfall_label.key = "rainfall" rainfall_label.value_type = ( monitoring_v3.enums.LabelDescriptor.ValueType.INT64) rainfall_label.description = "rainfall observation report from weather forecast service" descriptor.description = "room temperature" descriptor = client.create_metric_descriptor(project_name, descriptor)
ここでメトリクスのラベルを設定していますが、これは取得するメトリクスに紐づいて取得時ごとに変化する付加情報を入れるためのものです。今回のサンプルでは温度や湿度を取るわけですが、その際に外の天気との関係性を知りたくなるでしょう。そのため、天気予報サイトから雨量の情報を取得し、 rainfall
ラベルに入れることにしました。
実際のユースケースでは、例えばウェブアプリケーションの場合、「レスポンスデータのサイズ」をメトリクスにしていた場合、ステータスコードが400番台のものだけのグラフを作りたい場合に、「ステータスコード」をラベルとして設定しておきます。
またこの create_metric_descriptor
はまったく同盟のメトリクスが存在する場合は特にエラーが起きず上書きされ、エラーになることはありません。(メトリクスが存在するかどうか事前に確認しなくても大丈夫です。)
これをプログラムの開始時にだけ1度実行します。
2. メトリクスデータの書き込み
こちらもドキュメントのとおりです。ある瞬間のセンサーデータを登録する場合の流れは
TimeSeries
インスタンスを作成- カスタムメトリクス名、メトリクスのラベルの値を設定
- リソースのラベルを設定
TimeSeries
にメトリクスデータが入ったPoint
を追加- クライアント経由で
TimeSeries
をStackdriver Monitoringに送信
# 1. TimeSeriesの作成 series = monitoring_v3.types.TimeSeries() # 2. カスタムメトリクス名、メトリクスのラベルの値を設定 series.metric.type = "custom.googleapis.com/temperature" series.metric.labels['rainfall'] = fetch_rainfall() # 3. リソースのラベルを設定 # https://cloud.google.com/monitoring/custom-metrics/creating-metrics#which-resource series.resource.type = 'generic_node' series.resource.labels['location'] = 'asia-northeast1-a' series.resource.labels['namespace'] = RESOURCE_NAMESPACE series.resource.labels['node_id'] = socket.gethostname() # 4. `TimeSeries` にメトリクスデータが入った `Point` を追加 sensor = bme680.BME680() # 実際はプログラム起動時にインスタンス作成 sensor.get_sensor_data() point = series.points.add() point.value.double_value = value now = time.time() point.interval.end_time.seconds = int(now) point.interval.end_time.nano = int( (now - point.interval.end_time.seconds) * 10**9) # 5. クライアント経由で `TimeSeries` をStackdriver Monitoringに送信 client.create_time_series(project_name, [series])
リソースのラベルを設定する部分では generic_node
を設定しています。(本来は global
を設定すべきかも)リソースラベルはメトリクスラベルと違い、時間が経過してもそのデータを取得する上において変化しない属性を記録します。たとえば、マシンのホスト名などです。
どのリソースタイプでどのリソースラベルを設定するかは次のページに記載されています。
Point
の追加で注意しなければいけないことは、TimeSeries
を送信する際には Point
が2つ以上含まれていてはいけないということ。公式ドキュメントを引用します。
When creating a time series, this field must contain exactly one point and the point's type must be the same as the value type of the associated metric. If the associated metric's descriptor must be auto-created, then the value type of the descriptor is determined by the point's type, which must be BOOL, INT64, DOUBLE, or DISTRIBUTION.
したがって、上のように Point
を1つだけ追加しておしまいです。 *2
逆に TimeSeries
のインスタンスはクライアント経由でまとめて送信できます。今回はセンサーで取れる値が温度、湿度、気圧、空気質の4つあるので、上と同じ流れで4つ TimeSeries
をつくって、まとめて送信します。
これを10秒おきなど、定期的に実行します。
Stackdriver Monitoringの設定
以上のようなコードでデータをStackdriver Monitoringに送信し続けると、ダッシュボードでメトリクスとして選択できるようになります。
この自分で作成した custom/temperature
のメトリクスを選択すると、送信されたデータを元に作成されたグラフが表示され、さらにFilterの項目ではリソースラベルとメトリクスラベルでの絞り込みができるようになっています。
それ以下、Aggregationの項目ではグラフの書き方などについての一般的な設定を行っていき、SAVEボタンでチャートを保存します。そのようにして以下、湿度、気圧、空気質に関しても同様に行っていくとダッシュボードが完成します。
部屋の温度が日の出とともにぐっと上昇する様子や、湿度が人間の生活時間に合わせて上昇する様子、今日は高気圧であるなとわかるなど、記録を取るだけでかなり面白かったです。次はこれを複数台に増やしてチャートに重ねてみようと思います。
参照
BME680
- BME680
- https://cdn-shop.adafruit.com/product-files/3660/BME680.pdf
- Getting Started with BME680 Breakout - Pimoroni Yarr-niversity
- pimoroni · PyPI
- Pimoroni Ltd · GitHub
- https://cdn-shop.adafruit.com/product-files/3660/BME680.pdf
Stackdriver Monitoring V3
- python-docs-samples/snippets.py at master · GoogleCloudPlatform/python-docs-samples · GitHub
- Monitored Resource Types | Stackdriver Monitoring | Google Cloud
- google-cloud-python/monitoring/google/cloud/monitoring_v3/proto at master · googleapis/google-cloud-python · GitHub
- googleapis/google/api at master · googleapis/googleapis · GitHub