This requires the WiFiClient, Adafruit_WS2801 and HttpClient libraries.
Last active
December 30, 2015 11:18
-
-
Save rmasters/7821375 to your computer and use it in GitHub Desktop.
Code for Cheerlights Arduino hack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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