Saturday, December 24, 2011

It's a Christmas Miracle - Cheerlights for ENC28J60!

Just in Time!
     Okay, this will just be short, as I have holiday stuff to do soon! In case you have not heard about Cheerlights, here's a brief description: Cheerlights is a network of microcontrollers controlling colored lights based on social networking. The original Cheerlights used GE Color 50 lights, a string of addressable RGB LEDs and an ioBridge.
     Having none of this, but really wanting to participate, I downloaded the Arduino code. It, however, uses the Arduino Ethernet library, which didn't work with my ENC28J60 ethernet module (article coming soon). So basically I compiled this code together from the Cheerlights example and the example code from the Ethercard library. Huge thanks to everyone who worked on both of those, they are both awesome ideas. Also, I used an RGB LED from my local Radioshack. It's common anode.

My pseudo-Cheerlight setup taking its rightful place
next to the DVD player and [TiVo]




Here's the code (rather long):



/*


 CheerLights!

 CheerLights Channel --> Arduino Ethernet --> GE Color Effect Lights

 This sketch subscribes to the CheerLights ThingSpeak Channel and relays the
 last command from the Internet to a strand of GE Color Effects Lights. This
 sketch uses DHCP to obtain an IP address automatically and requires Arduino 1.0.

 Arduino Requirements:

   * Arduino Ethernet (or Arduino + Ethernet Shield)
   * Arduino 1.0 IDE
   * GEColorEffects Arduino 1.0 Library
     http://www.digitalmisery.com/wp-content/uploads/2011/11/GEColorEffects-Arduino-1.0.zip
   
 Network Requirements:


   * Ethernet port on Router    
   * DHCP enabled on Router
   * Unique MAC Address for Arduino


 Getting a Globally Unique MAC Address from ThingSpeak:

   * Sign Up for New User Account - https://www.thingspeak.com/users/new
   * Register your Arduino by selecting Devices, Add New Device
   * Once the Arduino is registered, click Generate Unique MAC Address
   * Enter the new MAC Address in this sketch under "Local Network Settings"

 Created: Novemeber 29, 2011 by Hans Scharler - http://www.iamshadowlord.com
 Modified for ENC28J60 December 24, 2011 by Thatcher Chamberlin - www.toasterbotics.blogspot.com

 Additional Credits:
 http://www.digitalmisery.com
 http://www.deepdarc.com

 To join the CheerLights project, visit http://www.cheerlights.com

*/


#include <EtherCard.h>


#define red 6
#define blue 5
#define green 7


byte Ethernet::buffer[700];
BufferFiller bfill;




// Local Network Settings
static byte mac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };


// ThingSpeak Settings
char thingSpeakAddress[] PROGMEM = "api.thingspeak.com";
String thingSpeakChannel = "1417";                // Channel number of the CheerLights Channel
String thingSpeakField = "1";                     // Field number of the CheerLights commands 
const int thingSpeakInterval = 16 * 1000;      // Time interval in milliseconds to get data from ThingSpeak (number of seconds * 1000 = interval)


// Variable Setup
long lastConnectionTime = 0; 
String lastCommand = "";
boolean lastConnected = false;
int failedCounter = 0;
String response;


// Initialize Arduino Ethernet Client




void setup() {
  pinMode(red, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(green, OUTPUT);
  delay(100);
  
  // Setup Serial
  Serial.begin(57600);
  delay(100);
  
  Serial.flush();
  delay(100);
  
  // Start Ethernet on Arduino
  startEthernet();
}


void loop() {
  if(millis() - lastConnectionTime > thingSpeakInterval)
  {
    subscribeToThingSpeak(thingSpeakChannel, thingSpeakField);
    lastConnectionTime = millis();
  }
   
  // Process CheerLights Commands
  //if(client.available() > 0)
  //if(ether.packetLoop(ether.packetReceive())){
    
     
    
    /*do {
        charIn = client.read(); // read a char from the buffer
        response += charIn; // append that char to the string response
      } while (client.available() > 0); 
      */
    word pos = ether.packetLoop(ether.packetReceive());
    if(pos){
      // Send matching commands to the GE-35 Color Effect Lights
      
    }
    
} // End loop










void subscribeToThingSpeak(String tsChannel, String tsField)
{
  ether.browseUrl(PSTR("/channels/1417/field/1/last.txt"), "", thingSpeakAddress, my_callback);
}


static void my_callback (byte status, word off, word len) {
  Ethernet::buffer[off+450] = 0;
  
  response = String((const char*)Ethernet::buffer + 353);
  Serial.print(String((const char*)Ethernet::buffer + 353));
  char* toast = (char *) Ethernet::buffer + 353;
  Serial.println(strncmp("red", toast, 3), DEC);
  if (strncmp("white", toast, 5) == 0)
      {  
          lastCommand = "white";
          digitalWrite(red, LOW);
          digitalWrite(green, LOW);
          digitalWrite(blue, LOW);
      }
      else if (strncmp("red", toast, 3)==0)
      {  
          lastCommand = "red";   
          digitalWrite(red, LOW);
          digitalWrite(green, HIGH);
          digitalWrite(blue, HIGH);
      }
      else if (strncmp("green", toast, 5) == 0)
      {  
          lastCommand = "green";
          digitalWrite(red, HIGH);
          digitalWrite(green, LOW);
          digitalWrite(blue, HIGH);
      }
      else if (strncmp("blue", toast, 4) == 0)
      {  
          lastCommand = "blue";  
          digitalWrite(red, HIGH);
          digitalWrite(green, HIGH);
          digitalWrite(blue, LOW);
      }
      else if (strncmp("cyan", toast, 4) == 0)
      {  
          lastCommand = "cyan";
          digitalWrite(red, HIGH);
          digitalWrite(green, LOW);
          digitalWrite(blue, LOW);
      }
      else if (strncmp("magenta", toast, 7) == 0)
      {  
          lastCommand = "magenta";
          digitalWrite(red, LOW);
          digitalWrite(green, HIGH);
          digitalWrite(blue, LOW);
      }
      else if (strncmp("yellow", toast, 6) == 0)
      {  
          lastCommand = "yellow";
          digitalWrite(red, LOW);
          digitalWrite(green, LOW);
          digitalWrite(blue, HIGH);
      }
      else if (strncmp("purple", toast, 6) == 0)
      {  
          lastCommand = "purple";
          analogWrite(red, 130);
          digitalWrite(green, HIGH);
          digitalWrite(blue, LOW);
      }
      else if (strncmp("orange", toast, 6) == 0)
      {  
          lastCommand = "orange";
          analogWrite(red, 70);
          digitalWrite(green, LOW);
          digitalWrite(blue, HIGH);
      }
      else if (strncmp("warmwhite", toast, 9) == 0)
      {  
          lastCommand = "warmwhite";
          digitalWrite(red, LOW);
          digitalWrite(green, LOW);
          analogWrite(blue,100);
      }
      else if (strncmp("black", toast, 5) == 0)
      {  
          lastCommand = "black";
          digitalWrite(red, HIGH);
          digitalWrite(green, HIGH);
          digitalWrite(blue, HIGH);
      }
      else
      {
          lastCommand = "(no match)"; 
          digitalWrite(red, HIGH);
          digitalWrite(blue, HIGH);
          digitalWrite(green, HIGH); 
      }
      delay(200);
    Serial.println("CheerLight Command Received: "+lastCommand);
    Serial.println();
    delay(200); 
}


void startEthernet()
{
  
  if (ether.begin(sizeof Ethernet::buffer, mac) == 0) {
    Serial.println( "Failed to access Ethernet controller");
  }
  if (!ether.dhcpSetup()){
    Serial.println("DHCP failed");
  }


  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip);  


  if (!ether.dnsLookup(thingSpeakAddress)){
    Serial.println("DNS failed");
  }
    
  ether.printIp("SRV: ", ether.hisip);
  
  Serial.println("Okay!");
  delay(1000);
}


     That should work right out of the box! As for connections, the ENC28J60 uses SPI with CS on Digital Pin 8. The LED definitions at the beginning can be changed however you like. Also, if you're using common cathode, you will want to change all the 'HIGH's to 'LOW's and vice versa.
    For those of you who don't have the time to build one of these awesome displays, you can visit the Cheerlights website and look at pictures of mine:


The ENC28J60 module from [eBay] attached to the free
protoshield from [Dangerous Prototypes].

A nice little aluminum wire stand holding up the film canister
diffuser.

The whole setup.
So, Happy Holidays! And don't forget to tweet your favorite color to @Cheerlights!



1 comment:

  1. I have the sketch running but i am not getting any changes of lights.

    ReplyDelete