grasys blog
grasysブログ

ラズパイで取得した部屋の温湿度をGrafana Cloudで可視化したい

こんにちは松原です。

今回は趣味の話。

現在の自宅ではNature RemoのAPIを叩いてメトリクスを作成してGrafanaで可視化をしていた。
しかしNature RemoのAPI経由の温度情報は0.5℃単位で変動が起き、また温度が取得されるインターバルも長かったのでより詳細な情報が欲しかった。(綺麗な折れ線グラフになって欲しかった)

なので温湿度センサモジュールを購入し、そこからメトリクスを作成してGrafanaの可視化をすることにした。

センサ選び

測定精度が高めの精度のSHT35-DISを購入。
https://akizukidenshi.com/catalog/g/gK-15654/

ラズパイ接続

まずはラズパイのどこのIOピンに接続すれば良いかの確認を確認する。

IOピンの状態の表示コマンドを実行。

$ gpio readall

gpioコマンドが見つからなかったので以下のページを参考に
https://raspberrypi.stackexchange.com/questions/54116/gpio-command-not-found

$ docker run --rm --device /dev/ttyAMA0:/dev/ttyAMA0 --device /dev/mem:/dev/mem --privileged -ti python:2 /bin/sh
$ apt-get update && apt-get install git-core sudo
$ git clone https://github.com/WiringPi/WiringPi --depth 1
$ cd WiringPi/
$ ./build
$ gpio readall

IOピンの状態を確認することができた。

root@raspberry:~# gpio readall
 +-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | IN   | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | IN   | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+

以上の情報から

センサ側ピンピン名Physical
VDD3.3v1
SDASDA.13
SCLSCL.15
ADR接続なし
GND0v6

で接続を行う。

I2Cの有効化

$ sudo raspi-config

Raspberry Piの設定画面が開くので以下のように選択を行い有効化する
Interface Options > I2C > YES
最後に
Finish
で完了

I2C通信の確認を行なう。

root@raspberry:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- 45 -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --     

アドレス0x45にマッピングされていることが確認できる。

Goでメトリクス出力

ここからはGoアプリケーションによってPrometheusのフォーマットのメトリクスを出力するために実装を行なっていく。

i2c-toolsが必要なのでまずはラズパイ側にライブラリをインストール。

$ apt-get install i2c-tools

Goの初期化とモジュール取得

適当な名前のプロジェクトを作成してモジュールをセットアップする。

$ mkdir sht35-exporter
$ cd sht35-exporter
$ go mod init sht35-exporter

Prometheusメトリクスの取得のモジュールと、ちょうど良いセンサ操作モジュールがあったので、それらを取得する。

$ go get github.com/prometheus/client_golang/prometheus
$ go get github.com/d2r2/go-i2c
$ go get github.com/d2r2/go-sht3x

センサ情報を取得してメトリクス取得用サーバーの構築を実装する。
先ほどのアドレス0x45を設定する。
portは適当に9257でLISTENするよう設定した。

package main  

import (  
   "github.com/d2r2/go-i2c"  
   "github.com/d2r2/go-sht3x"
   "github.com/prometheus/client_golang/prometheus" 
   "github.com/prometheus/client_golang/prometheus/promhttp"
   "log"
   "net/http"
   "time"
)  

var temperatureGauge = prometheus.NewGauge(prometheus.GaugeOpts{  
   Namespace: "i2c",  
   Name:      "temperature",  
})  

var humidityGauge = prometheus.NewGauge(prometheus.GaugeOpts{  
   Namespace: "i2c",  
   Name:      "humidity",  
})  

func main() {  
   prometheus.MustRegister(temperatureGauge)  
   prometheus.MustRegister(humidityGauge)  
   go getTemperature()  

   http.Handle("/metrics", promhttp.Handler())  
   if err := http.ListenAndServe(":9257", nil); err != nil {  
      log.Fatal("ListenAndServe:", err)  
   }  
}  

func getTemperature() {  
   i2c, err := i2c.NewI2C(0x45, 1)  
   if err != nil {  
      log.Fatal(err)  
   }  
   defer i2c.Close()  

   sensor := sht3x.NewSHT3X()  
   err = sensor.Reset(i2c)  
   if err != nil {  
      log.Fatal(err)  
   }  

   for {  
      temp, rh, err := sensor.ReadTemperatureAndRelativeHumidity(i2c, sht3x.RepeatabilityHigh)  
      if err != nil {  
         log.Fatal(err)  
      }  
      temperatureGauge.Set(float64(temp))  
      humidityGauge.Set(float64(rh))  

      time.Sleep(10 * time.Second)  
   }  
}

sht35-exporterという名前でビルドを行う。

$ GOOS=linux GOARCH=arm64 go build -trimpath -o sht35-exporter .

バイナリファイルをラズパイの適当な場所に設置する。
今回は/usr/local/bin/に配置を行なった。

あとはバイナリをを実行する。

$ /usr/local/bin/sht35-exporter &

Grafana Agent

既に設定をしていたので省略。
エージェントのセットアップは以下を参照。
https://grafana.com/blog/2021/01/26/how-to-connect-and-monitor-your-raspberry-pi-with-grafana-cloud/

スクレイピング設定に以下の設定を追加。

        - job_name: integrations/i2c
          static_configs:
            - targets:
                - localhost:9257

既にGrafana Agentを起動していたので再起動。

$ systemctl restart grafana-agent.service

結果

Grafana側で Namespace_Name の形でメトリクス名が取得できるので、今回は
温度: i2c_temperature
湿度: i2c_humidity
でメトリクス名を設定。

あとはダッシュボードをいい感じに整えて完成。