前回の記事で、Raspberry Piに時系列データベースInfluxDBと、データ可視化ソフトGrafanaをインストールしました。
今回は、センサー情報を取得してInfluxDBにデータを入れていきまます。 使用するセンサーは、Bluetooth Low Energy (BLE)で温度、湿度、気圧、照度が取れるSensorTagです。
最終的に、こんなダッシュボードの作成を目指します!
開発環境インストール
過去の記事で、SensorTagのセンサー値をPythonで読み取るサンプルを紹介しました。
これにならい、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というライブラリです。
例によって、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に入れたデータをグラフ化して表示します。ぜひご覧ください。