In the previous days I have built the code for all my clients (the light spots): they receive TCP commands from the Yún and control the lights accordingly.
1. The 3W RGB LED.
The first one is an Arduino Uno connected to a custom, constant-current RGB LED driver that can handle 3-10W LEDs (maybe even 20W). Here's a picture of it (yes, bad soldering job):
This has 3 PWM inputs which are connected to 3 pins on the Arduino. It gets 12V from any power supply which then also goes to the VIN pin on the Arduino, powering it.
I then soldered an ESP8266 module on a protoboard, along with an LM1117 for bringing 5V down to 3.3V (the onboard regulator of the Arduino doesn't supply enough current) and a resistor circuit for level shifting.
Here it is:
Here is the full Arduino code that controls the lights: there is still some work to do but the main functions are there and working. It has EEPROM saving so that the last value is automatically retrieved at boot. I got the ESP8266 control code from a website then tweaked it, but it was a couple of months ago so I don't remember where.
// TCP STRING SYNTAX
// Manual Mode - M,COLOR_R,COLOR_G,COLOR_B$ (e.g. M,255,128,0$ for orange)
// Strobe Mode - S,DELAY$ (e.g. S,200$ for a random color every 200ms)
// Fade Mode - F,R_START,G_START,B_START,R_END,G_END,B_END,DELAY_TIME$ (e.g. F,255,0,0,0,0,255,5$ fades from red to blue waiting 5ms between every fade "step")
// Options (0 or 1) - TODO
#include <EEPROM.h>
#include <AltSoftSerial.h>
#define BUFFER_SIZE 30
#define SSID "TP-LINK"
#define PASSWORD "topolottolo"
#define PORT 8080
AltSoftSerial debugSerial;
enum {WIFI_ERROR_NONE=0, WIFI_ERROR_AT, WIFI_ERROR_RST, WIFI_ERROR_SSIDPWD, WIFI_ERROR_SERVER, WIFI_ERROR_UNKNOWN};
char dataIn[BUFFER_SIZE];
char dataOut[BUFFER_SIZE];
char buff[BUFFER_SIZE];
char options[2];
char *dataPtr = dataIn;
char *data2Ptr, *mode, *word1, *word2, *word3, *word4, *word5, *word6, *word7;
int addr = 0, index = 0, red = 6, green = 3, blue = 11, debugLED = 13, strSize = sizeof(dataIn);
boolean dataComplete = false, newData = false, first = false, wifi = false;
byte setupWiFi() {
digitalWrite(debugLED, HIGH);
// reset WiFi module
Serial.println("AT+RST");
delay(500);
if(!Serial.find("ready")) {
return WIFI_ERROR_RST;
}
// set mode 3
//Serial.println("AT+CWMODE=3");
delay(500);
Serial.print("AT+CWJAP=\"");
Serial.print(SSID);
Serial.print("\",\"");
Serial.print(PASSWORD);
Serial.println("\"");
delay(2000);
if(!Serial.find("OK")) {
return WIFI_ERROR_SSIDPWD;
}
delay(500);
// start server
Serial.println("AT+CIPMUX=1");
if(!Serial.find("OK")){
return WIFI_ERROR_SERVER;
}
delay(500);
Serial.print("AT+CIPSERVER=1,"); // turn on TCP service
Serial.println(PORT);
if(!Serial.find("OK")){
return WIFI_ERROR_SERVER;
}
delay(500);
return WIFI_ERROR_NONE;
}
char* getIP() {
Serial.println("AT+CIFSR");
Serial.readBytesUntil('\r', buff, 20);
Serial.readBytesUntil('\r', buff, 20);
Serial.readBytesUntil('\r', buff, 20);
return buff;
}
void setup() {
Serial.begin(115200);
debugSerial.begin(9600);
pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
pinMode(debugLED, OUTPUT);
EEPROMReadString(addr, dataIn);
first = false;
delay(1000);
//wifi setup
if(wifi = true){
debugSerial.println("Enabling WiFi...");
while (byte err = setupWiFi()) {
digitalWrite(debugLED, LOW);
// error
debugSerial.print("Setup error:");
debugSerial.println((int)err);
debugSerial.println("Retrying...");
}
// connected
debugSerial.print("Connected to AP!");
// char *ip = getIP();
// debugSerial.print(" IP address is: ");
// debugSerial.println(ip);
}
}
void loop() {
while(Serial.available() > 0 && first == false && Serial.find(":")){
if (dataComplete == true || newData == true){
debugSerial.println("New data found! Erasing array...");
//erase data array
for (int i=0; i<sizeof(dataIn); i++){
dataIn[i] = NULL;
}
//erase eeprom
for (int i = 0; i < BUFFER_SIZE; i++){
EEPROM.write(i, 0);
}
dataComplete = false;
newData = false;
}
// if(wifi == false){
// char character = Serial.read();
// dataIn[index] = character;
// index++;
// if (character == '$'){
// dataIn[index-1] = 0;
// index = 0;
// } //old serial input mode
// }
Serial.readBytesUntil('$', dataIn, BUFFER_SIZE);
dataComplete = true;
debugSerial.print("New data received: ");
debugSerial.println(dataIn);
EEPROMWriteString(addr, dataPtr);
data2Ptr = strdup(dataIn);
splitSerialString();
}
if(strcmp(mode, "M") == 0){
setRGB(atoi(word1), atoi(word2), atoi(word3));
if(first == true){
first = false;
}
}
if(strcmp(mode, "S") == 0){
strobe(atoi(word1));
if(first == true){
first = false;
}
}
if(strcmp(mode, "F") == 0){
fade(atoi(word1), atoi(word2), atoi(word3), atoi(word4), atoi(word5), atoi(word6), atoi(word7));
if(first == true){
first = false;
}
}
if(first == true){
first = false;
}
}
void setRGB(int r, int g, int b){
analogWrite(red, r);
analogWrite(green, g);
analogWrite(blue, b);
}
void strobe(int timeDelay){
long r, g, b;
r = random(0, 256);
g = random(0, 256);
b = random(0, 256);
analogWrite(red, r);
analogWrite(green, g);
analogWrite(blue, b);
delay(timeDelay);
}
void fade(int rstart, int gstart, int bstart, int rend, int gend, int bend, int delayTime){
int r = rstart;
int g = gstart;
int b = bstart;
int rSteps = calcSteps(rstart, rend);
int gSteps = calcSteps(gstart, gend);
int bSteps = calcSteps(bstart, bend);
int redVal = calcSign(rSteps);
int greenVal = calcSign(gSteps);
int blueVal = calcSign(bSteps);
for(int i=1; i<=1020; i++){
if(checkSerial() == true){
setZero();
break;
}
if(i % rSteps == 0){
rstart+=redVal;
if(rstart >= 0){
analogWrite(red, rstart);
}
}
if(i % gSteps == 0){
gstart+=greenVal;
if(gstart >= 0){
analogWrite(green, gstart);
}
}
if(i % bSteps == 0){
bstart+=blueVal;
if(bstart >= 0){
analogWrite(blue, bstart);
}
}
delay(delayTime);
}
float aux;
aux=rstart;
rstart=rend;
rend=aux;
aux=gstart;
gstart=gend;
gend=aux;
aux=bstart;
bstart=bend;
bend=aux;
redVal = -redVal;
greenVal = -greenVal;
blueVal = -blueVal;
for(int i=1; i<=1020; i++){
if(checkSerial() == true){
setZero();
break;
}
if(i % rSteps == 0){
rstart+=redVal;
if(rstart >= 0){
analogWrite(red, rstart);
}
}
if(i % gSteps == 0){
gstart+=greenVal;
if(gstart >= 0){
analogWrite(green, gstart);
}
}
if(i % bSteps == 0){
bstart+=blueVal;
if(bstart >= 0){
analogWrite(blue, bstart);
}
}
delay(delayTime);
}
}
int calcSign(int steps){
int val;
if(steps > 0){
val = 1;
}
else if(steps == 0){
val = 0;
}
else{
val = -1;
}
return val;
}
int calcSteps(int startValue, int stopValue){
if(stopValue-startValue != 0){
return 1020/(stopValue-startValue);
}
else{
return 0;
}
}
void EEPROMWriteString(int startAddr, const char *string){
debugSerial.print("Writing data to EEPROM... ");
for (int i = 0; i < BUFFER_SIZE; i++) {
EEPROM.write(startAddr + i, string[i]);
if(string[i] != NULL)
debugSerial.print(string[i]);
}
debugSerial.println("");
}
void EEPROMReadString(int addr, char* string){
debugSerial.println("Reading data from EEPROM...");
for(int i=0; i<BUFFER_SIZE; i++){
char character = EEPROM.read(addr);
string[i] = character;
if(string[i] != NULL)
debugSerial.print(string[i]);
addr++;
}
//Serial.println();
addr = 0;
dataComplete = true;
splitSerialString();
}
void splitSerialString(){
debugSerial.print("\nSplitting string...");
data2Ptr = strdup(dataIn);
mode = strtok(data2Ptr, ",");
word1 = strtok(NULL, ",");
word2 = strtok(NULL, ",");
word3 = strtok(NULL, ",");
word4 = strtok(NULL, ",");
word5 = strtok(NULL, ",");
word6 = strtok(NULL, ",");
word7 = strtok(NULL, ",");
debugSerial.println("done!");
first = true;
}
boolean checkSerial(){
if (Serial.available() > 0){
newData = true;
return true;
}
}
void setZero(){
analogWrite(red, 0);
analogWrite(green, 0);
analogWrite(blue, 0);
}
2. The Infineon shield + RGB strips.
I have also installed and configured the Infineon RGB shield.
I immediately noticed that there were no "shield headers" included... and I only had standard male headers, so I soldered them on.
I then had to connect the ESP8266 module to the RX and TX pins (as well as to 5V and GND) so I had to do this ugly hack:
Sure enough, the Infineon shield expressed its disappointment by self-bending its pins! :O
Everything is powered by an ATX breakout board (another nice summer project!).
One of the difficulties I encountered was converting 0-255 values into hex 0-4096 ones. Apart from that, the code is the same I posted a few lines before. This was my solution and it works, yet I'm not sure if I have done this right...
void setRGB(int r, int g, int b){
//converts 0-255 values into i2c compatible values
r = map(r, 0, 255, 0, 4095);
g = map(g, 0, 255, 0, 4095);
b = map(b, 0, 255, 0, 4095);
char buffer[10];
String red = String(r, HEX);
String green = String(g, HEX);
String blue = String(b, HEX);
red = "0x" + red;
green = "0x" + green;
blue = "0x" + blue;
red.toCharArray(buffer, 10);
unsigned long r1 = strtoul(buffer, NULL, 16);
green.toCharArray(buffer, 10);
unsigned long g1 = strtoul(buffer, NULL, 16);
blue.toCharArray(buffer, 10);
unsigned long b1 = strtoul(buffer, NULL, 16);
I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, r1, g1, b1);
}
Feels very redundant, maybe because I haven't fully understood int->hex conversions. Is there a better way of doing it apart from converting to strings?
I like the Infineon shield: it's packed of features and relatively easy to use, yet it seems to have this "hard-coded fade".
Right now, if I set the shield to be a single color (e.g. 255,0,0), the lights automatically fade from the previous color to red, according to the fade settings. I'm now working to integrate the fading in a better way with my web interface.
Thanks for reading! I will post a video in a few days, in the meanwhile I'm writing the review of the components!



