Mes passions, le boulots, mes coups de gueule...




Xiaomi Mijia LYWSD03MMC : Récupérer les données du capteur sur un Raspberry Pi avec gatttool

Catégories : Domotique, Geek, Informatique, Linux, Raspberry Pi · par 16 Avr 2020

Introduction

Depuis quelques temps, j’utilise différents types de capteurs Bluetooth pour effectuer des mesures de température, d’humidité, d’éclairement, de fertilité du sol, …

Aujourd’hui, je vais détailler la procédure pour récupérer les données en provenance d’un capteur de température et d’humidité Xiaomi Mijia LYWSD03MMC.

Le capteur a une taille très modeste puisqu’il ne mesure que 4.30 x 4.30 x 1.25 cm et ne pèse pas plus de 60g.

Il est alimenté par une pile classique CR 2032.

Il est muni d’un petit écran LCD qui affiche la température, le pourcentage d’hygrométrie et un petit smiley qui détermine si la combinaison des deux premières valeurs est confortable.

On le trouve facilement, pour moins d’une dizaine d’euros, sur des sites comme AliExpress, Gearbest ou autre Banggood.


N.B. : Seule la version destinée au marché chinois est actuellement en vente. Vous devrez donc localiser l’App iOS « Xiaomi Home » en Chine pour pouvoir appairer un nouveau Mijia LYWSD03MMC, sans quoi il n’apparaîtra pas dans la liste des accessoires Xiaomi.

Appairage avec un iPhone

Importer les données

Installation du Bluetooth

En principe, si vous utilisez un RPi avec Jessie, Stretch ou Buster, 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

Déterminer l’adresse MAC du Mijia LYWSD03MMC

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 …
90:03:B7:E7:DC:6C (unknown)
90:03:B7:E7:DC:6C Parrot
4E:BD:77:42:D1:B5 (unknown)
4E:BD:77:42:D1:B5 (unknown)
C4:7C:8D:62:83:C9 (unknown)
C4:7C:8D:62:83:C9 Flower care
4E:94:AD:DE:80:33 (unknown)
4E:94:AD:DE:80:33 (unknown)
A4:C1:38:9D:D1:8F (unknown)
A4:C1:38:9D:D1:8F LYWSD03MMC
4B:13:13:68:2D:F7 (unknown)
4B:13:13:68:2D:F7 (unknown)

Le Mijia LYWSD03MMC a donc la MAC Address suivante : A4:C1:38:9D:D1:8F

Importer les données avec gatttool

gatttool en mode interactif

Premiers pas

Pour commencer, nous allons nous connecter en mode interactif ( -I ) avec cette commande :

$ sudo gatttool --device=A4:C1:38:9D:D1:8F -I

Une fois démarré, l’outil est prêt à recevoir des commandes et ceci devrait apparaitre à l’écran :

[A4:C1:38:9D:D1:8F][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 :

[A4:C1:38:9D:D1:8F][LE]> connect
Attempting to connect to A4:C1:38:9D:D1:8F
Connection successful
Notification handle = 0x0036 value: ce 08 2a 0f 0c
Notification handle = 0x0036 value: d0 08 2a 0f 0c
Notification handle = 0x0036 value: d0 08 2a 0f 0c
Notification handle = 0x0036 value: d0 08 2a 0f 0c
[A4:C1:38:9D:D1:8F][LE]>

À intervalles réguliers de quelques secondes, on voit s’ajouter des lignes de « Notification handle« . Ce sont les données de température, d’hygrométrie et de tension de la batterie qui sont envoyées par le petit boîtier.

Mais avant d’analyser ces valeures retournées, nous allons regarder s’il est possible d’obtenir d’autres informations sur le Mijia LYWSD03MMC.

Un petit help va nous retourner toutes les commandes disponibles :

[C4:7C:8D:63:85:B1][LE]> help
help                                          Show this help
exit                                          Exit interactive mode
quit                                          Exit interactive mode
connect [address [address type]]              Connect to a remote device
disconnect                                    Disconnect from a remote device
primary [UUID]                                Primary Service Discovery
included [start hnd [end hnd]]                Find Included Services
characteristics [start hnd [end hnd [UUID]]]  Characteristics Discovery
char-desc [start hnd] [end hnd]               Characteristics Descriptor Discovery
char-read-hnd <handle>                        Characteristics Value/Descriptor Read by handle
char-read-uuid <UUID> [start hnd] [end hnd]   Characteristics Value/Descriptor Read by UUID
char-write-req <handle> <new value>           Characteristic Value Write (Write Request)
char-write-cmd <handle> <new value>           Characteristic Value Write (No response)
sec-level [low | medium | high]               Set security level. Default: low
mtu <value>                                   Exchange MTU for GATT/ATT

La commande primary va explorer les handles des services primaires :

[A4:C1:38:9D:D1:8F][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x0018 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0019, end grp handle: 0x001c uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x001d, end grp handle: 0x0020 uuid: 00010203-0405-0607-0809-0a0b0c0d1912
attr handle: 0x0021, end grp handle: 0x004b uuid: ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6
attr handle: 0x004c, end grp handle: 0x005f uuid: 0000fe95-0000-1000-8000-00805f9b34fb
attr handle: 0x0060, end grp handle: 0x0068 uuid: 00000100-0065-6c62-2e74-6f696d2e696d

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 :

[A4:C1:38:9D:D1:8F][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: 0x0012, uuid: 00002a26-0000-1000-8000-00805f9b34fb
...
handle: 0x0014, uuid: 00002a27-0000-1000-8000-00805f9b34fb
...
handle: 0x001b, uuid: 00002a19-0000-1000-8000-00805f9b34fb
...
handle: 0x0068, uuid: 00002902-0000-1000-8000-00805f9b34fb

En comparant certains de ces uuid avec la nomenclature standardisée Bluetooth sur ce site https://www.bluetooth.com, nous pouvons en déduire ceci :

https://www.bluetooth.com/

Grâce à ce tableau, nous apprenons que :

  • handle 0x0003 : 2A00 => Device Name
  • handle 0x0012 : 2A26 => Firmware Revision String
  • handle 0x0014 : 2A27 => Hardware Revision String
  • handle 0x001b : 2A19 => Battery Level

Lire un handle

Pour lire le contenu d’un handle, on utilise la commande char-read-hnd suivie du n° du handle qui nous intéresse :

[A4:C1:38:9D:D1:8F][LE]> char-read-hnd 0x0003
Characteristic value/descriptor: 4c 59 57 53 44 30 33 4d 4d 43 00
[A4:C1:38:9D:D1:8F][LE]> char-read-hnd 0x0012
Characteristic value/descriptor: 31 2e 30 2e 30 5f 30 31 30 36 00
[A4:C1:38:9D:D1:8F][LE]> char-read-hnd 0x0014
Characteristic value/descriptor: 42 31 2e 34
[A4:C1:38:9D:D1:8F][LE]> char-read-hnd 0x001b
Characteristic value/descriptor: 63

gatttool en ligne de commande

Lire un handle

Pour lire un handle en ligne de commande, nous utiliserons :

$ sudo gatttool --device=A4:C1:38:9D:D1:8F --char-read -a 0x03

Et ainsi de suite pour tous les handles à lire, en veillant à utiliser le numéro correspondant à la fin ( 0x03 ).

Écouter les Notification handle

Dans le cas qui nous occupe, pour lire la température et l’hygrométrie, il n’est pas possible de lire directement le handle 36.

Voici les valeurs qui seraient retournées :

$ sudo gatttool --device=A4:C1:38:9D:D1:8F --char-read -a 0x36
Characteristic value/descriptor: 00 00 00

Pour obtenir les données, nous allons inscrire une valeur arbitraire dans le handle 38 qui permet l’écriture et écouter tout ce qui se passe ensuite ( --listen ):

$ sudo gatttool -b A4:C1:38:9D:D1:8F --char-write-req --handle=0x0038 --value=0100 --listen
Characteristic value was written successfully
Notification handle = 0x0036 value: f7 08 2c 05 0c
Notification handle = 0x0036 value: fa 08 2c 05 0c
Notification handle = 0x0036 value: f8 08 2c 05 0c
Notification handle = 0x0036 value: f8 08 2c 05 0c
Notification handle = 0x0036 value: fa 08 2c 05 0c
^C

Une fois la valeur inscrite avec succès, 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 à 15 secondes ( timeout 15 ) et ne récupérer qu’une seule ligne des notifications ( grep ) :

$ sudo timeout 15 gatttool -b A4:C1:38:9D:D1:8F --char-write-req --handle=0x0038 --value=0100 --listen | grep --max-count=1 "Notification handle"

Et voici la réponse retournée après 15 secondes :

Notification handle = 0x0036 value: fa 08 2c 05 0c

Structure des données

Table ASCII

Pour les handle 0x0003, 0x0012, 0x0014, 0x001b, il suffit d’utiliser une table ASCII pour convertir les Hex en Char

Wikimedia Foundation

0x0003Device Name : 4c 59 57 53 44 30 33 4d 4d 43

4c5957534430334d4d43
LYWSD03MMC

Il s’agit du nom qui apparaît lorsqu’on liste les périphériques BT avec la commande hcitool lescan vue au début.


0x0012Firmware Revision String : 31 2e 30 2e 30 5f 30 31 30 36

312e302e305f30313036
1.0.0_0106

0x0014Hardware Revision String : 42 31 2e 34

42312e34
B1.4

On peut le vérifier dans l’App Xiaomi Home :


0x001bBattery Level : 63

63
99

Ici, on va prendre la valeur décimale de celle en hexadécimale : 63. C’est un pourcentage.


Little endian

Dans le handle de notification 0x0036, lorsque les nombres entiers sont codés sur plusieurs octets, il sont présentés en Little endian. C.-à-d. avec l’octet de poids le plus faible en premier.

Pour comprendre la représentation des nombres entiers sur plusieurs octets, vous pouvez consulter cette page Wikipedia : https://fr.wikipedia.org/wiki/Endianness

Notification handle = 0x0036 value: fa 08 2c 05 0c
fa082c050c
2298443077
Température * 100 (°C)Hygrométrie (%)Tension de batterie * 1000 (Volts)
  • Bytes 1 & 2 : Température : Hex 08 fa : 2298 = 22,98 °C

Attention !
Lorsque la température est négative, les 2 premiers bytes affichent :
FF FF pour -0.1 °C / F6 FF pour -1.0 °C / 9C FF pour -10.0 °C
Soit la formule : Température = -65536 + Température

  • Byte 3 : Hygrométrie : Hex 2c : 44 = 44 %
  • Bytes 4 et 5 : Tension de la batterie en Volts : Hex 0c 05 : 3077 = 3,077 V

Concernant le niveau de la batterie, voici ce qu’indique jaggil sur le forum GitHub : https://github.com/JsBergbau/MiTemperature2/issues/1

Dans mes tests de batterie, j’ai utilisé une alimentation électrique réglable, et le résumé est le suivant :

1. La plage de fonctionnement est comprise entre 2,1v et 3v.

2. Lorsque 2,1 v est atteint, l’icône de la batterie vide est activée sur l’écran LCD.

3. Lorsqu’il atteint 2,09v, le capteur s’éteint.

Ma conclusion est que la plage de 0 à 100% de la batterie correspond à 2,1v à 3v

https://github.com/JsBergbau/MiTemperature2/issues/1

Script

#!/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="A4:C1:38:9D:D1:8F"


hciconfig hci0 down
hciconfig hci0 up

hnd38=$(timeout 15 gatttool -b $MACadd --char-write-req --handle='0x0038' --value="0100" --listen | grep --max-count=1 "Notification handle")
# Notification handle = 0x0036 value: 7c 08 2a 97 0c


if !([ -z "$hnd38" ])
then

	temperature=${hnd38:39:2}${hnd38:36:2}
	temperature=$((16#$temperature))
	if [ "$temperature" -gt "10000" ];
	then
		temperature=$((-65536 + $temperature))
	fi	
	temperature=$(echo "scale=2;$temperature/100" | bc)

	humidity=${hnd38:42:2}
	humidity=$((16#$humidity))

	voltage=${hnd38:48:2}${hnd38:45:2}
	voltage=$((16#$voltage))
	voltage=$(echo "scale=3;$voltage/1000" | bc)


	# Battery Level : 0x2A19
	# handle = 0x001b, uuid = 00002a19-0000-1000-8000-00805f9b34fb

		hnd1b=$(gatttool --device=$MACadd --char-read -a 0x1b)
		# Characteristic value/descriptor: 63
		battery=${hnd1b:33:2}
		battery=$((16#$battery))

	# Firmware Revision String : 0x2A26
	# handle = 0x0012, uuid = 00002a26-0000-1000-8000-00805f9b34fb

		hnd12=$(gatttool --device=$MACadd --char-read -a 0x12)
		# Characteristic value/descriptor: 31 2e 30 2e 30 5f 30 31 30 36 00
		firmware=$(echo "$hnd12" | cut -c34-65 | xxd -r -p)


	# Device Name : 0x2A00
	# handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb

		hnd03=$(gatttool --device=$MACadd --char-read -a 0x03)
		# Characteristic value/descriptor: 4c 59 57 53 44 30 33 4d 4d 43 00
		name=$(echo "$hnd03" | cut -c34-65 | xxd -r -p)


	# Hardware Revision String : 0x2A27
	# handle = 0x0014, uuid = 00002a27-0000-1000-8000-00805f9b34fb

		hnd14=$(gatttool --device=$MACadd --char-read -a 0x14)
		# Characteristic value/descriptor: 42 31 2e 34
		revision=$(echo "$hnd14" | cut -c34-45 | xxd -r -p)

	# Affichage des données

		echo "Reading Mijia..."
		echo "Hardware: {Firmware Version:$firmware / Hardware Revision:$revision / BT Name:$name / Battery Level:$battery}"
		echo "Sensors: {Temperature:$temperature / Humidity:$humidity / Voltage:$voltage}"

else

	echo "Mijia error"

fi

Voici ce que ce script devrait retourner :

Reading Mijia…
Hardware: {Firmware Version:1.0.0_0106 / Hardware Revision:B1.4 / BT Name:LYWSD03MMC / Battery Level:99}
Sensors: {Temperature:22.00 / Humidity:47 / Voltage:3.060}

(3) comments

Pierre PERNO
1 mois ago · Répondre

Bonjour, merci beaucoup pour votre script, mais j’ai un souci:

capteur.sh: ligne 29: bc : commande introuvable
capteur.sh: ligne 36: bc : commande introuvable
capteur.sh: ligne 51: avertissement :substitution de commande: octet nul ignoré en entrée
capteur.sh: ligne 59: avertissement :substitution de commande: octet nul ignoré en entrée
Reading Mijia…
Hardware: {Firmware Version:1.0.0_0106 / Hardware Revision:B1.4 / BT Name:LYWSD03MMC / Battery Level:99}
Sensors: {Temperature: / Humidity:62 / Voltage:}

voilà le retour qu’il me fait, je n’arrive pas à trouver le souci!

Pourriez-vous m’aider?

    fanjoe
    1 mois ago · Répondre

    Bonjour,

    BC est une calculatrice en ligne de commande.
    https://fr.wikipedia.org/wiki/Bc_(Unix)

    Il suffit de l’installer :
    $ sudo apt-get update
    $ sudo apt-get install bc

    Sans la calculatrice, les valeurs ne peuvent pas être calculées et sont absentes à la fin.

    Didier.

Pierre
1 mois ago · Répondre

Bonjour, merci beaucoup ça fonctionne niquel, avec un petit plus, affichage dans Domoticz…

Pierre

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.