Avec la pandémie qui persiste, il est recommandé d’utiliser un appareil de mesure du CO2 pour déterminer la qualité de l’air et son bon renouvellement. Je me suis donc mis à la recherche d’un capteur qui réponde à ces besoins et, tant qu’à faire, essayer d’en trouver un en Bluetooth pour compléter ma collection et relever les données à intervalles réguliers.
Voici les précédents articles qui parlent de mes capteurs :
Mon choix s’est porté sur un appareil « no name » de type 2CO3TB.
Ses dimensions sont : 70mm x 89mm x 35mm et il mesure :
Vous pouvez le retrouver sur Amazon pour un peu plus de 30€ : https://amzn.to/3p0KyGN
Il est muni d’un port micro-USB pour l’alimenter et recharger la batterie amovible (fournie) de 3.7V, de type 18650 et de 1500mAh. La batterie n’est pas nécessaire s’il est alimenté en USB. Un câble d’un mètre est livré dans la boite. L’autonomie sur batterie est de quelques heures.
L’écran affiche toutes les informations utiles en couleur. Il n’est pas de grande qualité et offre un faible angle de vision. Son affichage est rafraichi toutes les secondes.
Un seul et unique bouton permet de :
En principe, si vous utilisez un RPi avec Jessie, Stretch, Buster ou Bullseye, les outils gatttool et hcitool que nous allons utiliser plus loin devraient déjà être installés.
Si ce n’est pas le cas, je vous renvoie vers cet article : https://fr.tipsandtrics.com
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install bluetooth bluez-utils blueman bluez
Pour déterminer cette adresse, nous allons utiliser l’outil hcitool.
$ sudo hcitool lescan
Ce qui devrait nous retourner la liste des périphérique Bluetooth LE (Low Energy) qui se trouvent à proximité :
LE Scan ...
1F:6B:29:20:B3:B7 (unknown)
04:F7:A5:C7:2B:93 (unknown)
B6:6B:04:5C:82:B8 XS-82B8
B6:6B:04:5C:82:B8 XS-82B8
59:CE:9B:42:D4:EB (unknown)
FC:E4:1D:88:BD:59 FCE41D88
FC:E4:1D:88:BD:59 (unknown)
6E:A7:D6:8F:70:26 (unknown)
C4:7C:8D:62:83:C9 (unknown)
C4:7C:8D:62:83:C9 Flower care
EA:80:2F:03:5B:70 (unknown)
C4:F7:3A:21:8A:6D (unknown)
BA:95:9F:9F:58:00 A06AMJ
BA:95:9F:9F:58:00 (unknown)
D9:6A:EB:12:C1:1A (unknown)
F4:0F:24:21:C3:6A (unknown)
90:03:B7:E7:DC:6C Parrot
F4:0F:24:21:C3:6A (unknown)
4F:BE:C3:52:33:73 (unknown)
Le capteur 2CO3TB a donc la MAC Address suivante : B6:6B:04:5C:82:B8
Pour commencer, nous allons nous connecter en mode interactif ( -I
) avec cette commande :
$ sudo gatttool --device=B6:6B:04:5C:82:B8 -I
Une fois démarré, l’outil est prêt à recevoir des commandes et ceci devrait apparaitre à l’écran :
[B6:6B:04:5C:82:B8][LE]>
On va se connecter avec cette commande :
connect
L’outil devrait répondre quelque chose comme ceci et l’adresse MAC devrait passer en bleu lorsque la connexion est établie :
[B6:6B:04:5C:82:B8][LE]> connect Attempting to connect to B6:6B:04:5C:82:B8 Connection successful Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07 Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07 Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07 Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07 Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07 Notification handle = 0x000c value: 23 06 10 04 00 dc 00 30 5d Notification handle = 0x000c value: 23 08 10 04 01 9f 00 0c 00 03 07
À intervalles réguliers de quelques secondes, on voit s’ajouter des lignes de « Notification handle
« . Ce sont les données du capteur qui sont renvoyées sous forme de notifications.
Dans le bouquin « Inside bluetooth low energy – Second Edition » de Naresh Gupta aux éditions Artech House, à la page 323 (https://books.google.be/, l’auteur explique le principe des notifications ATT (Attribute Protocol).
Le serveur envoie des notifications au client sans attendre d’accusé de réception. Ces notifications comprennent un descripteur et une valeur d’attribut.
La commande char-desc
va explorer les descripteurs de caractéristiques et nous retourner tous les handle
disponibles avec leurs numéros et leurs uuid :
[B6:6B:04:5C:82:B8][LE]> char-desc handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb handle: 0x0004, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0005, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0006, uuid: 00002a05-0000-1000-8000-00805f9b34fb handle: 0x0007, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0008, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0009, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x000a, uuid: 0000c762-0000-1000-8000-00805f9b34fb handle: 0x000b, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x000c, uuid: 0000c761-0000-1000-8000-00805f9b34fb handle: 0x000d, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x000e, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x000f, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0010, uuid: f000ffc1-0451-4000-b000-000000000000 handle: 0x0011, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0012, uuid: 00002901-0000-1000-8000-00805f9b34fb handle: 0x0013, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0014, uuid: f000ffc2-0451-4000-b000-000000000000 handle: 0x0015, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0016, uuid: 00002901-0000-1000-8000-00805f9b34fb
Allons télécharger la liste des UUID standardisés du Bluetooth : https://www.bluetooth.com/.
Malheureusement, l’UUID du handle 0x000c
: 0000c761
ne correspond à rien de standardisé dans la liste.
Le seul qui peut nous intéresser est le 0x0003
: 00002a00
qui correspond au Device Name. Les autres UUID ne figurent pas dans la liste.
Pour lire le contenu d’un handle, on utilise la commande char-read-hnd
suivie du n° du handle qui nous intéresse :
[B6:6B:04:5C:82:B8][LE]> char-read-hnd 0x0003 Characteristic value/descriptor: 58 53 2d 31 32 33 34 00
Pour convertir les données, il suffit d’utiliser la table ASCII :
Dans notre cas :
Nous obtenons : XS-1234
Pour lire un handle en ligne de commande, nous utiliserons :
$ sudo gatttool --device=B6:6B:04:5C:82:B8 --char-read -a 0x03 Characteristic value/descriptor: 58 53 2d 31 32 33 34 00
Dans le cas qui nous occupe, pour lire les données, il n’est pas possible de lire directement le handle 0c
.
Voici les valeurs qui seraient retournées :
$ sudo gatttool --device=B6:6B:04:5C:82:B8 --char-read -a 0x0c Characteristic value/descriptor: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Pour obtenir les données, nous allons inscrire une valeur arbitraire dans le handle 31 qui n’existe pas et écouter tout ce qui se passe ensuite ( --listen
):
$ sudo gatttool --device=B6:6B:04:5C:82:B8 --char-write-req --handle=0x0031 --value=0100 --listen Characteristic Write Request failed: Invalid handle Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 Notification handle = 0x000c value: 23 08 10 04 01 a5 00 0d 00 04 0f Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 Notification handle = 0x000c value: 23 08 10 04 01 a2 00 0d 00 03 13 Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 Notification handle = 0x000c value: 23 08 10 04 01 a2 00 0e 00 03 12 Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 Notification handle = 0x000c value: 23 08 10 04 01 a5 00 0e 00 04 0e Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 Notification handle = 0x000c value: 23 08 10 04 01 a5 00 0d 00 04 0f Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64 ^C
Une fois la tentative d’écriture échouée, la commande va continuer à recevoir les notifications du boîtier jusqu’à interruption avec [ctrl] C
.
Pour éviter ce blocage, on va restreindre le temps d’exécution à 5 secondes ( timeout 5
).
Dans les données, on remarque que la commande nous retourne successivement 2 lignes différentes. On va donc ne récupérer que 2 lignes de ces notifications ( grep
) :
sudo timeout 5 gatttool --device=B6:6B:04:5C:82:B8 --char-write-req --handle=0x0031 --value=0100 --listen | grep --max-count=2 "Notification handle"
Et voici la réponse retournée après 15 secondes :
Notification handle = 0x000c value: 23 08 10 04 01 9b 00 06 00 04 fe Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64
Dans les données, on s’aperçoit que certains octets gardent toujours la même valeur alors que d’autres varient.
Notification handle = 0x000c value: 23 08 10 04 01 9b 00 0a 00 0d fe Notification handle = 0x000c value: 23 06 10 04 00 e9 00 2c 64
En rouge, les octets fixes et en vert, ceux qui nous intéressent.
Voici comment se structurent les données :
CO2 | TVOC | HCHO | |||
---|---|---|---|---|---|
01 | 9b | 00 | 0a | 00 | 0d |
411 | 10 | 13 |
Température | Humidité | ||
---|---|---|---|
00 | e9 | 00 | 2c |
233 | 44 |
Les octets sont regroupés par deux et convertis d’hexadécimal vers décimal : 019b => 411
Il faut diviser la température par 10 : 00e9 => 233 => 23,3°C
Les taux TVOC et HCHO doivent être divisés par 1000 : 000a => 10 => 0,010 mg/m³ et 000d => 13 => 0,013 mg/m³
Voici un petit script qui va nous retourner toutes les valeurs utiles du capteur :
#!/bin/bash
# Vérifie que l'on est en Root
if [[ $EUID -ne 0 ]];
then
echo "Ce script doit être exécuté avec les privilèges administrateur"
exit 1
fi
MACadd="B6:6B:04:5C:82:B8"
hciconfig hci0 down
hciconfig hci0 up
hnd03=$(gatttool --device=$MACadd --char-read -a 0x03)
#Characteristic value/descriptor: 58 53 2d 31 32 33 34 00
name=$(echo "$hnd03" | cut -c34-57 | xxd -r -p | tr -d '\0')
echo "Nom : $name"
echo
data=$((timeout 5 gatttool --device=$MACadd --char-write-req --handle=0x0031 --value=0100 --listen | grep --max-count=2 "Notification handle") 2>/dev/null)
data1=$(echo "$data" | grep --max-count=1 "Notification handle = 0x000c value: 23 08 10 04")
data2=$(echo "$data" | grep --max-count=1 "Notification handle = 0x000c value: 23 06 10 04")
co2=${data1:48:2}${data1:51:2}
co2=$((16#$co2))
echo "CO2 : $co2 ppm"
tvoc=${data1:54:2}${data1:57:2}
tvoc=$((16#$tvoc))
tvoc=$(echo "scale=3;$tvoc/1000" | bc | sed 's/^\./0./')
echo "TVOC : $tvoc mg/m³"
hcho=${data1:60:2}${data1:63:2}
hcho=$((16#$hcho))
hcho=$(echo "scale=3;$hcho/1000" | bc | sed 's/^\./0./')
echo "HCHO : $hcho mg/m³"
temp=${data2:48:2}${data2:51:2}
temp=$((16#$temp))
temp=$(echo "scale=3;$temp/10" | bc | sed 's/^\./0./')
echo "Température : $temp °C"
hum=${data2:54:2}${data2:57:2}
hum=$((16#$hum))
echo "Humidité : $hum %"
Edit 09/01/2022 : Les modifications proposées par Francesco Talamona dans les commentaires ont été implémentées au script.
Voici ce que le script devrait retourner comme résultat :
Nom : XS-1234 Characteristic Write Request failed: Invalid handle CO2 : 418 ppm TVOC : 0.013 mg/m³ HCHO : 0.003 mg/m³ Température : 23.300 °C Humidité : 44 %
3 ans ago ·
Awesome! I was playing around with the same device and this page helped me a lot.
I modified two lines in the script in order to suppress bash warning and the error message:
name=$(echo « $hnd03 » | cut -c34-57 | xxd -r -p | tr -d ‘\0’)
data=$((timeout 5 gatttool –device=$MACadd –char-write-req –handle=0x0031 –value=0100 –listen | grep –max-count=2 « Notification handle ») 2>/dev/null)
Furthermore there’s no need to reset hciconfig, so I’m not running the script as root.
3 ans ago ·
Thanks for your comment and the script corrections.
3 ans ago ·
Hello
Pour fiabiliser la prise de mesure, voici un bout de code
while [ -z « $data » ]
do
data=$((timeout 5 gatttool –device=$MACadd –char-write-req –handle=0x0031 –value=0100 –listen | grep –max-count=2 « Notification handle ») 2>/dev/null)
(( compteur_while = compteur_while + 1 ))
if [ « $compteur_while » -gt 20 ]
then
exit 0
fi
done
Merci pour le script