概要
RaspberryPi4と温湿度気圧計(BME680)をつなぎ、データを取得します。同ラズパイ上にInfluxDBを起動し、API経由で、取得したデータを格納します。
BME680をつなぐ
BME680をRaspberry Pi 4で使ってみる #RaspberryPi - Qiita 前の記事を参考に接続し、BME680から値を取得できることを確認します。
InfluxDBを起動
dockerで起動します。
起動&接続確認
docker-composeファイルを作成します
services:
influxdb:
image: influxdb:2.7.6
container_name: influxdb-local
volumes:
- ./docker/influxdb2/data/:/var/lib/influxdb2/
- ./docker/influxdb2/config/:/etc/influxdb2/
ports:
- 8086:8086
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=my_secret_password
- DOCKER_INFLUXDB_INIT_ORG=MyOrganization
- DOCKER_INFLUXDB_INIT_BUCKET=MyBucket
docker compose up -d
起動できたらInfluxDBのWebクライアントに接続します http://localhost:8086/ 。初期アカウントはcompose.yaml
のenvに指定しているadmin
/my_secret_password
となります。接続できることを確認します。
APIを使ってみる
API Token発行
APIで格納するためにAPI認証するためのTokenを発行します。
- 左メニューの「Load Data」 > API TOKENS > 「GENERATE API TOKEN」を押下 > とりあえず「Custom Access API Token」を作成
- Descriptionに適当にわかり易い名前をつける
- Resources > Buckets > とりあえず「All Buckets」の「Read」と「Write」にチェックを入れる
- 「GENERATE」押下で作成
BME680のデータを投入
pythonであれば、ライブラリinfluxdb_client
があるので、pythonを使いました。温湿度気圧を取得し、APIに格納します。
import datetime
from dataclasses import dataclass
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
TOKEN = "xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxx==" # 先程生成したTOKENを設定
ORGANIZATION = "MyOrganization"
BUCKET = "MyBucket"
URL = f"http://localhost:8086"
MEASUREMENT = "sample"
BME680_ADDRESS = "0077"
BME680_DIR = f"/sys/bus/i2c/devices/1-{BME680_ADDRESS}/iio:device0"
@dataclass
class Bme680Data:
"""Bme680から取得した温湿度気圧データ"""
humidity: float
"""相対湿度[%]"""
pressure: float
"""気圧[hPa]"""
resistance: int
"""抵抗値"""
milli_temperature: int
"""気温 [ミリ℃]"""
def get_temperature(self) -> float:
"""単位はミリ℃で格納されているようなので1000で割る(例: 27820℃ -> 27.820℃)"""
return self.milli_temperature / 1000.0
class Bme680Reader(object):
"""Bme680のデータを取得します"""
def __init__(self, bme680_dir: str):
super().__init__()
self.bme680_dir = bme680_dir
def fetch(self):
"""Bme680から温湿度気圧データを取得します"""
with open(
f"{BME680_DIR}/in_humidityrelative_input", "r", encoding="utf-8"
) as humidity_reader, open(
f"{BME680_DIR}/in_pressure_input", "r", encoding="utf-8"
) as pressure_reader, open(
f"{BME680_DIR}/in_resistance_input", "r", encoding="utf-8"
) as resistance_reader, open(
f"{BME680_DIR}/in_temp_input", "r", encoding="utf-8"
) as temp_reader:
# blackにフォーマット任せたらこうなったけど、なんか奇妙↑
humidity = float(humidity_reader.readline())
pressure = float(pressure_reader.readline())
resistance = int(resistance_reader.readline())
milli_temp = int(temp_reader.readline())
humidity_reader.close()
pressure_reader.close()
resistance_reader.close()
temp_reader.close()
return Bme680Data(humidity, pressure, resistance, milli_temp)
def __str__(self):
return self.bme680_dir
def main():
"""ラズパイ上でBME680の温湿度気圧データを取得してInfluxDBへ投入します"""
write_client = InfluxDBClient(url=URL, token=TOKEN, org=ORGANIZATION)
write_api = write_client.write_api(write_options=SYNCHRONOUS)
bme680_reader = Bme680Reader(BME680_DIR)
bme680_data = bme680_reader.fetch()
# timezoneをしっかり設定しないと投入される時刻がおかしくなる。
# JST環境では+9時間後の時刻で投入された・・・
localTimeZone = datetime.datetime.now().astimezone().tzinfo
timestamp = datetime.datetime.now(localTimeZone)
point = (
Point(MEASUREMENT)
.tag("sensor", "bme680") # tagは追加できます
.field("temperature", bme680_data.get_temperature())
.field("humidity", bme680_data.humidity)
.field("pressure", bme680_data.pressure)
.field("resistance", bme680_data.resistance)
.time(timestamp)
)
write_api.write(bucket=BUCKET, org=ORGANIZATION, record=point)
print(f"Point: {str(point)}")
if __name__ == "__main__":
main()
下記のようにスクリプトを起動しデータを投入します。
# InfluxDBのライブラリをインストール
pip3 install influxdb-client --break-system-packages
# 実行
python3 post_sample.py
break-system-packages
したくない場合は、下記のように仮想環境を作ってから実行します。
# 新しい仮想環境を作成
python3 -m venv .venv
source .venv/bin/activate
pip3 install influxdb-client
python3 post_sample.py
# 仮想環境終了
deactivate
データの確認
- InfluxDBのWebクライアントに接続します http://localhost:8086/
- 左メニュー「Data Explorer」 > 「FROM」にバケット一覧が表示されているので「MyBucket」を選択 > Filter/
_measurement
で「sample」を選択 > Filter/_field
で「temperature」等を選択 > 「SUBMIT」ボタンを押下 - グラフが表示されることを確認
- 表示されない場合はグラフの表示期間(「SUBMIT」ボタンの2つほど左のプルダウン)で表示を広げてみる。
cronに指定
毎分実行するようにします。
crontab -e
下記のようなcron設定を記述します。
LANG=ja_JP.UTF-8
SHELL=/bin/bash
* * * * * python3 path/to/post_sample.py &>>cronrun.log
# 仮想環境の場合
# * * * * * cd "path/to/post_sample_dir" && source .venv/bin/activate && python3 post_sample.py &>>cronrun.log
おまけ
curlでデータ投入するサンプル
サクッとInfluxDBへ投入したいときはこちらが使えます。
TOKEN="xxxxx"
ORGANIZATION="MyOrganization"
BUCKET="MyBucket"
API_URL="http://localhost:8086/api/v2/write?org=${ORGANIZATION}&bucket=${BUCKET}&precision=ns"
MEASUREMENT="sample"
curl -fv \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: text/plain; charset=utf-8" \
-H "Accept: application/json" \
-d @- \
-X POST "$API_URL" <<EOS
{{{ここにLineProtocolフォーマットで、改行区切りでバルクインサートできるっぽいがうまくいかなかった}}}
EOS
下記に具体例を示します。
curl -fv \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: text/plain; charset=utf-8" \
-H "Accept: application/json" \
-d @- \
-X POST "$API_URL" <<EOS
${MEASUREMENT},sensor=bme680 humidity=61.613,pressure=1006.88,resistance=16422i,temperature=31.59 1719757981665187000
EOS
エポック秒・ミリ秒・マイクロ秒・ナノ秒 早見表
日時 | エポック | 単位 | 桁 | 指数表記 |
---|---|---|---|---|
2024年6月30日 23:16:11 | 1719756971 | 秒 | 10 | |
2024年6月30日 23:16:11.629 | 1719756971629 | ミリ秒 | 13 | 10^-3 |
2024年6月30日 23:16:11.629074 | 1719756971629074 | マイクロ秒 | 16 | 10^-6 |
2024年6月30日 23:16:11.629074000 | 1719756971629074000 | ナノ秒 | 19 | 10^-9 |