Hack_xiaomi_mi_gestion_tension_piles

Xiaomi Mi – Gestion des tensions de piles

Bonjour à tous, je rédige un article rapide pendant que je travaille sur l’API de la ZiGate. Afin de rendre compatible les objets répondant à la norme ZHA, notamment les produits Xiaomi, je liste les fonctionnalités (les clusters et attributs). Cependant, sur les capteurs Xiaomi, il me restait à trouver comment récupérer les tensions des capteurs.

Dans les trames ZigBee récupérées, je ne percevais que les données utiles aux capteurs, comme la température, l’humidité relative, la pression atmosphérique, les différents types de clics sur les boutons, les mouvements etc … mais à aucun moment, je ne percevais en clair une trame sur les tensions ( entre 2.7V et 3.1V).

J’ai donc laissé tourner quelques temps ma ZiGate et j’ai aperçu, en fonction des capteurs des trames illisibles ayant des attributs propriétaires (0xFF01, 0xFF02) sur le cluster « Basic » (0x000). Donc, je me suis dis que ça ne pouvais être que là dedans que je trouverai mon bonheur.

J’ai donc décidé de mettre au point une stratégie

Votre note :

Click to rate this post!
[Total: 29 Average: 3.4]

 

Ma stratégie

Bon, il faut dire que parmi tout ce que j’ai à faire sur la ZiGate (bientôt un édito sur le sujet) pour vous offrir un bon produit, cette partie me « chaffouinait » tout particulièrement. Ne pas avoir la remontée de la tension de pile des Xiaomi était un point très négatif.

J’ai aussi remarqué que la réception de ces fameuses trames (illisibles) pouvait être déclenchée à chaque appairage de capteur. (ce qui est plutôt pratique pour tester)

Voici comment j’ai procédé :

  • J’ai démarré mon fidèle sniffer ZigBee
  • J’ai démarré la gateway Xiaomi et je l’ai paramétrée en mode debug (pour quelle envoie les données en UDP). Il y a plein de tutos sur le net, je vous laisse chercher.
  • J’ai lancé Wireshark en filtrant les trames UDP provenant de l’ip de la gateway Xiaomi

Une fois tout ce petit beau monde lancé, je me suis muni d’un capteur de température / humidité (rond ou carré c’est compatible) et j’ai lancé la procédure d’appairage avec l’application MIHOME sur mon téléphone.

Résultats

Voici les résultats côté Wireshark :

Xiaomi_capteur_TH_voltage_1

Xiaomi_capteur_TH_voltage_2Trames UDP de la Gateway XIAOMI

Premier constat de la part de la gateway Xiaomi, il y a deux trames UDP consécutives. Il semblerait que la première trame soit une trame avec des valeurs erronées (on comprendra mieux avec la trame ZigBee)

La deuxième trame semble plus cohérente avec une tension de 2995 –> 2.995VDC –> 0xBB3 (en hexadécimal)

Voyons maintenant ce qui se passe côté sniffer ZigBee :

Xiaomi_capteur_TH_voltage6Trames ZigBee correspondantes

On observe qu’après le « Device announce » (appairage), nous avons deux trames provenant du capteur avec un cluster Basic (0x0000). Est-ce que ça explique les deux trames UDP précédentes ? …. surement…

Sachant que la première trame indique simplement que c’est un lumi.sensor_ht avec la version du logiciel. Je suppose donc que le mode debug de la passerelle envoie une trame UDP à chaque trame « Basic » mais comme dans les données JSON, il n’y a ni la version, ni le nom du modèle et que c’est les premières données … il envoie les données par défaut … (ça reste une supposition hein).

Attardons nous sur la deuxième trame qui est une trame assez illisible (au niveau de la payload) avec un attribut propriétaire (0xFF01)

Xiaomi_capteur_TH_voltage5

Trames Basic avec attribut propriétaire

J’ai oublié de le surligner mais dans cette capture d’écran, on retrouve notre cluster Basic (0x0000) une commande « Report Attributes » (0x0A) et l’attribut « 0xFF01 » avec comme type de données une chaine de caractères…

La chaine de caractères se trouve juste en dessous et ne ressemble pas à de l’ASCII … Voyons maintenant les valeurs hexadécimales de cette chaine :

Xiaomi_capteur_TH_voltage3Données hexadécimales de la trame

Les parties colorées correspondent aux couleurs du dessus. Donc, prenons la partie verte et cherchons la tension 2.995VDC. On a vu au dessus que cette valeur en hexadécimal était 0xBB3.

Alors je ne sais plus la pour quelle raison (ça date de l’école et c’est devenu un quotidien) mais sachez que les mots (de 2 octets) sont quasi tout le temps inversés… (n’hésitez pas à donner la raison en commentaire).

Donc, je me suis mis à chercher 0xB3 0x0B et il est apparu au grand jour 😉 (surligné sur la capture d’écran).

Bingo !

Alors pour être sûr que ce soit réellement ça, j’ai mis en place deux manipulations :

La première, j’ai alimenté un capteur sur une alimentation de bureau que j’ai fixé à 2.70VDC.

Xiaomi_tension_volt2 Xiaomi_tension_volt

Et j’ai attendu (1 heure environ) de recevoir une nouvelle trame UDP.

Xiaomi_capteur_TH_voltage7

Et la tension correspond bien. (j’ai attendu plutôt que re appairer parce que j’ai moyennement confiance à la première trame qui calcule la tension…)

La deuxième manipulation a été de laisser tourner un capteur de température Xiaomi pendant X temps avec la ZiGate et de récupérer les logs:

Xiaomi_capteur_TH_voltage4

Et voici le résultat, la tension sur 2-3 jours baissent et les données sont cohérentes… la tension est surlignée en gris…

Bon ok, la première méthode aurait suffit mais je voulais vous montrer ce fichier complet car il est intéressant:

il nous apprend que :

Les capteurs de températures humidité Xiaomi carré ou rond ont une même base (comprenant la tension).

La première version du capteur de température à moins de données.

Il existe plein d’autres informations que je n’ai pas encore décodé et je vous invite à le faire 😉 ( ne me demandez pas comment, débrouillez-vous 😉 )

Conclusion

Voici un petit article qui me semblait intéressant à partager. Avec le projet ZiGate, j’apprends quasiment tous les jours (du coup je m’endors moins bête que la veille chaque jour) et je découvre toujours quelques subtilités.

Je sais aussi (je lis aussi sur les différents forums) que cette histoire de tensions de piles sur les produits Xiaomi vous chagrinent et je voulais vous apporter quelques précisions sur cette partie. En même temps, il était indispensable pour moi de découvrir comment récupérer la tension de pile des capteurs Xiaomi pour mon projet ZiGate.

Autre chose, En faisant les mêmes manipulations sur les boutons poussoirs Xiaomi, je me suis aperçu que c’était une autre trame avec un fonctionnement complètement différent qui donnait la tension de pile (grrrrrrr) une trame de type « Basic » (0x0000) mais cette fois-ci avec un attribut (0xFF02) .. et non géré par la ZiGate (pour le moment).

Bref, encore une partie que je vais devoir rajouter… du coup, je vous laisse et j’y retourne 😉

A bientôt !

 

Click to rate this post!
[Total: 29 Average: 3.4]

23 comments

  1. Ça me fait penser qu’il faut que je me trouve une alimentation de laboratoire, il y en a un tas sur Banggood (et GearBest of course) va falloir que j’épluche les avis avec rigueur 😉

    Et sinon dit bon boulot d’investigation et reverse engineering comme d’hab !

  2. L’inversion de l’ordre des octets de poids fort et de poids faible dans un mot est historique. A l’origine les octets étaient dans le bon ordre (configuration appelée big-indian), avec les octets de poids fort en premier. C’était le cas des processeur IBM, Motorola où DEC au départ. La configuration little-indian (octet de poids faible en premier sur un mot) a été introduite par DEC avec son modèle PDP11. Cette configuration a ensuite été reprise par Intel dans son l’architecture x86. Raison pour laquelle elle est si fréquente aujourd’hui.

    Quand un programme est écrit pour fonctionner sur un processeur fonctionnant en litle-indian, il y a de fortes chances pour que les données soient stockées/échangées sous cette forme inversée. Mais, même si ce n’est pas le cas, le litle-indian étant statistiquement dominant, même dans des environnement big-indian, les données peuvent se retrouver stockées en litle-indian afin de favoriser le cas le plus courant.

    Donc bien souvent, comme dans ce cas, dès que l’on cherche une valeur stockée sous la forme d’un mot de 16 ou 32 bits, il y a de fortes chances pour qu’elle soit notée en little-indian.

    Remarque: certains processeurs (ARM par exemple qui est en little-indian par défaut) ont la particularité d’avoir une instruction permettant de switcher le fonctionnement du processeur entre les modes little-indian et big-indian.

  3. Bonjour
    Encore un article excellent ! Et que c’est beau le partage de connaissance !
    Vivement la suite de tes aventures à la Christophe Colomb.
    Merci

  4. Merci à toi de partager tes expériences ,
    c’est pourquoi je vais en faire de même, alors sur le hub au niveau du connecteur P1 (l’avant dernière broche en bas à doite) communique en série en 115200 b/s.

    Il te suffit d’y connecter RX ( d’un esp8266 par exemple) pour y lire les données importantes .
    Tu pourras y lire bien plus d’informations qu’avec wireshark.

    Voici un exemple :
    =recv zigbee message:Free=39040 ,t=8f00;l=12;data= 00 90 15 01 03 00 06 00 00 10 00 a6
    =recv zigbee message:Free=38976 ,t=8f00;l=12;data= 00 90 15 01 04 00 06 00 00 10 01 a6
    03-07 02:38:16.728 {« id »:57, »sid »: »lumi.158d00010d5437″, »model »: »lumi.sensor_switch.v2″, »method »: »event.click », »params »:[]}
    03-07 02:38:16.739 {« id »:58, »method »: »event.start_play_music », »params »:[« m_10 »]}

    Personnellement j’utilise cette astuce avec plus ou moins de succès pour récupérer les info json par mqtt.

    Bonne chance pour la suite.

  5. Merci pour ces infos qui démontrent l étendu de tes connaissances.

    Comment regretter d avoir fait le pari zigate au vu de tous cela \o/

    Bravo

  6. Bonjour ,

    y a til une chance de contacter Xiaomi et d etre referencer comme un devloppeur (si gratuit etc…).
    Autrement nous allons utiliser un processus d acces au information non stable dans le temps. En effet tout changement de la structure des payloads, de clefs , imposeront une nouvelle recherche et dans tout les cas du code. En general la recherche de la bonne info prends plus de temps.
    Il serait bienvenue de connaitre les API officielles quitte a favoriser les produits des fabriquants qui jouent le jeu!
    cdt
    Leo

    1. Bonjour,
      Je crois peu au changement de payload ou clef car ça imposerait aussi à Xiaomi de changer la passerelle pour la rendre compatible. Je pense pas qu’ils souhaitent se rajouter du travail. Après le protocole utilisé, même si ce n’est pas officiel, est normé. La recherche consiste juste avoir la bonne commande. Alors au début c’est un peu long, mais ces efforts ne seront pas amenés à être souvent répétés.

      Mais tu as raison, c’est toujours plus efficace d’être en partenariat avec le fabricant. Il me semble que le blogueur Lunarok soit en contact avec les développeurs de Xiaomi mais à quel niveau, je n’en sais rien… Difficile de faire pression sur une firme comme Xiaomi pour les pousser à jouer le jeu.

  7. Merci pour cette information!

    J’utilise Google translate pour écrire ceci, donc je m’excuse pour toute erreur.

    Bien qu’il soit vrai que les utilisateurs de SmartThings aient eu du mal à lire les données de batterie des appareils Xiaomi, beaucoup de gens ne peuvent pas non plus les garder connectés à leur hub de contrôleur SmartThings après plusieurs heures. Pouvez-vous partager des informations sur la manière dont les périphériques Xiaomi établissent une connexion permanente au contrôleur?

  8. Salut akila et merci pour tes travaux sur les capteurs Xiaomi.
    Pour compléter ton analyse : dans la chaine de caractères, on trouve aussi 640B et 6F23 qui donnent 2916 et 9071 en décimal… ce sont les valeurs de température et d’humidité qu’on retrouve dans la trame UDP. Le capteur remonte donc la température et l’humidité dans ce message propriétaire en plus des clusters dédiés. Les données supplémentaires pour les capteurs carrés doivent correspondre à la mesure de pression atmosphérique qui n’existe pas sur le capteur rond.

      1. Alors je viens de faire le test chez moi avec un capteur carré.
        La chaine de caractères reçue est : 0121a90b0421a8430521060006240000000000642976076521dc0d662b888d01000a210000
        Dedans je trouve :
        A90B = 2985 => Tension pile = 29,85V
        7607 = 1910 => Température = 19,10°C
        DC0D = 3548 => Humidité = 35,48%
        888d0100 = 101768 => Pression atmo = 1017,68mb
        A chaque fois les deux octets avant les données (0121, 6429, 6521 et 662B) sont identiques aux tiens, ça doit être des étiquettes qui indiquent le type de données qui suit.

Leave a Reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

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