Je possède depuis quelques jours un thermomètre-hygromètre intérieur-extérieur sans fil TFA Maxim II. TFA est une entreprise allemande qui commercialise des appareils de mesure électroniques ou non. L’entreprise semble être liée à La Crosse Technology, certainement plus connue. Notamment les deux marques diffusent des systèmes de mesure sans fil estampillés « IT+ Instant Transmission 868 MHz ». Mon capteur appartient à cette nouvelle famille.
Bien entendu, je me devais d’analyser le codage utilisé par cette transmission IT+… Je suis parti à la chasse avec un FUNcube Dongle, un génial récepteur SDR 64-1700 MHz qui se présente sous la forme d’une clé USB. Son principal défaut est sa bande passante limitée (environ 80 kHz), mais on peut raisonnablement imaginer que cela soit suffisant pour recevoir la modulation engendrée par un petit capteur.
Matériel utilisé pour ce projet : un capteur sans fil de la station météo photographiée ici, ainsi qu’un récepteur FUNcube Dongle muni d’une antenne boudin VHF-UHF.
F6FBB donne quelques informations sur le mode de modulation utilisé par certaines stations La Crosse : il s’agit basiquement de modulation d’amplitude (discrète). La porteuse est émise à l’état haut, mais pas à l’état bas. On peut voir ça comme de l’AM classique, où le signal modulant est un signal logique tout où rien. Certains parlent d’ASK (Amplitude Shift Keying) car c’est de l’AM discrète (ici, ce serait plus précisément de l’ASK à deux états). D’autres parlent d’OOK (On-Off Keying). L’UIT parle de classe A1B.
J’ai effectivement localisé une émission AM provenant de mon capteur, sur précisément 868,428 MHz. En réception AM audio, on entend de très brefs « clics » toutes les 4 ou 8 secondes (exemple). Il faut bien prendre garde à couper le contrôle automatique de gain (AGC) qui peut jouer des tours. Le signal en sortie d’un démodulateur AM a l’allure suivante (ici vu dans Audacity) :
F6FBB décrit la modulation utilisée par des capteurs La Crosse sur 433 MHz, qui est de type « modulation en largeur d’impulsion » : les 0 et les 1 génèrent des impulsions de largeurs différentes. Ici, l’oscillogramme montre que ce n’est clairement pas le cas, les passages à 0 ou à 1 étant de largeurs très diverses. Une seule hypothèse viable (et qui s’est avéré être la bonne) : il s’agit d’un signal logique brut, sans horloge (asynchrone), comme il peut en circuler sur des liaisons TTL ou RS232. Autrement dit, le train de bits d’une trame module directement la porteuse en tout ou rien. L’étude de plusieurs trames montre que les 8 premiers bits alternent toujours entre 0 et 1 (valeur binaire 0b10101010), ce qui permet de synchroniser l’horloge du récepteur.
Après une étude plus poussée, il s’avère qu’une trame comporte exactement 64 bits (8 octets). La transmission se fait à environ 17200 bit/s, bit de poids fort (MSB) d’abord. De plus, les 5 derniers octets suivent exactement le protocole déchiffré par Fred Bossard qui a analysé le trafic sur le bus SPI interne d’une station La Crosse IT+ ! Notamment, son travail de cryptanalyse du CRC m’a beaucoup facilité la tâche.
Au final, voici le contenu d’une trame, illustré sur l’exemple de trame ci-dessus :
Numéro quartet | Exemple(hexa) | Champ | Commentaires |
---|---|---|---|
0 | A | Préambule | Mot de synchronisation, toujours 0xAA = 0b10101010. |
1 | A | ||
2 | 2 | Identificateur ? | Probablement un identificateur de fabricant et/ou de type de capteur, à confirmer. Chez moi il vaut toujours 0x2DD4. |
3 | D | ||
4 | D | ||
5 | 4 | ||
6 | 9 | Taille données | D’après Fred Bossard, la taille, en quartets, des données à venir jusqu’à la fin de la trame, CRC compris. Toujours 9. |
7 | 6 | Identificateur capteur | Identificateur du capteur, tiré aléatoirement au démarrage. |
8 | 4 | ||
9 | 5 | Température dizaines | Le capteur transmet (temperature + 40) * 10. Le résultat, sur 3 chiffres, est codé en BCD. Ici 0x561 signifie +16,1°C. |
10 | 6 | Température unités | |
11 | 1 | Température dixièmes | |
12 | 5 | Humidité relative | Contrairement à la température, l’humidité relative est codée en binaire standard, pas en BCD. Selon Fred Bossard, la valeur 0x6A (106) indique l’absence du capteur hygrométrique. Ici la valeur est 0x53, soit 83 %. |
13 | 3 | ||
14 | D | Mot de contrôle | CRC des 4 octets situés du quartet n°6 au quartet n°13. Le polynôme est \( x^8 + x^5 + x^4 + 1 \) (0x31), la valeur initiale 0, et il n’y a pas de XOR à la fin. Voir A Painless Guide to CRC Error Detection Algorithms. |
15 | 1 |
Le protocole utilisé par ces petits capteurs est donc assez simple. Quant à la modulation, elle est plutôt rudimentaire. J’ai intégré un décodeur de ces données à Pydemod, ma boîte à outils Python open-source pour le décodage de signaux radio. Pour la trame ci-dessus, Pydemod fournit les informations suivantes :
Frame: size 64 bits, contents [1 0 1 0 1 0 1 0 0 0 1 0 1 1 0 1 1 1 0 1 0 1 0 0 1 0
0 1 0 1 1 0 0 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 1 1 1 1 0 1 0 0 0 1]
Frame hex contents: AA 2D D4 96 45 61 53
CRC: calculated=D1, received=D1
Temperature: 16.1 C -- Humidity: 83 %
Mon outil prend en entrée un fichier WAVE comme celui-ci. Il se synchronise initialement sur le préambule 0xAA, puis il profite de chaque front pour se resynchroniser.
N’hésitez pas à jouer avec vos capteurs et avec Pydemod ! Si vous analysez les émissions de vos capteurs IT+ 868 MHz, que ce soient des TFA ou des La Crosse, je serais ravi d’avoir vos résultats afin d’étoffer cet article.
HTML5 valide ? © Christophe Jacquet. ✍ Contact. Mentions légales.