Si queremos conocer y monitorizar la presión atmosférica Podemos hacerlo rápidamente con una Raspberry Pi y un sensor. En este post veremos todos los pasos que necesitarás para conseguirlo, además como siempre… almacenaremos las mediciones en una base de datos de MySQL y luego visualizaremos con preciosas gráficas los valores gracias a Grafana!
Usaremos un pequeño sensor de presión barométrica BMP180, con él podremos obtener la temperatura, la presión atmosférica e incluso la altitud!
El conexionado GPIO del BMP180 sería muy sencillo, con la Raspberry Pi obviamente apagada, conectamos del BMP180 la conexión VCC al Pin 1 (3.3v), GND a un puerto de tierra de la Raspberry Pi, el SCL al Pin 5 (GPIO03) o SCL1; y por último la conexión SDA irá al Pin 3 (GPIO02) o SDA1 de la Pi.
Entendemos que tenemos una Raspberry Pi funcional con Raspbian instalado, si no tenemos las conexiones I2C habilitadas, lo tenemos que hacer ejecutando
“sudo raspi-config” > Vamos a “Interfacing Options”, habilitamos “I2C” y reiniciamos la Raspberry Pi.
Ahora el código:
import smbus import time from ctypes import c_short from ctypes import c_byte from ctypes import c_ubyte 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() print "Temperature : ", temperature, "C" print "Pressure : ", pressure, "hPa" print "Humidity : ", humidity, "%" if __name__=="__main__": main() |
Como vemos este script es para el BME280, que también tendría sensor de humedad, el script es totalmente compatible, así que genial! l script y el valor de presión atmosférica lo almacene en una base de datos de MySQL, luego los datos los veo con Grafana que queda Así que si añadimos esto mismo al final del script conseguiremos almacenar la presión atmosférica en la BD:
import sys
import MySQLdb
db = MySQLdb.connect("SERVIDOR_MYSQL","USUARIO","CONTRASEÑA","BASE_DE_DATOS")
cursor = db.cursor()
cursor.execute("""INSERT INTO presion_atmosferica (presion) VALUES (%s) """,( pressure))
db.commit()
Creamos una tabla sencilla exáctamente igual que la tengo yo, que tiene 2 columnas, una para almacenar la presión y otra la fecha (que al no permitir NULL pues se autocompleta cada vez que se mete el valor de presión):
CREATE TABLE `presion_atmosferica` (
`presion` FLOAT NULL DEFAULT NULL,
`fecha` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
ROW_FORMAT=COMPACT
;
Y listo en Grafana, en un Dashboard que tengamos, super fácil añadir un panel de tipo Graph y personalizarlo a gusto, dedicarle 5 minutos que Grafana es super intuitivo, en mi caso tengo un conector MySQL que conecta contra la BD.
SELECT presion as value, "Presion" as metric, UNIX_TIMESTAMP(fecha) as time_sec FROM presion_atmosferica WHERE $__timeFilter(fecha) order by time_sec asc
Listo!!! Espero que os resulte interesante! Ya tenemos la presión atmosférica monitorizada! Perfecto para una estación meteorológica ? Éxito!
Comments