Skip to content

Instantly share code, notes, and snippets.

@rmasters
Last active December 30, 2015 11:18
Show Gist options
  • Save rmasters/7821375 to your computer and use it in GitHub Desktop.
Save rmasters/7821375 to your computer and use it in GitHub Desktop.
Code for Cheerlights Arduino hack
#include <SPI.h>
#include <WiFi.h>
#include <b64.h>
#include <HttpClient.h>
#include <Adafruit_WS2801.h>
#define PIXELS 25
#define DATA_PIN 2
#define CLOCK_PIN 3
Adafruit_WS2801 chain = Adafruit_WS2801(PIXELS, DATA_PIN, CLOCK_PIN);
char wifi_ssid[] = "SSID";
char wifi_pass[] = "PASSPHRASE";
int wifi_status = WL_IDLE_STATUS;
WiFiClient client;
HttpClient http(client);
const char server[] = "api.thingspeak.com";
const char path[] = "/channels/1417/field/1/last.txt";
/**
* See if we can find the selected SSID
*/
boolean networkAvailable(char ssid[]) {
byte networks = WiFi.scanNetworks();
for (int i = 0; i < networks; i++) {
if (strcmp(WiFi.SSID(i), ssid) == 0) {
return true;
}
}
return false;
}
/**
* Write information about the network to a Serial connection
*/
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void setup() {
chain.begin();
chain.show();
Serial.begin(9600);
// Uncomment to wait for a Serial connection. Comment to run headless
//while(!Serial);
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
while(true);
}
Serial.print("Scanning for ");
Serial.println(wifi_ssid);
if (!networkAvailable(wifi_ssid)) {
Serial.println("Not found");
while(true);
}
Serial.println("Found");
wifi_status = WiFi.begin(wifi_ssid, wifi_pass);
delay(10000);
if (wifi_status != WL_CONNECTED) {
Serial.println("Unable to connect");
while(true);
}
printWifiStatus();
}
void loop() {
String colour = readChunked(httpRequest());
Serial.println(colour);
setLights(colour);
delay(20000);
}
// Saved half an hour of messing with strtoul
// https://github.com/benrugg/Arduino-Hex-Decimal-Conversion/blob/master/hex_dec.ino
unsigned int hexToDec(String hexString) {
unsigned int decValue = 0;
int nextInt;
for (int i = 0; i < hexString.length(); i++) {
nextInt = int(hexString.charAt(i));
if (nextInt >= 48 && nextInt <= 57) nextInt = map(nextInt, 48, 57, 0, 9);
if (nextInt >= 65 && nextInt <= 70) nextInt = map(nextInt, 65, 70, 10, 15);
if (nextInt >= 97 && nextInt <= 102) nextInt = map(nextInt, 97, 102, 10, 15);
nextInt = constrain(nextInt, 0, 15);
decValue = (decValue * 16) + nextInt;
}
return decValue;
}
/**
* Read a chunked-transfer-encoded response into a String
* A bit naiive - it doesn't handle malformed responses well and assumes a 0-length chunk is the last
*/
String readChunked(String bodyStr) {
char body[bodyStr.length()];
bodyStr.toCharArray(body, bodyStr.length());
boolean read_size = true;
char chr;
String sizebuf = "";
String chunkbuf = "";
String bodybuf = "";
unsigned int start = 0;
unsigned int len = 0;
// Run through each character of body
for (int i = 0; i < sizeof(body); i++) {
chr = body[i];
//Serial.print(i);Serial.print("] ");Serial.println(chr);
if (read_size) {
// Reading a chunk size
sizebuf += chr;
if (sizebuf.endsWith("\r\n")) {
// Finished reading this chunk size
// Convert size from hexadecimal
sizebuf.trim();
len = hexToDec(sizebuf);
// If the chunk is empty assume it's the last
if (len == 0) {
break;
}
// Cleanup
sizebuf = "";
// Starting chunk index
start = i + 1;
// Change into chunk reading mode
read_size = false;
}
} else {
// Reading a chunk
chunkbuf += chr;
if (i - (start - 1) == len) {
// We've read the designated number of bytes
bodybuf += chunkbuf;
// Cleanup
chunkbuf = "";
// Change to size read mode
read_size = true;
// Skip the next CRLF
i += 2;
len = 0;
}
}
}
return bodybuf;
}
/**
* Make the HTTP request
*/
String httpRequest() {
Serial.print("GET ");
Serial.println(path);
int err = http.get(server, path);
String body;
if (err == 0) {
err = http.responseStatusCode();
if (err == 200) {
err = http.skipResponseHeaders();
if (err >= 0) {
unsigned long timeoutStart = millis();
unsigned long netTimeout = 30000;
unsigned long netDelay = 1000;
int i = 0;
while((http.connected() || http.available()) && ((millis() - timeoutStart) < netTimeout)) {
if (http.available()) {
char c = http.read();
body += c;
timeoutStart = millis();
} else {
delay(netDelay);
}
}
} else {
Serial.print("Failed to skip headers, err: ");
Serial.println(err);
}
} else {
Serial.print("Failed to get response, status: ");
Serial.println(err);
}
} else {
Serial.print("Failed to connect, err: ");
Serial.println(err);
}
http.stop();
return body;
}
/**
* Create a color octet from rgb values
* Source: http://learn.adafruit.com/12mm-led-pixels/code
*/
uint32_t Color(byte r, byte g, byte b) {
uint32_t c;
c = r;
c <<= 8;
c |= g;
c <<= 8;
c |= b;
return c;
}
/**
* Progressively change pixel colours along the chain
*/
void colorWipe(uint32_t c, uint8_t wait) {
int i;
for (i = 0; i < chain.numPixels(); i++) {
chain.setPixelColor(i, c);
chain.show();
delay(wait);
}
}
/**
* Defines RGB colours for Cheerlight names and wipe new colour
*/
void setLights(String name) {
uint32_t colour;
if (name.equals("red")) {
colour = Color(255, 0, 0);
} else if (name.equals("green")) {
colour = Color(0, 255, 0);
} else if (name.equals("blue")) {
colour = Color(0, 0, 255);
} else if (name.equals("cyan")) {
colour = Color(0, 255, 255);
} else if (name.equals("white")) {
colour = Color(255, 255, 255);
} else if (name.equals("warmwhite")) {
colour = Color(255, 200, 200);
} else if (name.equals("purple")) {
colour = Color(128, 0, 128);
} else if (name.equals("magenta")) {
colour = Color(255, 0, 255);
} else if (name.equals("yellow")) {
colour = Color(255, 255, 0);
} else if (name.equals("orange")) {
colour = Color(255, 165, 0);
} else {
colour = Color(0, 0, 0);
}
colorWipe(colour, 50);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment