ラズパイ+BME280で温度・湿度・気圧を計測(BMP280は湿度なし)

スポンサーリンク

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

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

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

湿度を取得できない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があるけど使わない。

BME280 Raspberry Pi
GND GND
3.3V VCC
SCK GPIO3(SCL)
SDO
SDI GPIO2(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のサンプル

samplecodes/BME280 at master · SWITCHSCIENCE/samplecodes
Contribute to SWITCHSCIENCE/samplecodes development by creating an account on GitHub.

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

$ 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は以下のソースでちゃんと取得できる。

RaspberryPi/raspi_bme280.c at master · bokunimowakaru/RaspberryPi
ボクにもわかるRaspberry Pi. Contribute to bokunimowakaru/RaspberryPi development by creating an account on GitHub.

PIN

BMP280 Raspberry Pi
VCC 3.3V
GND GND
SCL GPIO3(SCL)
SDA GPIO2(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 --

BME280用のPythonは動かなかった。

$ wget https://github.com/SWITCHSCIENCE/samplecodes/tree/master/BME280/Python27/bme280_sample.py
$ sudo pip install smbus2
$ sudo python bme280_sample.py
Traceback (most recent call last):
  File "bme280_sample.py", line 138, in <module>
    setup()
  File "bme280_sample.py", line 133, in setup
    writeReg(0xF2,ctrl_hum_reg)
  File "bme280_sample.py", line 19, in writeReg
    bus.write_byte_data(i2c_address,reg_address,data)
  File "/usr/local/lib/python2.7/dist-packages/smbus2/smbus2.py", line 391, in write_byte_data
    ioctl(self.fd, I2C_SMBUS, msg)
IOError: [Errno 5] Input/output error

コメント

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