Pour mesurer la température, il est possible d’utiliser divers capteurs, tels que le TMP36, le DHT11/DH22, ou encore le DS18B20. C’est à cette dernière sonde que nous nous intéresserons aujourd’hui. Il s’agit d’une sonde numérique (pas besoin de convertisseur analogique-numérique tel que le MCP3008) qui est assez précise (±0.5°C sur la plage -10°C – 85°C), raisonnablement facile à utiliser, et consommant peu. Par rapport à une sonde analogique, c’est un peu plus complexe, puisqu’il faut utiliser le protocole dallas 1-wire, mais nous verrons qu’il y a déjà les outils nécessaires pour exploiter tout cela.
DS18B20 Raspberry pi : le câblage
Si nous regardons la sonde de près, elle est en forme de demi cylindre, avec un côté plat, portant des inscriptions, comme on peut le voir sur la photo suivante :
Lorsque nous regardons le côté plat, les pattes étant vers le bas, on à de gauche à droite les trois pattes de la sonde. La première pour la masse (GND), la seconde pour le signal (connecté au GPIO4) et la dernière est l’alimentation, VCC (ici 3.3V) .
On va donc logiquement connecter la broche GND à la masse du Raspberry Pi, la broche VCC au +3.3V, et la broche signal au GPIO4. Mais il faudra également connecter la broche signal à VCC, via une résistance de 4.7KOhms. Vous pouvez suivre le schéma suivant :
Et c’est tout 🙂
Configuration du système
Avant de pouvoir utiliser notre sonde, il faut configurer le système. Nous verrons donc les quelques commandes nécessaires pour cela.
Étape 1 : modifier /boot/config.txt
Pour cela, vous pouvez taper la commande suivante :
sudo nano /boot/config.txt
Il faudra alors ajouter le texte suivant à la fin du fichier :
dtoverlay=w1-gpio
Sauvegardez avec CTRL+W, puis quittez avec CTRL+X.
Vous pouvez alors redémarrer le système :
sudo reboot
Étape 2: charger les modules w1–gpio et w1–therm
Pour charger les modules noyau nécessaire à l’exploitation du capteur, on exécutera les commandes suivantes :
sudo modprobe w1-gpio sudo modprobe w1-therm
Cela nous permettra de charger les modules jusqu’au prochain redémarrage du système. Du coup, il faudra refaire cette manipulation à chaque démarrage.
Si l’on souhaite au contraire faire en sorte que les modules en question soient automatiquement chargés, une autre solution est de modifier le fichier /etc/modules :
sudo nano /etc/modules
On ajoute alors en fin de fichier les deux lignes suivantes :
w1-gpio w1-therm
Ainsi, à chaque démarrage du système, ces deux modules seront automatiquement chargés.
Étape 3 : lire les données de la sonde
On pourra alors vérifier le fonctionnement de la sonde en faisant ceci :
cd /sys/bus/w1/devices ls
Si la sonde est reconnue, on verra apparaitre une liste contenant au moins un élément qui correspond à la sonde (quelque chose comme 28-xxxx).
On pourra alors faire ceci pour lire les données du capteur :
cd 28-xxxx cat w1_slave
Cela affichera alors les données du capteur, comme on peut le voir ici :
Comme vous pouvez le voir dans l’exemple de l’image, on obtient une sortie sur deux lignes. La première ligne est terminée par YES, indiquant que notre capteur à pu lire une température, et la seconde ligne est terminée par t=xxxxx, ou l’on a la température en millièmes de degrés (on divise par 1000 pour obtenir la température en degrés).
Dans l’exemple, je fournis une ligne de code permettant de ne sélectionner que la température :
cat /sys/bus/w1/devices/28-000006799670/w1_slave | tail -n 1 | cut -f10 -d " " | cut -f 2 -d "="
Programmation
Nous verrons maintenant comment exploiter la sortie fournie par la sonde afin de surveiller une température. Nous verrons pour cela deux solutions : la première avec un script bash, et la seconde via un script python.
Comme nous l’avons déjà vu brièvement, il est possible de récupérer uniquement la température dans une variable. Nous devrons alors diviser l’ensemble par 1000 pour pouvoir avoir une température en degrés Celsius. Cependant, le problème est que l’interpréteur bash ne gère pas les nombres à virgule, mais uniquement les entiers. Il existe diverses solutions, et vous pourrez en apprendre davantage en suivant ce lien. Pour faire simple, une solution serait d’utiliser bc, mais ce n’est pas installé par défaut sur le raspberry pi. Une autre solution qui fonctionne sans ajouter de paquets est d’utiliser awk.
Script bash
Ainsi, on obtient un petit script readTemp1.sh basique :
#!/bin/bash temp01=`cat /sys/bus/w1/devices/28-000006799670/w1_slave | tail -n 1 | cut -f10 -d " " | cut -f 2 -d "="` temp02=$(awk "BEGIN {printf \"%.3f\",${temp01}/1000}") echo $temp02
Enregistrez donc ceci dans un fichier readTemp1.sh, puis faites ajoutez les droits d’exécution :
chmod u+x readTemp1.sh
Vous pouvez alors exécuter le script en faisant sudo ./readTemp1.sh . Il est également possible de ne pas ajouter les droits en exécution, et se contenter de faire sudo sh ./readTemp1.sh.
Dans tous les cas, on obtient un affichage en degrés Celsius avec les décimales (trois, mais on peut réduire en changeant le %.3f en %.2f dans le script pour avoir deux décimales par exemple).
Cette approche basique fonctionne, et permet d’obtenir la température. Mais idéalement, il faudrait vérifier sur la première ligne si l’on a bien un YES.
C’est ce que nous ferons maintenant :
#!/bin/bash probe_addr='28-000006799670' res=`cat /sys/bus/w1/devices/$probe_addr/w1_slave | head -n 1 | grep YES | wc -l` if [ $res -eq 1 ] then temp01=`cat /sys/bus/w1/devices/$probe_addr/w1_slave | tail -n 1 | cut -f10 -d " " | cut -f 2 -d "="` temp02=$(awk "BEGIN {printf \"%.2f\",${temp01}/1000}") echo $temp02 fi
Dans ce contexte, le script teste si on a bien YES sur la ligne 1, et si c’est le cas, récupère la température et l’affiche. Dans le cas contraire, il n’affiche rien.
On peut ajouter un elif dans le script si on veut afficher un message d’erreur.
Script python
Pour ce script, je ne vais pas réinventer la roue, et on va utiliser un script inspiré du code d’exemple d’Adafruit :
#!/usr/bin/env python import os import glob import time import sys os.system('modprobe w1-gpio') os.system('modprobe w1-therm') base_dir = '/sys/bus/w1/devices/' device_folder = glob.glob(base_dir + '28*')[0] device_file = device_folder + '/w1_slave' def read_temp_raw(): f = open(device_file, 'r') lines = f.readlines() f.close() return lines def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 temp_f = temp_c * 9.0 / 5.0 + 32.0 return temp_c, temp_f try: while True: print(read_temp()[0]) time.sleep(0.3) except KeyboardInterrupt: sys.exit(0)
J’ai modifié leur code pour ajouter un shebang au début, l’ajout de la gestion d’une exception pour capturer le CTRL+C, qui permet de quitter le script, sans afficher de messages d’erreur, et enfin le fait de n’afficher que la température en Celsius. Si vous voulez des degrés Fahrenheit, il suffira de modifier la ligne 34 pour remplacer le 0 en 1 entre les crochets, et pour afficher les deux il suffit d’enlever les crochets et le nombre.
Ce script affiche la température toutes les demi-secondes, et tourne en boucle pour ne se terminer que si l’on fait CTRL+C. En outre, il affichera la température de la première sonde DS18B20 trouvée, et donc ne sera pas adapté à l’affichage de plusieurs températures. On peut le modifier pour afficher une sonde bien précise qui n’est pas forcément la première, et également pour qu’il affiche la température une fois avant de quitter (pouvant ainsi être utilisé pour d’autres scripts) :
#!/usr/bin/env python import os import glob import time import sys os.system('modprobe w1-gpio') os.system('modprobe w1-therm') base_dir = '/sys/bus/w1/devices/' probe_addr='28-000006799670/' #remplacer ici par l'adresse de la sonde device_folder = glob.glob(base_dir + probe_addr)[0] device_file = device_folder + '/w1_slave' def read_temp_raw(): f = open(device_file, 'r') lines = f.readlines() f.close() return lines def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 temp_f = temp_c * 9.0 / 5.0 + 32.0 return temp_c, temp_f print(read_temp()[0])
A noter qu’on peut également se débarrasser des deux lignes 7 et 8 si l’on a chargé les modules au démarrage.
Autres ressources
S’il vous faut d’autres ressources, en voici quelques unes :
- Le tutoriel d’Adafruit, en Anglais, qui m’a servi de base;
- Le tutoriel de Yaug’s corner, (en Français) qui fournit encore quelques liens;
- Le tutoriel de framboise314, toujours en Français, extrêmement complet, avec notamment des explications sur le bus 1-wire, et le mode parasite, et qui complète très bien cet article ou je me suis davantage concentré sur le code que sur le principe électronique général du capteur.
Merci pour l’article détaillé et le lien 🙂
Bonjour,
J’aimerais savoir si quelqu’un pourrait m’indiquer ce qu’il faut modifier ou ajouter au programme python pour lancer un chauffage quand la température attend 0 degrés ?
Bonjour, il faudrait un relais, mais il faut vérifier qu’il est assez puissant. En outre il convient d’étudier plus avant le matériel pour vérifier que tout peut fonctionner ensemble.
J’ai un article sur les relais pour Arduino, mais le principe est le même : http://nagashur.com/blog/2013/03/27/utilisation-dun-relais-grove-sur-un-arduino-commandons-un-appareil-220v-depuis-notre-arduino/
Dès lors il suffit simplement d’activer le GPIO connecté au relais quand on passe sous la température cible, et de faire en sorte que le chauffage s’éteigne lorsqu’on passe au dessus d’une seconde température limite.
J’aimerai avoir ma température dans une courbe dans une page html avec Django ! je n’ai pas trouvé de solution pour envoyer la température à la page html !!
Merci pour les infos, j’ai des problèmes avec un de mes capteurs, de temps en temps impossible d’y accéder,
le seul moyen pour résoudre le problème est de lui couper l’alimentation,
est-ce qu’il est possible d’utiliser une des sortie du gpio pour alimenter le capteur en 3.3 V ?
Hello,
oui, il est possible d’utiliser un GPIO pour alimenter le capteur en 3.3V, lorsque le GPIO est à high, sa tension est justement de 3.3V 🙂
Attention toutefois à ne pas alimenter trop d’éléments via le 3.3V du raspi, qui est censé ne fournir que 50mA (pour des DS18B20, ça suffira largement!)
Bonjour en utilisant ton programme Python me donne ce message :
Traceback (most recent call last):
File “/home/pi/Bureau/test.py”, line 32, in
read_temp()[0]
TypeError: ‘NoneType’ object is not subscriptable
comment puis je le faire fonctionner
76to58
xacrly
qlepvv
ekyjwj
per1yi
qynthj
frvvww