「switchbotの部屋の気温をGrafana,InfruxDBで可視化してみる」 可視化愛好家、前加賀美の今日も可視化日和!! #1

スポンサーリンク
tech系(python)
スポンサーリンク
前加賀美
前加賀美

どうも、可視化愛好家の前加賀美 Necozay Gurlukovich(まえかがみ・ねこぜい・ごるるこびっち)です。

テレワークも常駐化してきて自室の環境がとても大事になってきましたので、部屋の環境を少しでも改善するため、部屋の不快な度合いを可視化します。

今回は、Amazon prime 感謝祭で割引で購入したswitchbotを使用します。

割引で1500円くらいで買いました。

今回すること

switchbotで取得されている気温のデータをpythonで取得して、それをGrafanaで表示させます。

気温に関してはswitchbotに連携したアプリで見れるんですけどね!

これは今後色々カスタマイズしていくとするということで、その前段として今回の可視化を試します。

環境はラズベリーパイで行います。

InfluxDB

まずはinfuxdbの設定です。(influxdbがまだ入っていない想定で書いてます。)

infuxdbの役割は時系列でデータを格納していきます。

今回の場合ですと、気温が時系列データとして格納されていきます。

ラズベリーパイの中に入って、下記のコマンドを実行していきます。

$ sudo apt update
$ sudo apt install influxdb

$ sudo pip3 install influxdb
$ sudo apt install influxdb-client

$ sudo systemctl unmask influxdb.service
$ sudo systemctl start influxdb

infuxdb内にDBを作成します。

$ influx
Connected to http://localhost:8086 version 1.6.4
InfluxDB shell version: 1.6.4
> CREATE DATABASE tempDB
> exit

これでinfuxdb側の設定は完了です。

python実装

次にpythonです。(pythonはもう入っている想定で書いてます。)

pythonの役割はswitchbotから値を取得することです。

bluepyをインストールします。

$ sudo pip3 install bluepy

switchbotから値を取得するコードを書いていきます。

取得した値をinfluxdbに接続し、格納する部分も書いています。

switchbotから値を取得するコードは以下

from influxdb import InfluxDBClient
import struct
import sys
from bluepy.btle import Scanner, DefaultDelegate
import time
from datetime import datetime

# データベースに接続
dbclient = InfluxDBClient(host='localhost', port=8086, database='tempDB')

#Broadcastデータ取得用デリゲート
#class SwitchbotScanDelegate(btle.DefaultDelegate):
class SwitchbotScanDelegate(DefaultDelegate):
    #コンストラクタ
    def __init__(self, macaddr):
        #btle.DefaultDelegate.__init__(self)
        DefaultDelegate.__init__(self)
        #センサデータ保持用変数
        self.sensorValue = None
        self.macaddr = macaddr
 
    # スキャンハンドラー
    def handleDiscovery(self, dev, isNewDev, isNewData):
        # 対象Macアドレスのデバイスが見つかったら
        if dev.addr == self.macaddr:
            # アドバタイズデータを取り出し
            for (adtype, desc, value) in dev.getScanData():  
                #環境センサのとき、データ取り出しを実行
                if desc == '16b Service Data':
                    #センサデータ取り出し
                    self._decodeSensorData(value)
 
    # センサデータを取り出してdict形式に変換
    def _decodeSensorData(self, valueStr):
        #文字列からセンサデータ(4文字目以降)のみ取り出し、バイナリに変換
        valueBinary = bytes.fromhex(valueStr[4:])
        #バイナリ形式のセンサデータを数値に変換
        batt = valueBinary[2] & 0b01111111
        isTemperatureAboveFreezing = valueBinary[4] & 0b10000000
        temp = ( valueBinary[3] & 0b00001111 ) / 10 + ( valueBinary[4] & 0b01111111 )
        if not isTemperatureAboveFreezing:
            temp = -temp
        humid = valueBinary[5] & 0b01111111
        #dict型に格納
        self.sensorValue = {
            'SensorType': 'SwitchBot',
            'MacAddr': self.macaddr,
            'Temperature': temp,
            'Humidity': humid,
            'Battery': batt
        }


def send_temp_data(macaddr):
    # macaddr指定した温湿度センサの値を取得
    macaddr = str.lower(macaddr)
    scanner = Scanner().withDelegate( SwitchbotScanDelegate(macaddr) )
    #スキャン(timeout9s)
    scanner.scan( 9.0 )
    temp=0
    #出力
    try:
        temp = str(scanner.delegate.sensorValue['Temperature'])
    except TypeError as e:
        print("Temporarily lost communication with Bluetooth temperature device.",e) 
    except:
        import traceback
        traceback.print_exc()
    
    return  temp
 
if __name__ == '__main__':
    while True:
        print("temp is  : ", send_temp_data('FE:EA:12:3D:E8:00'))
        
        json_body = [
            {
                "measurement": "temp_measurement",
                "time": datetime.utcnow(),
                "fields": {
                    ## ★XX:XX:XX:XX:XX:XXにはswitchbotのmacアドレスを入れてください
                    "temp": float(send_temp_data('XX:XX:XX:XX:XX:XX')),
                }
            }
        ]
        dbclient.write_points(json_body)
        time.sleep(10)

実際に実行してみると以下のように部屋の気温が取得できると思います。

$ sudo python3 switchbot.py

## 実行結果
temp is  :  22.9

上記のコードの

# データベースに接続
dbclient = InfluxDBClient(host='localhost', port=8086, database='tempDB')

の部分で、infruxdbと接続しています。

これでpythonコードを実行している間、infruxdbにデータが蓄積します。

このデータをGrafanaで可視化しようという流れです。

ですので、常にデータを表示するときはpythonを実行し続ける必要があります。

Grafana

次にGrafanaです。(Grafanaがまだ入っていない想定で書いてます。)

Grafanaはデータを可視化するダッシュボードを提供します。

以下のコマンドを実行していきます。

$ sudo apt install -y apt-transport-https
$ sudo apt install -y software-properties-common wget
$ wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
$ echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt update
$ sudo apt install grafana
$ sudo systemctl daemon-reload
$ sudo systemctl start grafana-server

http://<ラズベリーパイのIP>:3000にアクセスする。

すると、以下のようなログイン画面が出ていればOK

😫ラズパイのgrafanaにブラウザから接続できない問題が出た場合

ブラウザでGrafanaにアクセスしようとすると以下のようにGrafanaの画面が表示されないことがあります。

これに関しては、画像にも書いてある通りファイアウォール周りに問題がある可能性があります。

ラズベリーパイで以下のコマンドを実行して、

$ sudo ufw status | grep 3000

以下の出力がされない場合は、ファイアウォールに設定が必要です。

3000/tcp                   ALLOW       Anywhere                  
3000/tcp (v6)              ALLOW       Anywhere (v6)

Grafanaのポートをファイアウォールに設定するには以下を実行します。

$ sudo ufw allow 3000/tcp

これで以下のように表示できると思います。

ここからGrafanaのinfluxdbの説明は画像が多くなるので割愛しますが、

ググると結構でてきますので、それらを参考にすると良いです。

そこまでハマらないかと思います。

ハマるとしたら、pythonでswitchbotのデータをinfluxdbに格納するときにstr型で格納してしまい、プロットが上手くいかないといったところがあるのでそこは注意します。

ということで、以下のようにプロットができました。

タイトルとURLをコピーしました