J’ai récemment acheté un ruban de LEDs RGB de 5 mètres. Le kit comprend un petit transfo, un petit boîtier et une télécommande infrarouge pour choisir la couleur ou le pattern d’animation. Passionné par le concept d’internet des objets, il me fallait trouver un moyen d’interfacer cet éclairage avec Arduino.
J’ouvre le boîtier et ne découvre que peu de composants (ouf, car mes connaissances en électronique ne sont pas bien solides). Il y a 3 pistes pour les 3 couleurs, alimentées par 3 transistors MOSFET. Un capteur infrarouge pour la télécommande et au centre de la conception… un microcontrôleur.
Je me dis que si je branche un microcontrôleur à la place de l’original je fais ce que je veux du circuit. Je dessoude la puce originale et ponte timidement Arduino avec un code de test sur une des pattes allant vers le MOSFET. Victoire, ça fonctionne, je peux allumer les LEDs vertes !
Finalement j’ai asservi les 3 couleurs, pris la puissance à l’entrée du boitier original pour donner à l’Arduino et attaqué le software.
Comment contrôler la couleur exacte du ruban ?
Pour chaque couleur je fais varier l’intensité de la tension avec une valeur entre 0 et 255 par PWM (Pulse Width Modulation). C’est la technique qu’utilisait le microcontrôleur original et il s’avère que les transistors de puissance sont optimisés pour la PWM. Donc R,G,B, 3 fois 0-255 en combinatoire ça me donne théoriquement plus de 16 millions de couleurs. En pratique il y a sûrement des non linéarités dans le fonctionnement des LEDs et tout et tout mais on peut quand même faire de beaux dégradés et un paquet de couleurs différentes.
J’ai réutilisé des bouts de code Arduino que j’avais déjà fait, piqué un code javascript pour aider à sélectionner les couleurs et ça me donne une petite interface pour commander n’importe quelle couleur de la lampe via un navigateur web.
Je passe un moment aussi à implémenter des systèmes de dégradé automatique pour animer un peu le truc.
Je rebranche ensuite le capteur infrarouge et dépoussière une librairie que j’avais testé sur Arduino il y a longtemps pour décoder des télécommandes. J’arrive à associer à chaque bouton un nombre et ça me suffit pour me faire mes propres contrôles de la lampe.
Me voilà avec une lampe qui fonctionne sur Ethernet et via infrarouge, ou comment ajouter des fonctionnalités (ô combien essentielles) à l’appareil original.
Bonus inutile : le code de mon arduino
#include#include #include byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x09, 0x36 }; const int ledRouge = 6; const int ledVerte = 5; const int ledBleue = 3; int r = 0; int g = 0; int b = 0; int preset = 0; int phase = 0; int delai = 20; int count = 0; int r2 = 0; int g2 = 0; int b2 = 0; String readString = String(30); IRrecv irrecv(2); decode_results results; EthernetServer server(80); void color(int red, int green, int blue) { analogWrite(ledRouge, red); analogWrite(ledVerte, green); analogWrite(ledBleue, blue); } void setup() { pinMode(ledRouge, OUTPUT); pinMode(ledVerte, OUTPUT); pinMode(ledBleue, OUTPUT); color(0,0,0); randomSeed(analogRead(0)); irrecv.enableIRIn(); Ethernet.begin(mac); server.begin(); } void loop() { EthernetClient client = server.available(); if (client) { boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read() if(readString.length() < 100) readString.concat(c); if (c == '\n' && currentLineIsBlank) { int Re = readString.indexOf("preset="); if(Re > 1) { if(readString.indexOf("smooth",0) > 1) preset = 1; if(readString.indexOf("fixed",0) > 1) preset = 0; if(readString.indexOf("wtf",0) > 1){ preset = 2; count = 0; } } Re = readString.indexOf("color=",0); if(Re > 1 && !preset) { char c[3]; readString.substring((Re+6),(Re+8)).toCharArray(c,3); r = strtoul(c, 0, 16); readString.substring((Re+8),(Re+10)).toCharArray(c,3); g = strtoul(c, 0, 16); readString.substring((Re+10),(Re+12)).toCharArray(c,3); b = strtoul(c, 0, 16); } Re = readString.indexOf("delay="); if(Re > 1) delai = readString.substring((Re+6),(Re+9)).toInt(); client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); client.println(""); client.print(""); client.print("Preset : "); switch(preset) { case 0: client.println("Fixe"); break; case 1: client.println("Smooth"); break; case 2: client.println("WTF Mode"); break; } break; } if (c == '\n') { currentLineIsBlank = true; } else if (c != '\r') { currentLineIsBlank = false; } } } delay(1); readString = ""; client.stop(); } switch(preset) { case 1: //smooth animSmooth(); break; case 2: wtfMode(); break; } color(r,g,b); if (irrecv.decode(&results)) { switch (results.value){ case 16748655 : //off r = 0; g = 0; b = 0; preset = 0; break; case 16752735 : //on r = random(0,2)*127; g = random(0,2)*127; b = random(0,2)*127; delai = 20; preset = 0; break; case 16724175 : //red r = 255; g = 0; b = 0; preset = 0; break; case 16713975 : //green r = 0; g = 255; b = 0; preset = 0; break; case 16716015 : //blue r = 0; g = 0; b = 255; preset = 0; break; case 16736415 : //smooth preset = 1; if(r > g && r > b) phase = 2; else if(g > r && g > b) phase = 1; else phase = 0; break; case 16769055 : //fade preset = 2; r2 = r; g2 = g; b2 = b; break; case 16720605 : //strobe delai = 1; preset = 2; break; case 16756815 : //eclairer if(delai > 30) delai += 5; if(delai > 50) delai += 45; delai += 5; if(delai > 200) delai = 200; break; case 16746615 : //assombrir if(delai > 30) delai -= 5; if(delai > 100) delai -= 45; delai -= 5; if(delai < 5) delai = 5; break; case 16720095 : //W preset = 0; break; } irrecv.resume(); } } void animSmooth() { if(phase == 0) { if(r > 0) r--; if(g > 0) g--; if(b < 255) b++; if(b == 255 && r == 0 && g == 0) phase = 1; } if(phase == 2) { if(g > 0) g--; if(b > 0) b--; if(r < 255) r++; if(r == 255 && g == 0 && b == 0) phase = 0; } if(phase == 1) { if(r > 0) r--; if(b > 0) b--; if(g < 255) g++; if(g == 255 && r == 0 && b == 0) phase = 2; } delay(delai); } void wtfMode() { if(r2 == r && g2 == g && b2 == b) { r2 = random(0,2)*127; g2 = random(0,2)*127; b2 = random(0,2)*127; } if(r-r2 < 0) r++; else if(r-r2 > 0) r--; if(g-g2 < 0) g++; else if(g-g2 > 0) g--; if(b-b2 < 0) b++; else if(b-b2 > 0) b--; delay(delai); }