Sommaire
Objectif
Récupérer la température, le taux d’humidité ainsi que la pression atmosphérique d’un BME/BP280 et l’envoyer sur le serveur domoticz avec un Raspberry Zero W
Matériel
- Raspeberry Zero W
- Capteur BMP280 https://www.amazon.fr/gp/product/B07KY8WY4M/ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&psc=1 (par exemple mais moins cher sur AliExpress)
Montage
- GPIO2 = alim
- GPIO39 = grnd
- GPIO3 = SDA
- GPIO5 = SCL
Voici un lien l’organisation des GPIO : https://pinout.xyz/pinout/pin1_3v3_power#
Code
Pré-requis
Au préalable installer i2c-tools : sudo apt-get update
sudo apt-get install i2c-tools
Puis, si ce n’est pas déjà fait, activer l’usage du i2c sur raspbian, faire sudo raspi-config puis se rendre dans le menu 5 puis P5.
enfin, sudo i2cdetect -y 1
, ce qui devrait vous mettre quelque chose qui ressemble à l’image suivante :
A partir de là votre BMP communique avec le raspberry, reste à comprendre.
Lire le BMP280
J’ai récupéré ce script à cette adresse : https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/bme280.py
#!/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/ # https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/bme280.py # -------------------------------------- import smbus import time from ctypes import c_short # Default device I2C address DEVICE = 0x76 # Rev 2 Pi, Pi 0, Pi 2 & Pi 3 uses bus 1 # Rev 1 Pi uses bus 0 bus = smbus.SMBus(1) 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_CONTROL_HUM = 0xF2 # 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) # Wait the required time time.sleep(wait_time / 1000) # 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(): temperature, pressure, humidity = readBME280All() weather = [temperature, pressure, humidity] return weather if __name__ == "__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, "%")
Vous noterez le DEVICE = 0x76
ligne 27 qui correspond à ce qu’il y avait d’affiché avec la commande sudo i2cdetect -y 1
.
Avant de le faire fonctionner, n’oubliez pas d’installer smbus
à coup de pip install smbus
; une fois que cela est fait vous pouvez faire python bme.py
là où vous avez mis le fichier sur le Raspberry , ce qui vous donnera :
~/bme $ python bme.py ('Chip ID :', 96) ('Version :', 0) ('Temperature : ', 20.34, 'C') ('Pressure : ', 1002.2085705444156, 'hPa') ('Humidity : ', 60.38054404621201, '%')
Donc, une température de 20.34° C, une pression atmosphérique de 1002.20 hPa, et une humidité de 60%. Maintenant, envoyons cela à Domoticz.
Communication avec Domoticz
Toujours le même principe que pour le poulailler ou encore le relai : un fichier send_domoticz avec une tache dans le cron.
#!/usr/bin/python from bme import main from requests.auth import HTTPBasicAuth import requests import sys # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # fonctions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def maj_widget(val_url): requete = 'http://' + domoticz_ip + ':' + domoticz_port + val_url # print requete r = requests.get(requete, auth=HTTPBasicAuth(user, password)) if r.status_code != 200: print("Erreur API Domoticz") # 0=Normal # 1=Comfortable # 2=Dry # 3=Wet def humidity_status(val): if 0 <= val <= 75: humidity_status = 0 elif 76 <= val <= 79: humidity_status = 1 elif 80 <= val <= 94: humidity_status = 2 elif 95 <= val <= 100: humidity_status = 3 return humidity_status # 0 = No info # 1 = Sunny # 2 = Partly cloudy # 3 = Cloudy # 4 = Rain def barometer_forecast(val): if val < 1006: weather = 4 elif 1007 <= val <= 1013: weather = 3 elif 1014 <= val <= 1020: weather = 2 elif val > 1020: weather = 1 else: weather = 0 return weather # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # les parametres de Domoticz # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ domoticz_ip = '' domoticz_port = '8080' user = '' password = '' domoticz_idx = '' # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # recuperation des informations des capteurs # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ value = main() temperature = int(value[0]) pressure = int(value[1]) humidity = int(value[2]) hum_stat = humidity_status(humidity) bar_for = barometer_forecast(int(pressure)) if humidity is not None and temperature is not None and pressure is not None: # https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity.2Fbarometer # modele url : /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0& # svalue=TEMP;HUM;HUM_STAT;BAR;BAR_FOR # l URL Domoticz pour le widget virtuel url = '/json.htm?type=command¶m=udevice&idx=' + str(domoticz_idx) url += '&nvalue=0&svalue=' url += str('{0:0.1f};{1:0.1f};{2:0};{3:0.1f};{4:0}').format(temperature, humidity, hum_stat, pressure, bar_for) print(url) maj_widget(url) else: print('Probleme avec la lecture du BME280') sys.exit(1)
Pour l’automatisation avec le cron voir : https://journaldunarchiviste.fr/2019/01/15/domotique-poulailler-connecte-partie-2/#Temperature_et_humidite
Il faut également ajuster la fonction barometer_forecast
; en effet la pression atmosphérique dépend de votre localisation, en particulier de l’altitude, pour plus de renseignement lire : http://leguidemeteo.com/prevoir-le-temps-a-partir-de-son-barometre/
Note : la partie identification nécessite d'avoir configuré son accès à domoticz par un identifiant et un mot de passe.
Configuration domoticz
Il faut créer un capteur virtuel : les explications en capture d’écran
Une fois cela fait, il faut créer le dispositif pour le capteur
Une fois que cela est fait, on alimente le script send_domoticz.py
avec le bon idx
Résultat
En lançant le script avec la commande python send_domo.py
vous aurez un résultat comme celui-ci /json.htm?type=command¶m=udevice&idx=19&nvalue=0&svalue=18.0;66.0;0;1003.0;4
ce qui mettra à jour Domotitcz. Sur l’interface Domoticz, un joli capteur, avec possibilité d’envoyer des notifications via Télégram.
Voici des statistiques sur le mois précédent d’un autre BMP280 installé depuis plus d’un an dans le jardin.
Le code est disponible sur ce dépôt github : https://github.com/fz3p/weatherstation ; cependant il sert également à envoyer les données d’un DHT11.