Pour quelques dizaines d’euros, je viens d’acheter un Tempo Disc de marque BlueMaestro sur Amazon.
C’est un petit capteur de 33mm de diamètre sur 9,5mm d’épaisseur. Il permet de mesurer et d’enregistrer des données de température, d’humidité et de point de rosée. Il est alimenté par une pile (incluse) CR2032 facilement remplaçable qui devrait offrir une durée de vie de plus d’un an en utilisation normale. La portée sans fil est annoncée à 75 mètres en terrain dégagé et à environ 20 mètres en intérieur.
Le capteur de température et d’humidité est un SI7020 de Silicon Labs étalonné en usine. Voici ses caractéristiques :
Les données peuvent facilement être téléchargées par un smartphone ou une tablette (iOS 7 et supérieur et Android 4.3 et supérieur) où elles peuvent être analysées, les alertes traitées et les données exportées au moyen d’un fichier CSV pour une analyse plus poussée et la tenue de registres.
L’appareil utilise une puce nRF52 Bluetooth Low Energy de Nordic Semiconductor et communique en Bluetooth 4.1 (Bluetooth Low Energy).
Le constructeur indiques, sur cette page, comment les données sont transmises.
Le Tempo Disc se comporte en réalité comme une balise iBeacon qui transmet les données via un « advertisement packet ». La dimension de ce dernier étant limitée, il faudra envoyer un « scan response request » pour obtenir la suite des données.
Le constructeur documente également la structure des données dans les packets reçus :
Nous nous focaliserons sur l’ « advertisement packet » qui contient les données live qui nous intéressent. Et honnêtement, je n’ai pas encore trouvé comment envoyer la requête qui permet de recevoir la deuxième partie des données. Si vous trouvez, indiquez la marche à suivre dans les commentaires.
Si l’on utilise un outil comme GATT Browser sur iOS, on peut avoir un aperçu des données que nous allons devoir récupérer :
33 01 17 64 0e 10 00 15 00 de 01 e4 00 77 01 00 00 de 02 51 00 ab 01 cb 00 c2 02 18 00 00 00 00 00
Elles sont représentées en octets avec un offset commençant par l’identificateur Bluetooth SIG de la société BlueMaestro : 0x33 0x01
.
Il suffira alors de les comparer au tableau ci-dessus (advertisement packet) pour comprendre à quoi sert chaque octet ou groupe d’octets.
Il est nécessaire d’utiliser le Bluetooth Low Energy pour se connecter au Tempo Disc.
Le Raspberry Pi 3 en est équipé d’origine. Si vous utilisez un RPi de première ou de seconde génération, je vous conseille d’utiliser un dongle BLE comme celui-ci, vendu sur Amazon.
En principe, si vous utilisez un RPi 3, avec Jessie ou Stretch, les outils hcitool que nous allons utiliser plus loin devraient déjà être installés. Mais hcidump pourrait manquer à l’appel.
Pour plus d’infos sur l’installation, je vous renvoie vers cet article : https://thepihut.com/
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install bluetooth bluez-utils bluez-hcidump blueman bluez
Il n’existe pas, à ma connaissance, de moyen simple sur Linux pour récupérer les données dont nous avons besoin.
Sur cette page, le contributeur explique comment utiliser le couple hcitool et hcidump pour récupérer les données brutes renvoyées par le capteur.
Nous allons écrire un petit script pour voir ce qui est retourné :
#!/bin/bash # On désactive le BT et on le réactive juste après pour éviter les erreurs hciconfig hci0 down hciconfig hci0 up # Démarrage du scan BLE # On fait tourner lescan durant 11sec # SIGINT (équivalent à ctrl-c) timeout -s SIGINT 11s hcitool lescan --duplicates > /dev/null & sleep 1 # On s'assure que le scan a démarré if [ "$(pidof hcitool)" ]; then # On débute le scan des packets avec hcidump timeout -s SIGINT 10s hcidump --raw else echo "ERREUR: Il semblerait que hcitool lescan n'a pas démarré correctement" >&2 exit 1 fi
On devrait obtenir quelque chose comme ceci :
HCI sniffer - Bluetooth packet analyzer ver 5.23 device: hci0 snap_len: 1500 filter: 0xffffffff > 04 3E 1E 02 01 00 00 5E 36 12 58 75 11 12 02 01 02 0E 09 41 75 72 61 42 6F 78 2D 6C 69 67 68 74 9F > 04 3E 1E 02 01 00 00 5E 36 12 58 75 11 12 02 01 02 0E 09 41 75 72 61 42 6F 78 2D 6C 69 67 68 74 A2 > 04 3E 27 02 01 00 00 B1 85 63 8D 7C C4 1B 02 01 06 03 02 95 FE 13 16 95 FE 71 20 98 00 D2 B1 85 63 8D 7C C4 0D 08 10 01 17 A5 > 04 3E 19 02 01 04 00 B1 85 63 8D 7C C4 0D 0C 09 46 6C 6F 77 65 72 20 63 61 72 65 A5 > 04 3E 2B 02 01 00 01 C8 FC E0 F7 F1 F7 1F 02 01 06 11 FF 33 01 17 64 0E 10 00 15 00 E0 01 DB 00 77 01 00 09 09 46 37 46 31 46 37 45 30 A8 > 04 3E 29 02 01 04 01 C8 FC E0 F7 F1 F7 1D 1C FF 33 01 00 DE 02 51 00 AB 01 CB 00 DE 02 51 00 AB 01 CB 00 C2 02 18 00 00 00 00 00 A8 > 04 3E 1E 02 01 00 00 5E 36 12 58 75 11 12 02 01 02 0E 09 41 75 72 61 42 6F 78 2D 6C 69 67 68 74 9E > 04 3E 1E 02 01 00 00 5E 36 12 58 75 11 12 02 01 02 0E 09 41 75 72 61 42 6F 78 2D 6C 69 67 68 74 9F > 04 3E 27 02 01 00 00 B1 85 63 8D 7C C4 1B 02 01 06 03 02 95 FE 13 16 95 FE 71 20 98 00 D2 B1 85 63 8D 7C C4 0D 08 10 01 17 A5 > 04 3E 19 02 01 04 00 B1 85 63 8D 7C C4 0D 0C 09 46 6C 6F 77 65 72 20 63 61 72 65 A4 > 04 3E 1E 02 01 00 00 5E 36 12 58 75 11 12 02 01 02 0E 09 41 75 72 61 42 6F 78 2D 6C 69 67 68 74 9E > 04 3E 0F 02 01 04 00 5E 36 12 58 75 11 03 02 01 02 9F > 04 3E 2B 02 01 00 01 C8 FC E0 F7 F1 F7 1F 02 01 06 11 FF 33 01 17 64 0E 10 00 15 00 E0 01 DA 00 77 01 00 09 09 46 37 46 31 46 37 45 30 B9 > 04 3E 29 02 01 04 01 C8 FC E0 F7 F1 F7 1D 1C FF 33 01 00 DE 02 51 00 AB 01 CB 00 DE 02 51 00 AB 01 CB 00 C2 02 18 00 00 00 00 00 B9
J’ai surligné en rouge les données qui nous intéressent. Vous remarquerez que la première ligne des données surlignées se termine par 0x33 et le deuxième commence par 0x01. Ce sont les octets qui identifient BlueMaestro que nous avons vu plus haut.
Maintenant que nous avons les données, il ne nous reste plus qu’à les récupérer et les mettre en forme.
Le script ci-dessous est largement inspiré de celui d’Elliot Larson que l’on peut trouver sur GitHub à cette adresse : https://gist.github.com/elliotlarson/1e637da6613dbe3e777c
#!/bin/bash # Lecteur de données Tempo Disc BlueMaestro # Ce script est inspiré de celui d'Elliot Larson disponible sur GitHub # https://gist.github.com/elliotlarson/1e637da6613dbe3e777c # Processus: # 1. Arrêt et démarrage de HCI0 # 2. Démarrage de hcitool lescan # 3. Démarrage de la lecture de données RAW avec hcidump # 4. Réassemblage des données réparties sur plusieurs lignes # 5. Vérification de l'entête du paquet de données. # - Si OK => Extraction des données # => STOP # - Si KO => On retourne et on continue # 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 halt_hcitool_lescan() { sudo pkill --signal SIGINT hcitool } trap halt_hcitool_lescan INT process_complete_packet() { # Exemple de packet : # > 04 3E 2B 02 01 00 01 C8 FC E0 F7 F1 F7 1F 02 01 06 11 FF 33 01 17 64 0E 10 00 10 00 C1 02 1F 00 66 01 00 09 09 46 37 46 31 46 37 45 30 B9 local packet=${1//[\ |>]/} # Si le packet ne correspond pas à celui qu'on recherche, on retourne # Si il correspond, on extrait les données if [[ ! $packet =~ ^043E2B0201.{24}11FF ]]; then return else # Supprime le début du packet qui ne nous intéresse pas pour garder ce qui commence par 3301 # 330117640E10001000C1021F0066010009094637463146374530B9 packet=${packet:38:54} echo "Packet complet :" $packet echo # Lorsque la température ou le point de rosée sont négatifs, les 2 octets 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 # J'ai arbitrairement fixé la température pivot à 32768 soit 3276.8 °C !!! battery_lvl=$((0x${packet:6:2})) time_interval=$((0x${packet:8:4})) stored_log_count=$((0x${packet:12:4})) current_temp=$((0x${packet:16:4})) if [[ $current_temp -gt 32768 ]]; then current_temp=$((-65536 + $current_temp)) fi # Division par 10 avec 1 chiffre après la virgule current_temp=$(echo "scale=1; $current_temp/10" | bc) # Forcer un "0" avant le point décimal pour éviter par exemple ".1" ou "-.1" current_temp=$(echo $current_temp | bc -l | sed -e 's/^-\./-0./' -e 's/^\./0./') current_humidity=$((0x${packet:20:4})) current_humidity=$(echo "scale=1; $current_humidity/10" | bc) current_dew_point=$((0x${packet:24:4})) if [[ $current_dew_point -gt 32768 ]]; then current_dew_point=$((-65536 + $current_dew_point)) fi # Division par 10 avec 1 chiffre après la virgule current_dew_point=$(echo "scale=1; $current_dew_point/10" | bc) # Forcer un "0" avant le point décimal pour éviter par exemple ".1" ou "-.1" current_dew_point=$(echo $current_dew_point | bc -l | sed -e 's/^-\./-0./' -e 's/^\./0./') mode=$((0x${packet:28:2})) breach_count=$((0x${packet:30:2})) name_identifier=$((0x${packet:32:2})) length_of_name=$((0x${packet:34:2})) name_of_device=$(echo ${packet:36:16} | xxd -r -p) echo "Battery (%) :" $battery_lvl echo "Time Interval (sec) :" $time_interval echo "Stored Log Cont :" $stored_log_count echo "Current Temp (°C) :" $current_temp echo "Current Humidity (%) :" $current_humidity echo "Current Dew Point (°C) :" $current_dew_point echo "Mode :" $mode echo "Breach Count :" $breach_count echo "Name Identifier :" $name_identifier echo "Length of Name :" $length_of_name echo "Name of Device :" $name_of_device exit 0 fi } read_blescan_packet_dump() { # Les packets sont répartis sur plusieurs lignes et ont besoin d'être reconstitués # Exemple : # > 04 3E 2B 02 01 00 01 C8 FC E0 F7 F1 F7 1F 02 01 06 11 FF 33 # 01 17 64 0E 10 00 10 00 C1 02 1F 00 66 01 00 09 09 46 37 46 # 31 46 37 45 30 B9 packet="" while read line; do # Les packets qui débutent par : ">" if [[ $line =~ ^\> ]]; then # Traite le paquet terminé (sauf si c'est la première fois que c'est terminé) if [ "$packet" ]; then process_complete_packet "$packet" fi # Commencer un nouveau packet packet=$line else # Continuer à construire le packet packet="$packet $line" fi done } # On désactive le BT et on le réactive juste après pour éviter les erreurs hciconfig hci0 down hciconfig hci0 up # Démarrage du scan BLE # Si le périphérique BLE n'est pas trouvé dans les 10 sec on arrête lescan # SIGINT (équivalent à ctrl-c) timeout -s SIGINT 11s hcitool lescan --duplicates > /dev/null & sleep 1 # On s'assure que le scan a démarré if [ "$(pidof hcitool)" ]; then # On débute le scan des packets avec hcidump et on stream le tout à un process timeout -s SIGINT 10s hcidump --raw | read_blescan_packet_dump else echo "ERREUR: Il semblerait que hcitool lescan n'a pas démarré correctement" >&2 exit 1 fi
Vous pouvez télécharger ce script en cliquant sur ce lien.
Pour le rendre exécutable :
$ chmod +x temp-disc.bash
Et pour l’exécuter :
$ sudo ./temp-disc.bash
Vous devriez obtenir ce genre de données :
Packet complet : 330117640E10001300D701F90074010009094637463146374530AC Battery (%) : 100 Time Interval (sec) : 3600 Stored Log Cont : 19 Current Temp (°C) : 21.5 Current Humidity (%) : 50.5 Current Dew Point (°C) : 11.6 Mode : 1 Breach Count : 0 Name Identifier : 9 Length of Name : 9 Name of Device : F7F1F7E0
5 ans ago ·
Merci pour ces infos.
J’essaye de faire quelque chose dans le genre, mon idée est de poster sur MQTT les données de mes différents tempo discs (et mon pebble dehors).
Dans mon cas, j’ai déplacé une Pi dans un endroit assez dégagé pour bien capter les beacons, et sur cette pi, je ne reçoit que les Scan Responses! donc j’ai bien les valeurs limites (max/min/myne 24H), mais pas les valeurs instantanées.
Je cherche encore comment les avoir, toute info est la bienvenue.
PS: si tu es interesé, je peut donner mon projet Github (encore très basique) sur ce projet.
5 ans ago ·
Salut,
Peux-tu poster l’adresse de ton projet Github ci-dessous ?
Ça peut m’intéresser et d’autres lecteurs aussi.
Didier.
5 ans ago ·
https://github.com/roinou/blueCast
Ce n’est que le début, loin d’une solution qui marche.
5 ans ago ·
Thanks!