Milight Multi-Bridge Emulator (chapitre 3)

Hello World !

Comme je l’ai expliqué dans mon précédent article, avec mon code Python maison j’arrive à reproduire le comportement du pont original avec les lampes RGBW. Toutefois le code ne supporte pas encore les lampes CCT (Correlated Color Temperature)… On va y remédier ! 🙂 Dans son projet, Henryk a procédé à un reverse engineering des lampes RGB : il a d’abord tenté de comprendre les trames échangées en radio, puis il a tenté de comprendre les ordres échangés entre le microcontrôleur du pont et le chipset radio PL1167.

J’ai donc décidé de reproduire son mode opératoire mais avec mes moyens limités.

Fabrication d’un analyseur logique

Henryk utilise un analyseur logique professionnel de chez Saleae. Le prix d’entrée est d’environ 250€ pour un modèle supportant 8 canaux. Trop cher pour le peu d’usage que je vais avoir. J’ai donc creusé ce qu’on pouvait faire avec un Arduino et un projet Hackaday a attiré mon regard : Arduino Generic Logic Analyzer.

Son concepteur m’a permis de concevoir un analyseur à partir d’une carte Arduino Mega qui m’a couté 10€. Le logiciel qui l’accompagne est également opensource. Parfait !

20160926_010938

NB : Bien entendu, il faut charger le code source C++ idoine dans le Arduino Mega via le compilateur, sinon le Arduino est une brique 😉

Connexion à l’analyseur logique

En me basant sur la documentation du PL1167. J’ai tenté de repérer les pins CLK, MISO, MOSI et d’analyser, mais je n’avais aucun signal ressemblant à un signal SPI. Du coup je me suis basé sur des photos du logproject d’Henryk afin de voir sur quels pins il a effectué son analyse. Et voici les points de repiquage sur le microcontrôleur après recherche à tâton.

milight_uc

Le câblage est ainsi réalisé :

  • Broche /CS (en bleu) ==> Port 22 (Channel 0)
  • Broche SCK (en vert) ==> Port 23 (Channel 1)
  • Broche MOSI (en marron) ==> Port 24 (Channel 2)
  • Broche MISO (en jaune) ==> Port 25 (Channel 3)
  • Une masse repiquée au régulateur de tension (en noir) ==> Port GND

NB : l’analyseur logique sur Arduino Mega utilise les ports 22 à 29.

Utilisation de OLS et décodage des transmissions SPI

A partir de là on peut maintenant lancer une analyse sérieuse. Pour ce faire on configure l’analyseur logique OLS en cliquant sur Capture > Begin Capture

ols_capture_settings2

On commence déjà par définir l’Arduino comme analyseur logique.

ols_capture_settings1

Capture à 1mhz (pour plus de précision vous pouvez capturer aussi à 2mhz mais cela diminue la taille du buffer par 2, dans notre cas c’est assez). Pourquoi cette valeur ? Car le code source d’Henryk montre que le chipset fonctionne à 1mhz 🙂

Et enfin, à moins de s’appeler Superman, il est impossible de déclencher la capture et de générer un ordre radio dans le délai imparti de 7ms 🙂 Donc on va configurer un trigger.

Selon la norme du bus SPI, la patte /CS passe à l’état 0 en début de transmission et repasse à 1 en fin de transmission. Très bien, on va utiliser ce trigger là :

ols_capture_settings3

La capture ainsi réalisée nous permet maintenant de procéder à une analyse SPI en passant par le menu Tools > SPI Analyzer, qu’on va configurer comme suit :

ols_capture_spi2

On défini les différents canaux comme tel, ensuite pour le mode j’y suis allé à taton, mais il s’agit au final de mode 1, en MSB.

On obtient le résultat suivant avec un ordre RGBW :

ols_milight_syncwords

C’est cohérent avec le LogProject de Henryk ! (et son code source)

  0.65326000: Write reg  7 -> 00 00 channel 0 (2402)MHz
  0.65336250: Write reg 24 -> 14 7A syncword 0: 147A
  0.65346500: Write reg 27 -> 25 8B syncword 3: 258B
  0.65357250: Write reg  7 -> 00 00 channel 0 (2402)MHz
  0.65367625: Write reg 34 -> 80 80 clear FIFO TX, FIFO write pointer: 0, clear FIFO RX, FIFO read pointer: 0

Donc, maintenant qu’on arrive à lire le SPI, on recommence, mais cette fois-ci avec un ordre CCT :

ols_milight_syncwords_cww

Les Syncwords d’initiation d’un ordre CCT sont différents d’une lampe RGBW. Pas étonnant que je ne recevais rien avec le code source d’Henryk quand je tentais de sniffer les lampes CCT. De part sa conception, son abstraction PL1167 ==> nRF24L01 ne peut techniquement pas écouter 2 syncwords en même temps.

Par ailleurs, si on creuse un peu, on s’aperçoit que les lampes ne causent pas sur les mêmes canaux… Les lampes RGBW envoient des ordres sur les canaux 9, 40 et 71, alors que les lampes CWW envoient des ordres sur les canaux 4, 39 et 74. Raison de plus pour que je ne puisse rien sniffer avec le code d’Henryk…

On peut également voir le « payload » envoyé en radio :

ols_milight_cww_payload

Modification de OpenMilight pour prendre en charge les lampes CCT

On peut lire la trame avec OLS, mais ce n’est pas très pratique pour faire du reverse… Tiens, et si on tentait de modifier le code de Henryk pour se faciliter la vie ?

On modifie le fichier MilightRadio.cpp :

Ligne 12, on remplace

static const uint8_t CHANNELS[] = {9, 40, 71};

par

static const uint8_t CHANNELS[] = {4, 39, 74};

Et ensuite, ligne 42, on remplace :

retval = _pl1167.setSyncword(0x147A, 0x258B);

par

retval = _pl1167.setSyncword(0x050A, 0x55AA);

Un petit make clean, puis make, et on execute :

sudo ./openmilight -l

On envoie un ordre CCT, et… miracle, il apparait à l’écran 🙂

openmilight_cww

Reste plus qu’à adapter mon code Python « Milight Multi Bridge Emulator » pour supporter ce type de lampe 😉

La suite au prochain épisode 😀

2 commentaires :

  1. Bonjour

    Je voulais savoir si aujourd’hui votre projet pour le protocole milight est au point ? Pensez vous qu’il serait possible de faire un kit à assembler pour les débutants ? Merci

Laisser un commentaire

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