Weatherdata with Raspberry Pi Zero WH (BME280 sensor)  Sun, 15.02.26 18:18 LT

Current uptime: 56 days, 5 hours, 53 minutes

Airpressure, Temperature and Humidity

Location: Tornesch Livingroom

BME280-Sensor-Data shown as a dynamic line plot (RRDtool)

AIR PRESSURE [hPa]
daily pressure trend

daily air pressure trend

AIR TEMPERATURE [°C]
daily temperature trend

daily air temperature trend

REL HUMIDITY [%]
daily humidity trend

daily relative humidity trend

AIR PRESSURE [hPa]
7 days pressure trend

weekly air pressure trend

AIR TEMPERATURE [°C]
7 days temperature trend

weekly air temperature trend

REL HUMIDITY [%]
7 days humidity trend

weekly relative humidity trend

AIR PRESSURE [hPa]
monthly pressure trend

monthly air pressure trend

AIR TEMPERATURE [°C]
monthly temperature trend

monthly air temperature trend

REL HUMIDITY [%]
monthly humidity trend

monthly relative humidity trend

AIR PRESSURE [hPa]
yearly pressure trend

yearly air pressure trend

AIR TEMPERATURE [°C]
yearly temperature trend

yearly air temperature trend

REL HUMIDITY [%]
yearly humidity trend

yearly relative humidity trend


used hardware

Raspberry Pi Zero WH
Raspberry Pi Zero WH

Description

The Raspberry Pi Zero WH is a largely reduced size of only 65mm long by 30mm wide and at a very economical price (about 17 €). With the addition of wireless LAN and Bluetooth, the Raspberry Pi Zero W is ideal for making embedded Internet of Things (IoT) projects. The Pi Zero W has been designed to be as flexible and compact as possible with mini connectors and an unpopulated 40-pin GPIO, allowing you to use only what your project requires. At the heart of the Raspberry Pi Zero W is a 1GHz BCM2835 single-core processor, the same as the B+ and A+, with 512MB RAM. Quite frankly, this Pi is about four times faster that the original Raspberry Pi and is only a fraction of the cost of the current RPi3. The setup for the Raspberry Pi Zero W is a little more complicated than on other Pis. Because of the small size, many of the connectors on the Pi Zero are not standard. For starters you will want a Mini HDMI to HDMI cable or adapter to connect to your monitor. You will also need a USB OTG cable to connect a USB device, as well as a unique CSI camera cable. No matter how you want to use your Raspberry Pi Zero W, you will need a microSD card and a high-quality 5V power supply to power your board. Note: You may use - using an SD-card with a single bootfile - an USB-Stick for installation of an OS. The biggest benefit of using a USB-stick or -drive is, they are far more reliable than MicroSD for running Raspbian and tend to be a lot quicker. It’s a cheap way of improving the performance of your Raspberry Pi.

Configuration

  • BCM2835 chip
  • Quad-core 64-bit ARM cortex A53 CPU
  • Clocked at 1.0 GHz
  • 400MHz VideoCore IV GPU
  • 1GB LPDDR2-900 SDRAM
  • Cypress 43455 chip for wireless and Bluetooth
  • 802.11ac Wireless LAN
  • Bluetooth 4.2

Connectivity

  • 26 GPIO ports in the standard 40-pin Pi configuration
  • 1 Mini USB 2 port
  • No ethernet
  • DSI port
  • CSI port
  • 4-pole composite video/audio
  • Mini HDMI 1.4

Power

  • Micro-usb power in
  • 2.5 Amp supply recommended

Set up a Raspberry Pi
BME 280 sensor
BME 280 sensor (air pressure, temperature and humidity)

Description

BMP280 is an absolute barometric pressure sensor especially designed for mobile applications. The sensor module is housed in an extremely compact package. Its small dimensions and its low power consumption allow for the implementation in battery powered devices such as mobile phones, GPS modules or watches. As its predecessor BMP180, BMP280 is based on Bosch’s proven Piezo-resistive pressure sensor technology featuring high accuracy and linearity as well as long term stability and high EMC robustness. Numerous device operation options offer highest flexibility to optimize the device regarding power consumption, resolution and filter performance. A tested set of default settings for example use case is provided to the developer in order to make design-in as easy as possible. You may either query the I2C or SPI bus to the BME280. This board is 5V compliant - a 3.3V regulator and a i2c level shifter circuit is included so you can use this sensor safely with 5V logic and power.

Sensor Data

  • Supply Voltage VDD: 1.71V to 3.6V
  • Low power consumption: 3.6uA at 1Hz
  • I²C/SPI interface
  • Max I²C Speed: 3.5 Mhz
  • Very low noise: up to 0.12 hPa (1 m)
  • Pressure Range: 300 hPa to 1100 hPa (+9000 m to -500 m)
  • Temperature Range: -40 to +85 °C
  • Humidity Range: 0 to 100 %

Pin Details (I²C)

  • VIN – connect to +3.3V DC
  • GND – connect to GND
  • SCK – connect to I2C clock line (SCL)
  • SDI – connect to I2C data line (SDA)

Wiring

BME280 to GPIO RPI

Barometric formula

barometric formula

In a simplified manner (psea = pressure / pow(1.0 - altitude/44330.0, 5.255)) you may use this formular in the below stated pythonscript (bme680_wx.py) to determine the correct pressure at sea level.

Adafruit´s GPIO Setup

sensor data logging charted with rrd tool

How to get sensor measurements (Temperature, Pressure and Humidity) into graphs

Requirements: Raspberry Pi with properly installed OS (Raspbian Buster) and a webserver (lighttpd with php 7.0 enabled)

  • 1.) Prepare the system for use of sensors: I²C-Bus, Python modules, Adafruit-Installation
  • 2.) install RRD Tool, create a database and appropriate graphs
  • 3.) show graphs as dynamically updated images on a webpage

1.) Communication between the Raspberry Pi and bme-sensor uses in this example the I²C bus (or SPI). The necessary kernel modules are part of Raspbian. Add their names to the file /etc/modules:

i2c-bcm2708i2c-dev

In case, you have a blacklist, these entries in /etc/modprobe.d/raspi-blacklist.conf should be commented out:

#blacklist spi-bcm2708#blacklist i2c-bcm2708

Newer versions of Raspbian require the activation of the I²C bus. Enable this in your Raspi-config: Select Advanced Options - I2C from the menu and confirm the dialog box with Yes.

You may now install the required Python modules and tools for working with the I²C bus:

sudo apt-get install python-smbus i2c-tools

Get default user pi to be a member of the group i2c:

sudo adduser pi i2c

Now reboot the Raspberry Pi with the BME280-sensor attached. The kernel should load the I²C modules. As user pi verify that hardware and software are working properly with i2cdetect. The output shows that communication with the I²C address 77 (or 0x76) is possible. This address is permanently assigned to the BME280. Run this code and see the output as follows..

i2cdetect -y 1

You should see this picture in your console:

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

You should now install Python2. I installed both python-versions: python2 and python3. Also install the BME280-library:

sudo pip install adafruit-circuitpython-bme280
The following script (named: bme280.py) for readout sensor-data from BME280 is written in python2 and it is an adapted code from: GitHub To print out sensor data to terminal screen, you have to delete the comment signs (#) at the end of this script. Then comment out the last part "insert data into round-robin-database".
#!/usr/bin/python # Distributed with a free-will license. # Use it any way you want, profit or free, provided it fits in the licenses of its associated works. # BME280 # This code is designed to work with the BME280_I2CS I2C Mini Module available from ControlEverything.com. # https://www.controleverything.com/content/Humidity?sku=BME280_I2CS#tabs-0-product_tabset-2 import smbus import time import os import rrdtool databaseFile = "/home/pi/py/bme280.rrd" # Get I2C bus bus = smbus.SMBus(1) # BME280 address, 0x76(118) # Read data back from 0x88(136), 24 bytes b1 = bus.read_i2c_block_data(0x77, 0x88, 24) # Convert the data # Temp coefficients dig_T1 = b1[1] * 256 + b1[0] dig_T2 = b1[3] * 256 + b1[2] if dig_T2 > 32767 : dig_T2 -= 65536 dig_T3 = b1[5] * 256 + b1[4] if dig_T3 > 32767 : dig_T3 -= 65536 # Pressure coefficients dig_P1 = b1[7] * 256 + b1[6] dig_P2 = b1[9] * 256 + b1[8] if dig_P2 > 32767 : dig_P2 -= 65536 dig_P3 = b1[11] * 256 + b1[10] if dig_P3 > 32767 : dig_P3 -= 65536 dig_P4 = b1[13] * 256 + b1[12] if dig_P4 > 32767 : dig_P4 -= 65536 dig_P5 = b1[15] * 256 + b1[14] if dig_P5 > 32767 : dig_P5 -= 65536 dig_P6 = b1[17] * 256 + b1[16] if dig_P6 > 32767 : dig_P6 -= 65536 dig_P7 = b1[19] * 256 + b1[18] if dig_P7 > 32767 : dig_P7 -= 65536 dig_P8 = b1[21] * 256 + b1[20] if dig_P8 > 32767 : dig_P8 -= 65536 dig_P9 = b1[23] * 256 + b1[22] if dig_P9 > 32767 : dig_P9 -= 65536 # BME280 address, 0x77(118) # Read data back from 0xA1(161), 1 byte dig_H1 = bus.read_byte_data(0x77, 0xA1) # BME280 address, 0x76(118) # Read data back from 0xE1(225), 7 bytes b1 = bus.read_i2c_block_data(0x77, 0xE1, 7) # Convert the data # Humidity coefficients dig_H2 = b1[1] * 256 + b1[0] if dig_H2 > 32767 : dig_H2 -= 65536 dig_H3 = (b1[2] & 0xFF) dig_H4 = (b1[3] * 16) + (b1[4] & 0xF) if dig_H4 > 32767 : dig_H4 -= 65536 dig_H5 = (b1[4] / 16) + (b1[5] * 16) if dig_H5 > 32767 : dig_H5 -= 65536 dig_H6 = b1[6] if dig_H6 > 127 : dig_H6 -= 256 # BME280 address, 0x76(118) # Select control humidity register, 0xF2(242) # 0x01(01) Humidity Oversampling = 1 bus.write_byte_data(0x77, 0xF2, 0x01) # BME280 address, 0x76(118) # Select Control measurement register, 0xF4(244) # 0x27(39) Pressure and Temperature Oversampling rate = 1 # Normal mode bus.write_byte_data(0x77, 0xF4, 0x27) # BME280 address, 0x76(118) # Select Configuration register, 0xF5(245) # 0xA0(00) Stand_by time = 1000 ms bus.write_byte_data(0x77, 0xF5, 0xA0) time.sleep(0.5) # BME280 address, 0x76(118) # Read data back from 0xF7(247), 8 bytes # Pressure MSB, Pressure LSB, Pressure xLSB, Temperature MSB, Temperature LSB # Temperature xLSB, Humidity MSB, Humidity LSB data = bus.read_i2c_block_data(0x77, 0xF7, 8) # Convert pressure and temperature data to 19-bits adc_p = ((data[0] * 65536) + (data[1] * 256) + (data[2] & 0xF0)) / 16 adc_t = ((data[3] * 65536) + (data[4] * 256) + (data[5] & 0xF0)) / 16 # Convert the humidity data adc_h = data[6] * 256 + data[7] # Temperature offset calculations var1 = ((adc_t) / 16384.0 - (dig_T1) / 1024.0) * (dig_T2) var2 = (((adc_t) / 131072.0 - (dig_T1) / 8192.0) * ((adc_t)/131072.0 - (dig_T1)/8192.0)) * (dig_T3) t_fine = (var1 + var2) cTemp = (var1 + var2) / 5120.0 fTemp = cTemp * 1.8 + 32 # Pressure offset calculations var1 = (t_fine / 2.0) - 64000.0 var2 = var1 * var1 * (dig_P6) / 32768.0 var2 = var2 + var1 * (dig_P5) * 2.0 var2 = (var2 / 4.0) + ((dig_P4) * 65536.0) var1 = ((dig_P3) * var1 * var1 / 524288.0 + ( dig_P2) * var1) / 524288.0 var1 = (1.0 + var1 / 32768.0) * (dig_P1) p = 1048576.0 - adc_p p = (p - (var2 / 4096.0)) * 6250.0 / var1 var1 = (dig_P9) * p * p / 2147483648.0 var2 = p * (dig_P8) / 32768.0 pressure = (p + (var1 + var2 + (dig_P7)) / 16.0) / 100 # Humidity offset calculations var_H = ((t_fine) - 76800.0) var_H = (adc_h - (dig_H4 * 64.0 + dig_H5 / 16384.0 * var_H)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * var_H * (1.0 + dig_H3 / 67108864.0 * var_H))) humidity = var_H * (1.0 - dig_H1 * var_H / 524288.0) if humidity > 100.0 : humidity = 100.0 elif humidity < 0.0 : humidity = 0.0 # Output data to screen #print "Temperature in Celsius : %.2f C" %cTemp #print "Temperature in Fahrenheit : %.2f F" %fTemp #print "Pressure : %.2f hPa " %pressure #print "Relative Humidity : %.2f %%" %humidity # insert data into round-robin-database data = "N:%.2f:%.2f:%.2f" % (cTemp,pressure,humidity) rrdtool.update( databaseFile, data)

Run python bme280.py (with the code-modifications made: uncomment # Output data to screen and comment out # insert data into round-robin-database) to check if your modified script prints out values to the console like below:

Temperature: 18.63 °C Pressure: 1017.54 hPa Humidity: 59.00 %

2.) To visualize atmospheric pressure a long-term recording of measured values into a database and a convenient way to create graphics, we install a round-robin database with the OpenSource software RRDtool written by Tobias Oetiker. It holds high temporal resolution readings on only a certain number of days. This is followed by an automatic consolidation of data so that only the daily average values are kept in the database. After a long time, you can also override these values. Thus, the memory requirements of the database are kept into predetermined limits.

sudo apt-get install rrdtool python-rrdtool

Now create a database, that stores the temperature temp, atmospheric pressure at sea level psea and relative humidity. It should store one value tuple per quarter hour (900 seconds). After ten days (= 960 values), a reduction takes place to one average, minimum, and maximum value per day. The retention time of the daily values is ten years (= 3600 values).

rrdtool create bme280.rrd --step 900 \ DS:temp:GAUGE:1200:-40:80 \ DS:psea:GAUGE:1200:950:1050 \ DS:hum:GAUGE:1200:10:100 \ RRA:AVERAGE:0.5:1:960 \ RRA:MIN:0.5:96:3600 \ RRA:MAX:0.5:96:3600 \ RRA:AVERAGE:0.5:96:3600

Now change the above explained code modifications vice versa and extend the pythonscript (bme280.py) at the end to write measured values into the database. Take care about your path: in my case script and database are in the same directory.

# insert data into round-robin-database data = "N:%.2f:%.2f:%.2f" % (cTemp,pressure,humidity) rrdtool.update( databaseFile, data)

To check, whether the script is actually writing data into the database use this command: rrdtool lastupdate bme280.rrd. It returns the timestamp and the values of the last update of the database.

After a few hours of collecting data, you could create graphs with RRDtool. The following code creates 12 graphics files with the air pressure, temperature and humidity data collected within a daily, weekly, monthly and yearly timespan.

#!/bin/bash RRDPATH="/home/pi/py/" #create graph Luftdruck daily rrdtool graph $RRDPATH/pressure_d.png \ -s 'now - 1 day' -e 'now' \ -v "[hPa]" \ -A -Y -X 0 \ DEF:psea=$RRDPATH/values.rrd:psea:AVERAGE \ LINE1:psea#3fe0db:"Air Pressure (QNH)" # VDEF:psealast=psea:LAST \ # GPRINT:psea:LAST:"Now\:%4.2lf" #create graph Temperatur daily rrdtool graph $RRDPATH/temp_d.png \ -s 'now - 1 day' -e 'now' \ -v "[°C]" \ -A -Y -X 0 \ DEF:temp=$RRDPATH/values.rrd:temp:AVERAGE \ LINE1:temp#FF0000:"Air Temperature (OAT)" # VDEF:templast=temp:LAST \ # GPRINT:temp:LAST:"Now\:%2.2lf" #create graph Luftfeuchte daily rrdtool graph $RRDPATH/hum_d.png \ -s 'now - 1 day' -e 'now' \ -v "[%]" \ -A -Y -X 0 \ DEF:hum=$RRDPATH/values.rrd:hum:AVERAGE \ LINE1:hum#cf38ca:"Rel Humidity (%)" # VDEF:humlast=hum:LAST \ # GPRINT:hum:LAST:"Now\:%4.2lf" #********************************************* #create graph Luftdruck weekly rrdtool graph $RRDPATH/pressure.png \ -s 'now -1w' -e 'now' \ -v "[hPa]" \ -A -Y -X o \ DEF:psea=$RRDPATH/values.rrd:psea:AVERAGE \ LINE1:psea#3fe0db:"Air Pressure (QNH)" \ GPRINT:psea:LAST:"Now\:%4.2lf" \ GPRINT:psea:MIN:"Min\:%4.2lf" \ GPRINT:psea:MAX:"Max\:%4.2lf\n" #create graph Temperatur weekly rrdtool graph $RRDPATH/temp.png \ -s 'now -1w' -e 'now' \ -v "[°C]" \ -A -Y -X o \ DEF:temp=$RRDPATH/values.rrd:temp:AVERAGE \ LINE1:temp#FF0000:"Air Temperature (OAT)" \ GPRINT:temp:LAST:"Now\:%2.2lf" \ GPRINT:temp:MIN:"Min\:%2.2lf" \ GPRINT:temp:MAX:"Max\:%2.2lf\n" #create graph Luftfeuchte weekly rrdtool graph $RRDPATH/hum.png \ -s 'now -1w' -e 'now' \ -v "[%]" \ -A -Y -X o \ DEF:hum=$RRDPATH/values.rrd:hum:AVERAGE \ LINE1:hum#cf38ca:"Rel Humidity (%)" \ GPRINT:hum:LAST:"Now\:%4.2lf" \ GPRINT:hum:MIN:"Min\:%4.2lf" \ GPRINT:hum:MAX:"Max\:%4.2lf\n" #********************************************* #create graph Luftdruck monthly rrdtool graph $RRDPATH/pressure_m.png \ -s 'now - 1 month' -e 'now' \ -v "[hPa]" \ -A -Y -X 0 \ DEF:pseamin_m=$RRDPATH/values.rrd:psea:MIN \ DEF:pseamax_m=$RRDPATH/values.rrd:psea:MAX \ DEF:psea=$RRDPATH/values.rrd:psea:AVERAGE \ CDEF:psearanges=pseamax_m,pseamin_m,- \ LINE1:pseamin_m#3fe0db \ AREA:psearanges#8dadf588::STACK \ LINE1:pseamax_m#3fe0db \ LINE2:psea#3fe0db:Pressure #create graph Temperatur monthly rrdtool graph $RRDPATH/temp_m.png \ -s 'now - 1 month' -e 'now' \ -v "[°C]" \ -A -Y -X 0 \ DEF:tempmin_m=$RRDPATH/values.rrd:temp:MIN \ DEF:tempmax_m=$RRDPATH/values.rrd:temp:MAX \ DEF:temp=$RRDPATH/values.rrd:temp:AVERAGE \ CDEF:tempranges=tempmax_m,tempmin_m,- \ LINE1:tempmin_m#FF0000 \ AREA:tempranges#8dadf588::STACK \ LINE1:tempmax_m#FF0000 \ LINE2:temp#FF0000:Temperature #create graph Luftfeuchtigkeit monthly rrdtool graph $RRDPATH/hum_m.png \ -s 'now - 1 month' -e 'now' \ -v "[%]" \ -A -Y -X 0 \ DEF:hummin_m=$RRDPATH/values.rrd:hum:MIN \ DEF:hummax_m=$RRDPATH/values.rrd:hum:MAX \ DEF:hum=$RRDPATH/values.rrd:hum:AVERAGE \ CDEF:humranges=hummax_m,hummin_m,- \ LINE1:hummin_m#cf38ca \ AREA:humranges#ffb900::STACK \ LINE1:hummax_m#cf38ca \ LINE2:hum#cf38ca:Humidity #********************************************** #create graph Luftdruck yearly rrdtool graph $RRDPATH/pressure_y.png \ -s 'now - 1 year' -e 'now' \ -v "[hPa]" \ -A -Y -X o \ DEF:psea_y=$RRDPATH/values.rrd:psea:AVERAGE \ LINE1:psea_y#3fe0db:"Air Pressure (QNH)" \ GPRINT:psea_y:LAST:"Now\:%4.2lf" \ GPRINT:psea_y:MIN:"Min\:%4.2lf" \ GPRINT:psea_y:MAX:"Max\:%4.2lf\n" #create graph Temperatur yearly rrdtool graph $RRDPATH/temp_y.png \ -s 'now - 1 year' -e 'now' \ -v "[°C]" \ -A -Y -X o \ DEF:temp_y=$RRDPATH/values.rrd:temp:AVERAGE \ LINE1:temp_y#FF0000:"Air Temperature (OAT)" \ GPRINT:temp_y:LAST:"Now\:%2.2lf" \ GPRINT:temp_y:MIN:"Min\:%2.2lf" \ GPRINT:temp_y:MAX:"Max\:%2.2lf\n" #create graph Luftfeuchtigkeit yearly rrdtool graph $RRDPATH/hum_y.png \ -s 'now - 1 year' -e 'now' \ -v "[%]" \ -A -Y -X o \ DEF:hum_y=$RRDPATH/values.rrd:hum:AVERAGE \ LINE1:hum_y#cf38ca:"Rel Humidity (%)" \ GPRINT:hum_y:LAST:"Now\:%4.2lf" \ GPRINT:hum_y:MIN:"Min\:%4.2lf" \ GPRINT:hum_y:MAX:"Max\:%4.2lf\n" #copy to var/www/html/rrd/images/graphs cp /home/pi/py/*.png /var/www/html/rrd/images/graphs
For long term operation you may delegate the script call to the scheduling service cron - here line 2 and 3 (type crontab -e to edit).

# m h dom mon dow command */5 * * * * cd /home/pi/py && python bme280.py */15 * * * * /home/pi/py/create_graph.sh */5 * * * * /home/pi/py/cputemp.sh @reboot cd /usr/local/bin && sudo noip2

3.) Assumed you have a webserver like lighttpd installed on your system, you can either copy the images into your web directory or you directly let RRDtool create the graphs in your web directory. The second solution requires to adjust the $RRDPATH in the script above. For the first solution add the code below and change it with your path.

#copy to var/www/html/rrd/images/graphs cp /home/pi/py/*.png /var/www/html/rrd/images/graphs

You`re done! Since the database will be updated every 15 minutes, wait a few hours until you can observe the diagram growing...