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.