IMG_20160902_211736

Cheerlights is an awesome example of an IOT (Internet Of Things) collaborative project. It allows all users lights across the world to synchronize to one color. For that, it uses a Thingspeak channel and API. More information about the project you can visit its page.

Requirements

1x Adafruit HUZZAH ESP8266 Breakout

1x WS2812 Serial 5050 Full-color LED Extension Module For Arduino

Note: You can use any NeoPixel compatible led strip, led ring, RGB LED, etc… I’ve build and enclosure for this one i’m using

Schematics

Here’s a Fritzing schematic of the project and its connections.

CheerLights_bb

Note: The TTL cable is only used when uploading code. I’m drawing power from a USB port. I’ve just cut a USB cable and used the USB -> Computer adapter to connect to a USB port and get power from there.

Enclosure

To create this funny project, I reused a small white acrylic cube I had around here from another Arduino project. I had two, one was used in my project –

Arduino LED Ambient Mood Light with Light/Luminosity/LUX Sensor – and the other one I’m going to use it here.

I’ve created a base for the cube, where the HUZZAH and the LED ring will be put and connect to a USB port.

Here are some pictures of the base being printed. You can get it from Thingiverse.

IMG_20160822_085213 IMG_20160822_085218

IMG_20160902_210117 IMG_20160902_210122 IMG_20160902_211331 IMG_20160902_211629 IMG_20160902_211707 IMG_20160902_211718 IMG_20160902_211736 IMG_20160902_211756

Code

Cheearlights uses Thingspeak API to know when a color has changed and change the RGB LED accordingly. When you install the thingspeak library there’s an example for cheerlights. I’ve tried to use that example, but my HUZZAH was always crashing with the “wdt reset”. I was unable to solve this error, no matter what I did – pull ups, pull downs, resistors – nothing worked.. After some testing, I realized that if I removed some code, the HUZZAH worked like a charm. I decided not to use the Thingspeak API and make my own functions.

According to Cheerlights API, you can get the latest color in 3 different formats: XML, JSON and plain text. Plain text just returns the name of the color and nothing else. By using string functions I can get the color.

But, I decided to add a special feature – instead of changing directly from one color to another, I added a transition like effect.  We have the old color, the new color and in 10 steps (You can change that if you like), change from one color to the other.  It works better (the effect is better perceived) if the old color and the new color RGB values are far apart.

Support for Adafruit’s Huzzah board

First, We need to add support for the Adafruit Huzzah board. You can see here how to add support in the Arduino IDE

Note: Your Arduino IDE must have been downloaded from arduino.cc.

Install (if you like) Thingspeak libraries. It has an example for Cheerlights. Go to this Github page to read how to install the library.

The Code

#include <ESP8266WiFi.h>
#include <Adafruit_NeoPixel.h>

//Nepixels
//connected Pin
#define NeopixelPIN 4; 
//Num of Neopixels
#define NumNeopixels 16;

int steps = 10; //number of transitions to go from the old color to the new color

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(16, 4, NEO_GRB + NEO_KHZ800); 

const char* ssid     = "<ssid>";
const char* password = "<pwd>";
 
const char* host = "api.thingspeak.com";

// Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 80;

// List of CheerLights color names
String colorName[] = {"none","red","pink","green","blue","cyan","white","warmwhite","oldlace","purple","magenta","yellow","orange"};

// Map of RGB values for each of the Cheerlight color names
int colorRGB[][3] = {     0,  0,  0,  // "none"
                        255,  0,  0,  // "red"
                        255,79,166,  // "pink"
                          0,255,  0,  // "green"
                          0,  0,255,  // "blue"
                          0,255,255,  // "cyan",
                        255,255,255,  // "white",
                        255,223,223,  // "warmwhite",
                        255,223,223,  // "oldlace",
                        128,  0,128,  // "purple",
                        255,  0,255,  // "magenta",
                        255,255,  0,  // "yellow",
                        255,140,  0}; // "orange"}; 


//store the oldColor
String oldColor = "";

void setup() {
  //Serial port
  Serial.begin(115200);
  //delay a bit
  delay(100);

  //Start the Neopixels
  pixels.begin();
 
  // We start by connecting to a WiFi network
 
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
 
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  //define LedPin
  pinMode (4, OUTPUT);
}
 
//int value = 0;
 
void loop() {

  String line = "";
  delay(5000);

 
//  Serial.print("connecting to ");
//  Serial.println(host);
  
  
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }
  
  // We now create a URI for the request
  String url = "/channels/1417/field/1/last.xml";
//  Serial.print("Requesting URL: ");
//  Serial.println(url);
  
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  delay(500);

  
  // Read all the lines of the reply from server and print them to Serial
  while (client.available()) {
    
    line = client.readStringUntil('\n');
    if (line.startsWith("  <field1>")) {
      //Serial.print(line);
      //colortobe = line;
      break;
    }
  }
  line.trim(); //remove spaces
//  Serial.print("Line: ");
  //Serial.println(line);

  int start = line.indexOf('>');
//  Serial.print("Int: ");
//  Serial.println(start);
  int last = line.indexOf("</field1>");
//  Serial.print("Last: ");
//  Serial.println(last);

//  Serial.print ("The color is: ");
  String theColor = line.substring(start+1,last);
//  Serial.println(theColor);
  setColor(theColor);
//  Serial.println();
//  Serial.println("closing connection");
}


void setColor(String color) {
  int a, b, c;
  int valueA, valueB, valueC;

  int curStep = 0;    //current iteration
  
  //get the old color
   for(int iColor = 0; iColor <= 12; iColor++) {
    if(oldColor == colorName[iColor]) {
      a = colorRGB[iColor][0];
      b = colorRGB[iColor][1];
      c = colorRGB[iColor][2];
    }
  }
  //old color
  /*
  Serial.println ("Old Color");
  Serial.print (a);
  Serial.print (" ");  
  Serial.print (b);
  Serial.print (" ");  
  Serial.println (c);
  delay (3000); //to remove
  */
  
  // Look through the list of colors to find the one that was requested
  //valueXYZ is the new color
  for(int iColor = 0; iColor <= 12; iColor++) {
    if(color == colorName[iColor]) {
/*      Serial.print("Color is: ");
      Serial.println(colorName[iColor]);
      Serial.print("iColor is: ");
      Serial.println(iColor); */
      valueA = colorRGB[iColor][0];
      valueB = colorRGB[iColor][1];
      valueC = colorRGB[iColor][2];
      //colorSet(pixels.Color (colorRGB[iColor][0], colorRGB[iColor][1], colorRGB[iColor][2]));
    }
  }

/*
  //New color
  Serial.println ("New Color");
  Serial.print (valueA);
  Serial.print (" ");
  Serial.print (valueB);
  Serial.print (" ");  
  Serial.println (valueC);
  delay (3000); //to remove
*/
  //find the value for the transitions
  int stepA = abs((valueA - a) / steps);
  int stepB = abs((valueB - b) / steps);
  int stepC = abs((valueC - c) / steps);

/*
  //steps values
  Serial.println ("step values");
  Serial.print (stepA);
  Serial.print (" ");
  Serial.print (stepB);
  Serial.print (" ");  
  Serial.println (stepC);
  delay (3000); //to remove

*/
  //go throw the transitions of colors
  //Serial.println ("Iterations: ");
  while (curStep < steps) {
    a > valueA ? (a -= stepA) : (a += stepA);
    b > valueB ? (b -= stepB) : (b += stepB);
    c > valueC ? (c -= stepC) : (c += stepC);
/*
    //give some info
    Serial.print (a);
    Serial.print (" ");
    Serial.print (b);
    Serial.print (" ");    
    Serial.println (c);
    */
    
    //set the color
    colorSet(pixels.Color (a, b, c));
    delay(110); //delay a bit so we can observe the change of colors

    curStep++;
  }

  //final iteration and add the remainder 
  /*
  Serial.print (a);
  Serial.print (b);
  Serial.println (c);*/
  a += (valueA - a);
  b += (valueB - b);
  c += (valueC - c);
  colorSet(pixels.Color (a, b, c));
  oldColor = color;
  /*
  Serial.print ("old color ");
  Serial.println(oldColor);*/
}

/*
void setColor(String color) {
  // Look through the list of colors to find the one that was requested
  for(int iColor = 0; iColor <= 12; iColor++) {
    if(color == colorName[iColor]) {
      colorSet(pixels.Color (colorRGB[iColor][0], colorRGB[iColor][1], colorRGB[iColor][2]));
    }
  }
}

*/
// Fill strip with a color
void colorSet(uint32_t c) {
  for(uint16_t i=0; i<pixels.numPixels(); i++) {
      pixels.setPixelColor(i, c);
  }
   pixels.show();
}

Here’s a tweet with the result:

Hope you all like it !

References

https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout

https://learn.adafruit.com/cheerlights

http://cheerlights.com/