ラズパイ+BME280で温度・湿度・気圧を計測(BMP280は湿度なし):ラズパイとPPD42NJダストセンサー 自宅PM2.5値を自作で計測:InfluxDBがデータを保存しない!8086ポート閉じてInfluxDB SYN FLOOD攻撃とみなされてデータを保存しなくなった

ラズパイとBME280で温度・湿度・気圧を計測してInfuxDBに送信、Grafanaで表示するまでの作業をしてみます。

2019年の初めころに完成してましたが、記事にしてなかったので紹介します。といっても多くの他のスゴイ方がやっているのであまり参考にならないかもしれませんが・・・備忘録的に書いておきます。

この記事は複数のページに別れています
  1. (今このページを見ています)
BME280
BME280を磁石でくっつけて棚裏に設置

BME280とラズパイで温度・湿度・気圧を計測

BME280買ったとこ

ebayが安かったので送料無料で送ってもらいました。

1PCS BME280 Embedded high-precision barometric pressure sensor module height

1PCS BME280 Embedded high-precision barometric pressure sensor module height

こっち↓のBME280のほうがもっとちゃんとしてるっぽいけど同じかな?

BME280搭載 温湿度・気圧センサモジュール

BME280搭載 温湿度・気圧センサモジュール

湿度を取得できないBMP280も誤って買ってしまった。誤ってというより安さに飛びついて買ってしまった・・・BMP280は買わないほうがいいと思います。

BMP280 Pressure Sensor Module High Precision Atmospheric 3.3V Replace BMP180

BMP280 Pressure Sensor Module High Precision Atmospheric 3.3V Replace BMP180

では、ラズパイと接続していきましょう。

PIN

I2C(Inter-Integrated Circuit)通信を使うのでGPIO2(SDA),GPIO3(SCL)に接続します。

反対側にGND・3.3V・SDA・SDLがあるけど使わない。

BME280Raspberry Pi
GNDGND
3.3VVCC
SCKGPIO3(SCL)
SDO
SDIGPIO2(SDA)
SDD

i2cを有効にする

raspi-configでI2Cを有効にする。

$ sudo raspi-config
[5 Interfacing Options] [I2C] [enabled?はい]

modulesで「i2c-dev」が記入されているか確認します。

$ sudo vim /etc/modules
i2c-dev

i2cdetectで確認

BME280をラズパイと接続後、ラズパイに認識されているかi2cdetectコマンドで確認します。

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --

76に来てました。

SWITCHSCIENCEのサンプル

https://github.com/SWITCHSCIENCE/samplecodes/tree/master/BME280

こちらのサンプルを使わせていただきました。

$ wget https://github.com/SWITCHSCIENCE/samplecodes/tree/master/BME280/Python27/bme280_sample.py
$ sudo apt-get -y install python-pip #pip無い場合はインストールする。
$ sudo pip install smbus2 #smbus2が必要なのでインストールする。

サンプルを実行してみます。

$ python bme280_sample.py
temp : 23.10  ℃
pressure : 1000.65 hPa
hum :  37.07 %

正常に取得できているみたい!

温度・湿度・気圧を取得してInfuxDBに投げるスクリプト

サンプルスクリプトをちょっと改造してInfluxDBに登録できるようにした。

#coding: utf-8
# encoding: utf-8

from influxdb import InfluxDBClient
client = InfluxDBClient(host='localhost', port=8086, username='root', password='xxxx', database='sensor')
measurement = 'air5'
tags = {'place': 'leaf-bme280','host': 'raspi3B+'}

from smbus2 import SMBus
import time

bus_number  = 1
i2c_address = 0x76

bus = SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0


def writeReg(reg_address, data):
	bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
	calib = []
	
	for i in range (0x88,0x88+24):
		calib.append(bus.read_byte_data(i2c_address,i))
	calib.append(bus.read_byte_data(i2c_address,0xA1))
	for i in range (0xE1,0xE1+7):
		calib.append(bus.read_byte_data(i2c_address,i))

	digT.append((calib[1] << 8) | calib[0])
	digT.append((calib[3] << 8) | calib[2])
	digT.append((calib[5] << 8) | calib[4])
	digP.append((calib[7] << 8) | calib[6])
	digP.append((calib[9] << 8) | calib[8])
	digP.append((calib[11]<< 8) | calib[10])
	digP.append((calib[13]<< 8) | calib[12])
	digP.append((calib[15]<< 8) | calib[14])
	digP.append((calib[17]<< 8) | calib[16])
	digP.append((calib[19]<< 8) | calib[18])
	digP.append((calib[21]<< 8) | calib[20])
	digP.append((calib[23]<< 8) | calib[22])
	digH.append( calib[24] )
	digH.append((calib[26]<< 8) | calib[25])
	digH.append( calib[27] )
	digH.append((calib[28]<< 4) | (0x0F & calib[29]))
	digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
	digH.append( calib[31] )
	
	for i in range(1,2):
		if digT[i] & 0x8000:
			digT[i] = (-digT[i] ^ 0xFFFF) + 1

	for i in range(1,8):
		if digP[i] & 0x8000:
			digP[i] = (-digP[i] ^ 0xFFFF) + 1

	for i in range(0,6):
		if digH[i] & 0x8000:
			digH[i] = (-digH[i] ^ 0xFFFF) + 1  

def readData():
	data = []
	for i in range (0xF7, 0xF7+8):
		data.append(bus.read_byte_data(i2c_address,i))
	pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
	temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
	hum_raw  = (data[6] << 8)  |  data[7]
	
	temp = compensate_T(temp_raw)
	pres = compensate_P(pres_raw)
	humi = compensate_H(hum_raw)
	print round(temp,2)
	print round(pres,2)
	print round(humi,2)
	json_body = [
		{
			'measurement': measurement,
			'tags': tags,
			'fields': {'temp': round(temp,2) , 'humi': round(humi,2) , 'hpa': round(pres,2)}
		}
	]
	client.write_points(json_body)
	print(json_body)


def compensate_P(adc_P):
	global  t_fine
	pressure = 0.0
	
	v1 = (t_fine / 2.0) - 64000.0
	v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
	v2 = v2 + ((v1 * digP[4]) * 2.0)
	v2 = (v2 / 4.0) + (digP[3] * 65536.0)
	v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
	v1 = ((32768 + v1) * digP[0]) / 32768
	
	if v1 == 0:
		return 0
	pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
	if pressure < 0x80000000:
		pressure = (pressure * 2.0) / v1
	else:
		pressure = (pressure / v1) * 2
	v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
	v2 = ((pressure / 4.0) * digP[7]) / 8192.0
	pressure = pressure + ((v1 + v2 + digP[6]) / 16.0)  

	return (pressure/100)
	#print "pressure : %7.2f hPa" % (pressure/100)

def compensate_T(adc_T):
	global t_fine
	v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
	v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
	t_fine = v1 + v2
	temperature = t_fine / 5120.0

	return temperature
	#print "temp : %-6.2f ℃" % (temperature) 

def compensate_H(adc_H):
	global t_fine
	var_h = t_fine - 76800.0
	if var_h != 0:
		var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))
	else:
		return 0
	var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)
	if var_h > 100.0:
		var_h = 100.0
	elif var_h < 0.0:
		var_h = 0.0

	return var_h
	#print "hum : %6.2f %" % (var_h)


def setup():
	osrs_t = 1			#Temperature oversampling x 1
	osrs_p = 1			#Pressure oversampling x 1
	osrs_h = 1			#Humidity oversampling x 1
	mode   = 3			#Normal mode
	t_sb   = 5			#Tstandby 1000ms
	filter = 0			#Filter off
	spi3w_en = 0			#3-wire SPI Disable

	ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
	config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
	ctrl_hum_reg  = osrs_h

	writeReg(0xF2,ctrl_hum_reg)
	writeReg(0xF4,ctrl_meas_reg)
	writeReg(0xF5,config_reg)


setup()
get_calib_param()


if __name__ == '__main__':
	try:
		readData()
	except KeyboardInterrupt:
		pass


Cronで一定時間おきに計測

$ crontab -e
*/3 * * * * /usr/bin/python /home/pi/script/bme280.py

これで定期的にラズパイ+BME280で温度・湿度・気圧の計測をしてInfuxDBに投げてGrafanaに表示できるようになりました。

グラフ表示ツールGrafanaのjsonコード

BME280で取得したデータをInfuxDBに保存してGrafanaで表示してみました。BME280は以下のRaspi4Bのデータです。その他はWxBeacon2やESP8266にセンサーをつけて計測しています。

Grafna

以下をjsonコードをコピペすると簡単に上画像のようなGrafanaのグラフを表示できます。

jsonのインサート方法は以下のページをご覧ください。

【Iot環境センシング下準備】InfluxDB設定+Grafana+telegrafでラズパイデータ可視化 カッコいいグラフを作ろう
自宅環境センシングの2回目の記事として今回はラズパイ(Raspberry Pi)にデータベースのInfluxDBを入れて将来的にセンシングしたデータをInfluxDB保存していきます。 そして次回は、GrafanaというデータをWebで美し
{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": 6,
  "links": [],
  "panels": [
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Sensor",
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 6,
        "w": 11,
        "x": 0,
        "y": 0
      },
      "id": 2,
      "legend": {
        "avg": false,
        "current": true,
        "max": false,
        "min": false,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "dataLinks": []
      },
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "alias": "Raspi4B",
          "groupBy": [],
          "measurement": "air5",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "G",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "temp"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": [
            {
              "key": "host",
              "operator": "=",
              "value": "raspi4B"
            }
          ]
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "温度(TEMP)",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": "°C",
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Sensor",
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 5,
        "w": 11,
        "x": 0,
        "y": 6
      },
      "id": 4,
      "legend": {
        "avg": false,
        "current": true,
        "max": false,
        "min": false,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "dataLinks": []
      },
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "alias": "Raspi4B",
          "groupBy": [],
          "hide": false,
          "measurement": "air5",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "G",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "humi"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": [
            {
              "key": "place",
              "operator": "=",
              "value": "leaf-bme280"
            }
          ]
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "湿度(Humi)",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": "%",
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Sensor",
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 5,
        "w": 11,
        "x": 0,
        "y": 11
      },
      "id": 6,
      "legend": {
        "avg": false,
        "current": true,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": true
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "null",
      "options": {
        "dataLinks": []
      },
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "alias": "Raspi4B",
          "groupBy": [],
          "measurement": "air5",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "B",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "hpa"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": [
            {
              "key": "place",
              "operator": "=",
              "value": "leaf-bme280"
            }
          ]
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "気圧",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": "hPa",
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    }
  ],
  "refresh": false,
  "schemaVersion": 20,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": []
  },
  "time": {
    "from": "now-6h",
    "to": "now"
  },
  "timepicker": {
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ]
  },
  "timezone": "",
  "title": "BME280",
  "uid": "oJBW1Xzgz",
  "version": 7
}

無事にラズパイで温度・湿度・大気圧を計測することができました♪

以下、BMP280などの備忘録メモです。読み飛ばしてください。

その後、抜いたり刺したりしたら77になった・・・

GPIOを抜き差ししているときに0x76から0x77になった?ので変更する。こんなことってあるのかな?ピン間違えてる?

 $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

13行目「i2c_address = 0x77」この部分の「0x76」から「0x77」に変更した。

$ python bme280.py
24.98
1009.07
31.86
[{'fields': {'hpa': 1009.07, 'humi': 31.86, 'temp': 24.98}, 'tags': {'host': 'raspi3B+', 'place': 'leaf-bme280'}, 'measurement': 'air5'}]

問題なく取得できた。

GNDに指すSDOを3.3Vに刺したら77になった。

BMP280は湿度センサがないので使わない

BME280が本物?らしい・・・BMP280は湿度センサがないらしい・・・意味ないなぁ。

BMP280は以下のソースでちゃんと取得できる。

https://github.com/bokunimowakaru/RaspberryPi/blob/master/gpio/raspi_bme280.c

PIN

BMP280Raspberry Pi
VCC3.3V
GNDGND
SCLGPIO3(SCL)
SDAGPIO2(SDA)
CSB
SDD

下準備

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --

コメント

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