Propósito:
Construir una estación metereológica basada en los sensores BME280 y BH1750 local que envía datos a un servidor externo.
Un proyecto interesante es una estación meteorológica que envía los datos de presión, temperatura, humedad e iluminación a un servidor externo para proporcionar una gráfica, en este caso Thingspeak.
También puede servir para ver cómo funciona el internet de las cosas o IoT.
Material necesario
- Raspberry Pi
- Sensor de temperatura, presión y humedad BME280. Ojo, que el BMP280 es muy parecido, con la diferencia de que este no mide humedad, por lo que hay que desconfiar de los que sean muy baratos.
- GPIO Extension Board
- Sensor digital del nivel de luz BH1750
- Placa de desarrollo
- Alimentador
Dificultad:
- Fácil
Conexiones:
Comenzamos conectando los sensores BME280 y BH1750. El esquema es el mismo:
SDA -> GPIO SDA1
SCL -> GPIO SCL1
GND -> GND
VCC -> 3.3V
Comenzamos comprobando si está activado el driver i2c.
dmesg | grep i2c
En caso contrario, tendremos que activarlo con
sudo raspi-config
Vamos a 9 Advanced Options
Bajamos hasta A7 I2C
Y lo activamos.
Instalamos algunos paquetes
sudo apt-get install i2c-tools python-pip
Hacemos lo mismo con Python, en su versión 2 o 3:
sudo python setup.py install
sudo python3 setup.py install
E instalamos la librería RPi.bme280
sudo pip install RPi.bme280
Comprobamos el correcto funcionamiento con el siguiente script:
#!/usr/bin/python #-------------------------------------- # ___ ___ _ ____ # / _ \/ _ \(_) __/__ __ __ # / , _/ ___/ /\ \/ _ \/ // / # /_/|_/_/ /_/___/ .__/\_, / # /_/ /___/ # # bme280.py # Read data from a digital pressure sensor. # # Official datasheet available from : # https://www.bosch-sensortec.com/bst/products/all_products/bme280 # # Author : Matt Hawkins # Date : 25/07/2016 # # http://www.raspberrypi-spy.co.uk/ # # Modified for personal use by # https://github.com/bortek # #-------------------------------------- import smbus import time from ctypes import c_short from ctypes import c_byte from ctypes import c_ubyte import datetime # Humidity & temp adjustment value. Positive value will be added. # Negative will be substracted humidity_adj = +0 temperature_adj = +0 DEVICE = 0x76 # Default device I2C address bus = smbus.SMBus(1) # Rev 2 Pi, Pi 2 & Pi 3 uses bus 1 # Rev 1 Pi uses bus 0 def getShort(data, index): # return two bytes from data as a signed 16-bit value return c_short((data[index+1] << 8) + data[index]).value def getUShort(data, index): # return two bytes from data as an unsigned 16-bit value return (data[index+1] << 8) + data[index] def getChar(data,index): # return one byte from data as a signed char result = data[index] if result > 127: result -= 256 return result def getUChar(data,index): # return one byte from data as an unsigned char result = data[index] & 0xFF return result def readBME280ID(addr=DEVICE): # Chip ID Register Address REG_ID = 0xD0 (chip_id, chip_version) = bus.read_i2c_block_data(addr, REG_ID, 2) return (chip_id, chip_version) def readBME280All(addr=DEVICE): # Register Addresses REG_DATA = 0xF7 REG_CONTROL = 0xF4 REG_CONFIG = 0xF5 REG_CONTROL_HUM = 0xF2 REG_HUM_MSB = 0xFD REG_HUM_LSB = 0xFE # Oversample setting - page 27 OVERSAMPLE_TEMP = 2 OVERSAMPLE_PRES = 2 MODE = 1 # Oversample setting for humidity register - page 26 OVERSAMPLE_HUM = 2 bus.write_byte_data(addr, REG_CONTROL_HUM, OVERSAMPLE_HUM) control = OVERSAMPLE_TEMP<<5 | OVERSAMPLE_PRES<<2 | MODE bus.write_byte_data(addr, REG_CONTROL, control) # Read blocks of calibration data from EEPROM # See Page 22 data sheet cal1 = bus.read_i2c_block_data(addr, 0x88, 24) cal2 = bus.read_i2c_block_data(addr, 0xA1, 1) cal3 = bus.read_i2c_block_data(addr, 0xE1, 7) # Convert byte data to word values dig_T1 = getUShort(cal1, 0) dig_T2 = getShort(cal1, 2) dig_T3 = getShort(cal1, 4) dig_P1 = getUShort(cal1, 6) dig_P2 = getShort(cal1, 8) dig_P3 = getShort(cal1, 10) dig_P4 = getShort(cal1, 12) dig_P5 = getShort(cal1, 14) dig_P6 = getShort(cal1, 16) dig_P7 = getShort(cal1, 18) dig_P8 = getShort(cal1, 20) dig_P9 = getShort(cal1, 22) dig_H1 = getUChar(cal2, 0) dig_H2 = getShort(cal3, 0) dig_H3 = getUChar(cal3, 2) dig_H4 = getChar(cal3, 3) dig_H4 = (dig_H4 << 24) >> 20 dig_H4 = dig_H4 | (getChar(cal3, 4) & 0x0F) dig_H5 = getChar(cal3, 5) dig_H5 = (dig_H5 << 24) >> 20 dig_H5 = dig_H5 | (getUChar(cal3, 4) >> 4 & 0x0F) dig_H6 = getChar(cal3, 6) # Wait in ms (Datasheet Appendix B: Measurement time and current calculation) wait_time = 1.25 + (2.3 * OVERSAMPLE_TEMP) + ((2.3 * OVERSAMPLE_PRES) + 0.575) + ((2.3 * OVERSAMPLE_HUM)+0.575) time.sleep(wait_time/1000) # Wait the required time # Read temperature/pressure/humidity data = bus.read_i2c_block_data(addr, REG_DATA, 8) 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] #Refine temperature var1 = ((((temp_raw>>3)-(dig_T1<<1)))*(dig_T2)) >> 11 var2 = (((((temp_raw>>4) - (dig_T1)) * ((temp_raw>>4) - (dig_T1))) >> 12) * (dig_T3)) >> 14 t_fine = var1+var2 temperature = float(((t_fine * 5) + 128) >> 8); # Refine pressure and adjust for temperature 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 if var1 == 0: pressure=0 else: pressure = 1048576.0 - pres_raw pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1 var1 = dig_P9 * pressure * pressure / 2147483648.0 var2 = pressure * dig_P8 / 32768.0 pressure = pressure + (var1 + var2 + dig_P7) / 16.0 # Refine humidity humidity = t_fine - 76800.0 humidity = (hum_raw - (dig_H4 * 64.0 + dig_H5 / 16384.0 * humidity)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * humidity * (1.0 + dig_H3 / 67108864.0 * humidity))) humidity = humidity * (1.0 - dig_H1 * humidity / 524288.0) if humidity > 100: humidity = 100 elif humidity < 0: humidity = 0 return temperature/100.0,pressure/100.0,humidity def main(): (chip_id, chip_version) = readBME280ID() # print "Chip ID :", chip_id # print "Version :", chip_version temperature,pressure,humidity = readBME280All() if datetime.date.today().year != 1970: print ("{} {:0.1f} {:0.1f} {:0.2f}".format(datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S'),humidity + humidity_adj,temperature + temperature_adj,pressure)) # print "Temperature : ", temperature, "C" # print "Pressure : ", pressure, "hPa" # print "Humidity : ", humidity, "%" if __name__=="__main__": main()
Claro, que también lo podemos instalar así
wget -O bme280.py http://bit.ly/bme280py
o así:
wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/bme280.py
Si da error, instalamos la librería smbus
pip install smbus o pip3 install smbus (en su caso)
ejecutando
python bme280.py
debe aparecer
(debería también dar datos de humedad… si fuera un bme280. En mi caso me temo que sea un bmp280).
También comprobamos el funcionamiento del sensor de luminosidad, con un script que se puede descargar de aquí:
https://gist.github.com/oskar456/95c66d564c58361ecf9f
En este caso, el resultado es este.
Ya que tenemos los sensores funcionando, nos creamos una cuenta gratuita en https://thingspeak.com/.
Con este script leemos los datos de los sensores y los enviamos periódicamente a https://thingspeak.com/, con este resultado:
También presenta los datos en pantalla:
Fuentes:
https://pypi.org/project/RPi.bme280/
Conclusión:
Una raspberry puede ser el «corazón» de una estación meteorológica con unos sensores adecuados.