みかんのゆるふわ技術ブログ

Raspberry PiやIoT関係のことを書き残していきます

Raspberry Piでセンサー情報グラフ化~その2 センサー情報をInfluxDBに投入!

前回の記事で、Raspberry Piに時系列データベースInfluxDBと、データ可視化ソフトGrafanaをインストールしました。

www.mikan-tech.net

今回は、センサー情報を取得してInfluxDBにデータを入れていきまます。 使用するセンサーは、Bluetooth Low Energy (BLE)で温度、湿度、気圧、照度が取れるSensorTagです。

最終的に、こんなダッシュボードの作成を目指します!

f:id:kimura_khs:20200820180343p:plain:w480

開発環境インストール

過去の記事で、SensorTagのセンサー値をPythonで読み取るサンプルを紹介しました。

www.mikan-tech.net

これにならい、Raspberry PiにbluepyというBluetooth Low Energy通信用のPythonライブラリを導入します。 まずは、必要なパッケージを導入します。

$ sudo apt install python3-venv

開発用のディレクトリsensortagを作り、そこにPythonのvenv環境を作ります。

$ mkdir sensortag
$ cd sensortag
$ python3 -m venv venv

bluepyを導入します。

$ ./venv/bin/pip install bluepy

これで開発環境の完成です。

SensorTagのセンサー値を1分周期で取得する

SensorTagのMACアドレスを取得

接続するSensorTagのMACアドレスを取得しておきます。 hcitoolを使って、BLEデバイスのスキャンを行います。sudo権限が必要です。

$ sudo hcitool lescan
LE Scan...
54:6C:0E:79:13:06 (unknown)
54:6C:0E:79:13:06 CC2650 SensorTag

周囲にBLE機器がたくさんあれば、大量のアドレスが出てくるかもしれません。CC2650 SensorTagというものを探しましょう。 私の場合、MACアドレスは54:6C:0E:79:13:06でした。

SensorTagへの接続とセンサ値読み取り

SensorTagへ接続するPythonプログラムは次の通りです。

from bluepy.sensortag import SensorTag

SENSORTAG_MAC_ADDRESS = "54:6C:0E:79:13:06"  # Change to your SensorTag MAC Address

# Connect to SensorTag
print("Connecting to " + SENSORTAG_MAC_ADDRESS)
stag = SensorTag(SENSORTAG_MAC_ADDRESS)
print("Connected.")

センサ値を取得する関数は次のようになります。

def get_data(stag):
    # Turn on sensors
    stag.humidity.enable()
    stag.barometer.enable()
    stag.lightmeter.enable()
    stag.battery.enable()

    # Waiting for sensor initialization
    time.sleep(1.0)

    # Read sensor value
    data = {}
    humid_sensor_value = stag.humidity.read()
    data['temperature'] = humid_sensor_value[0]
    data['humidity'] = humid_sensor_value[1]
    data['barometer'] = stag.barometer.read()[1]
    data['lightmeter'] = stag.lightmeter.read()
    data['battery'] = stag.battery.read()

    # Turn off sensors
    stag.humidity.disable()
    stag.barometer.disable()
    stag.lightmeter.disable()
    stag.battery.disable()

    return data

これで、get_data(stag)で各種センサーの値を読んでPythonの辞書形式で返すことができますね。

SensorTagのセンサ値を1分周期で取得する

SensorTagのセンサ値を1分周期で取得してみましょう。このように、Pythonで周期的に何かを実行する際に便利なのが、scheduleというライブラリです。

schedule.readthedocs.io

例によって、pipで簡単にインストールできます。

$ ./venv/bin/pip install schedule

こちらのように使います。

import schedule

def on_minute():
    global stag
    data = get_data(stag)
    print(data)
 
def main():
    schedule.every(1).minutes.do(on_minute)
    while True:
        schedule.run_pending()
        time.sleep(1)

if __name__=="__main__":
    main()

先ほどのプログラムにこちらのプログラムを追加すると、1分周期でget_data(stag)が呼ばれて、取得したセンサーデータを出力します。

schedule.every(1).minutes.do()で、1分周期で指定した関数を実行させることができます。 whileループでschedule.run_pending()を定期的に呼び出す必要があり、これが実行されたタイミングで1分経過していれば上記のon_minute()関数が実行されます。

InfluxDBへの書き込み

InfluxDBへはHTTP APIを用いて書き込みもできますが、Pythonの場合、InfluxDB-Pythonという便利なライブラリがあります。

influxdb-python.readthedocs.io

こちらのライブラリを使ってみましょう。インストールはpipで簡単です。

$ ./venv/bin/pip install influxdb

あらかじめ、データベースを作成しておきましょう。InfluxDB付属のシェルで、sensortagという名前のデータベースを作成します。 (もちろんPythonライブラリから作成もできますが、簡単のためシェルで作成します)

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

書き込むプログラムを作ってみましょう。

import influxdb
import datetime

db = influxdb.InfluxDBClient(
    host='localhost',
    port=8086,
    database='sensortag'
)

def write_to_influxdb(data):
    points = [{
        'measurement': 'sensortag',
        'tags': {
            'macaddr': stag.addr.replace(':','')
        },
        'time': datetime.datetime.utcnow(),
        'fields': data
    }]
    db.write_points(points)

db = influxdb.InfluxDBClient()で、InfluxDBへの接続を作成します。InfluxDBのホストの場所、ポート番号、ユーザ名、パスワード、データベース名を指定します。 書き込みは、db.write_points()で書き込むデータを渡します。データはmeasurement, time, tags, fieldsを含んだPython辞書形式をリストにします。

これで、先ほどのon_minute()を次のように置き換えます。

def on_minute():
    global stag
    data = get_data(stag)
    print(data)
    write_to_influxdb(data)

これで、1分ごとにセンサー値がInfluxDBに書き込まれるようになりました。

動作確認

実際に動かしてみましょう。SensorTagの電源を入れ、プログラムを実行します。

$  ./venv/bin/python main.py
Connecting to 54:6C:0E:79:13:06
Connected.
{'temperature': 27.14202880859375, 'humidity': 45.623779296875, 'barometer': 1009.81, 'lightmeter': 474.24, 'battery': 97}
{'temperature': 27.16217041015625, 'humidity': 45.648193359375, 'barometer': 1009.82, 'lightmeter': 475.52, 'battery': 97}
{'temperature': 27.1722412109375, 'humidity': 45.745849609375, 'barometer': 1009.82, 'lightmeter': 475.52, 'battery': 97}
{'temperature': 27.1923828125, 'humidity': 45.745849609375, 'barometer': 1009.82, 'lightmeter': 476.48, 'battery': 97}
{'temperature': 27.1923828125, 'humidity': 45.745849609375, 'barometer': 1009.78, 'lightmeter': 475.84000000000003, 'battery': 97}
{'temperature': 27.1923828125, 'humidity': 45.452880859375, 'barometer': 1009.82, 'lightmeter': 476.16, 'battery': 97}
{'temperature': 27.1923828125, 'humidity': 45.166015625, 'barometer': 1009.83, 'lightmeter': 474.56, 'battery': 97}
{'temperature': 27.2125244140625, 'humidity': 44.970703125, 'barometer': 1009.79, 'lightmeter': 475.2, 'battery': 97}
{'temperature': 27.20245361328125, 'humidity': 44.873046875, 'barometer': 1009.84, 'lightmeter': 475.52, 'battery': 97}

このように、1分ごとにセンサー値が取れていることがわかります。Ctrl-Cで終了できます。 InfluxDBに書き込めているかも見てみましょう。

$ influx
Connected to http://localhost:8086 version 1.8.1
InfluxDB shell version: 1.8.1
> USE sensortag
Using database sensortag
> SELECT * FROM sensortag
name: sensortag
time                barometer battery humidity        lightmeter         macaddr      temperature
----                --------- ------- --------        ----------         -------      -----------
1597904313341656000 1009.81   97      45.623779296875 474.24             98072D1D6600 27.14202880859375
1597904375204830000 1009.82   97      45.648193359375 475.52             98072D1D6600 27.16217041015625
1597904436923862000 1009.82   97      45.745849609375 475.52             98072D1D6600 27.1722412109375
1597904498641903000 1009.82   97      45.745849609375 476.48             98072D1D6600 27.1923828125
1597904560359710000 1009.78   97      45.745849609375 475.84000000000003 98072D1D6600 27.1923828125
1597904622076741000 1009.82   97      45.452880859375 476.16             98072D1D6600 27.1923828125
1597904683794782000 1009.83   97      45.166015625    474.56             98072D1D6600 27.1923828125
1597904745561521000 1009.79   97      44.970703125    475.2              98072D1D6600 27.2125244140625

見事に書き込めていますね。

サンプルプログラム

まとめのサンプルプログラムをこちらに置いておきます。

gistb19d2c0a6eed9b7501cc44d9dbe18598

通信エラーが出たら終了するようにしているなど、若干の変更を含んでいます。

続き

次回でいよいよInfluxDBに入れたデータをグラフ化して表示します。ぜひご覧ください。

www.mikan-tech.net