Skip to content

Instantly share code, notes, and snippets.

@kgleeson
Last active August 29, 2015 13:57
Show Gist options
  • Save kgleeson/9387458 to your computer and use it in GitHub Desktop.
Save kgleeson/9387458 to your computer and use it in GitHub Desktop.
Clock
modes <- array();
function getWeather()
{
local url = "https://api.forecast.io/forecast/XXXXXXXXXXXX/53.3331,-6.2489?units=si";
local res = http.get(url, {}).sendsync();
if (res.statuscode != 200)
{
server.log("Forecast.io Error: " + res.statuscode + " => " + res.body);
} else
{
try
{
return http.jsondecode(res.body);
}
catch (e)
{
server.error("Forecast.io Error: " + e)
}
}
}
function getSunTimes(modeNum)
{
local response = getWeather();
if(response) {
server.log(response.daily.data[0].sunriseTime);
local today = response.daily.data[0];
local dRise = date(today.sunriseTime);
local dSet = date(today.sunsetTime);
local Sun = { rise=((dRise.hour/2)*5 + (dRise.min/12)), down=((dSet.hour/2)*5 + (dSet.min/12)), i=modeNum};
device.send("sun", Sun)
server.log(format("Sunrise: %d:%d Sunset: %d:%d", dRise.hour, dRise.min, dSet.hour, dSet.min));
}
}
function getCurrentTemp(modeNum)
{
local response = getWeather();
if(response)
{
local temperature = response.currently.temperature;
local date = { temp=temperature, i=modeNum };
device.send("temp", date);
server.log(format("The temp is %2f°c", temperature));
}
}
function setModes(names)
{
modes = names;
generateUrls();
}
device.on("setModes", setModes);
function generateUrls()
{
for(local i = 0; i < modes.len(); i++)
{
server.log("Turn " + modes[i] + " On: " + http.agenturl() + "?mode=" + i);
}
}
function checkMode(mode)
{
if(modes[mode] == "Sun times")
{
server.log("Sun times");
getSunTimes(mode);
}
if(modes[mode] == "Temperature")
{
server.log("Temperature");
getCurrentTemp(mode);
}
}
function requestHandler(request, response)
{
// local c_mode;
local message = "";
try {
// check if the user sent led as a query parameter
if ("mode" in request.query)
{
local mode = request.query.mode.tointeger();
if((mode < 0) || (mode >= modes.len())) mode = 0;
message = modes[mode];
server.log(" Requested " + modes[mode]);
checkMode(mode);
device.send("mode", mode);
}
if ("fillclock" in request.query)
{
local fillclock = request.query.fillclock.tointeger();
local mode = false;
if(fillclock) mode = true;
device.send("fillclock", mode);
message = format("Fill Clock is %s", mode ? "true" : "false");
}
if ("segments" in request.query)
{
local segments = request.query.segments.tointeger();
local data = {segments=segments, i=modes.find("Windmill")}
device.send("windmill", data);
message = format("Windmill segments set to %d", segments);
}
if ("debug" in request.query)
{
local debug = request.query.debug.tointeger();
local mode = false;
if(debug == 1) mode = true;
server.log("Debug is " + mode);
device.send("debug", mode);
message = format("Debug is %s", mode ? "true" : "false");
server.log(message);
}
if ("demo" in request.query)
{
local demo = request.query.demo.tointeger();
local mode = false;
if(demo == 1) mode = true;
server.log("Demo is " + mode);
device.send("demo", mode);
message = format("Demo is %s", mode ? "true" : "false");
server.log(message);
}
if ("delay" in request.query)
{
local delay = request.query.delay.tofloat();
device.send("delay", delay);
message = format("Delay set to %f seconds", delay);
server.log(message);
}
local ip = request.headers["x-forwarded-for"];
server.log("IP Address " + ip);
response.send(200, format("OK\n%s", message));
}
catch (ex)
{
response.send(500, "Internal Server Error: " + ex);
}
}
// register the HTTP handler
http.onrequest(requestHandler);
const SPICLK = 7500; // kHz
const BYTESPERPIXEL = 24;
class NeoPixels
{
ZERO = 0xC0;
ONE = 0xF8;
bits = null;
clearblob = blob(BYTESPERPIXEL);
spi = null; // imp SPI interface (pre-configured)
frameSize = null; // number of pixels per frame
frame = null; // a blob to hold the current frame
constructor(_spi, _frameSize)
{
this.spi = _spi;
this.frameSize = _frameSize;
this.frame = blob(frameSize*BYTESPERPIXEL + 1);
// prepare the bits array and the clearblob blob
initialize();
clearFrame();
writeFrame();
}
function initialize()
{
bits = array(256);
for (local i = 0; i < 256; i++)
{
local valblob = blob(BYTESPERPIXEL / 3);
valblob.writen((i & 0x80) ? ONE:ZERO,'b');
valblob.writen((i & 0x40) ? ONE:ZERO,'b');
valblob.writen((i & 0x20) ? ONE:ZERO,'b');
valblob.writen((i & 0x10) ? ONE:ZERO,'b');
valblob.writen((i & 0x08) ? ONE:ZERO,'b');
valblob.writen((i & 0x04) ? ONE:ZERO,'b');
valblob.writen((i & 0x02) ? ONE:ZERO,'b');
valblob.writen((i & 0x01) ? ONE:ZERO,'b');
bits[i] = valblob;
}
// now fill the clearblob
for(local j = 0; j < BYTESPERPIXEL; j++)
{
clearblob.writen(ZERO, 'b');
}
// must have a null at the end to drive MOSI low
clearblob.writen(0x00,'b');
}
function writePixel(p, color)
{
frame.seek(p*BYTESPERPIXEL);
// red and green are swapped for some reason, so swizzle them back
frame.writeblob(bits[color[1]]);
frame.writeblob(bits[color[0]]);
frame.writeblob(bits[color[2]]);
}
function clearFrame()
{
frame.seek(0);
for (local p = 0; p < frameSize; p++) frame.writeblob(clearblob);
}
function writeFrame()
{
spi.write(frame);
}
}
RED <- [255,0,0];
GREEN <- [0,255,0];
BLUE <- [0,0,255];
CYAN <- [0,255,255];
WHITE <- [255,255,255];
WARMWHITE <- [253,245,230];
MAGENTA <- [255,0,255];
YELLOW <- [255,255,0];
PACYELLOW <- [100,100,0];
ORANGE <- [255,165,0];
PINK <- [255,192,203];
PURPLE <- [128,0,128];
OLDLACE <- [255,192,203];
BLACK <- [0,0,0];
DARKGREY <- [1,1,1];
LIGHTGREY <- [20,20,20];
const NUMPIXELS = 60;
spi <- hardware.spi257;
spi.configure(MSB_FIRST, SPICLK);
pixelStrip <- NeoPixels(spi, NUMPIXELS);
function logToServer(message)
{
if(debug) server.log(message);
}
function colourString(colour)
{
return format("[%d, %d, %d]", colour[0], colour[1], colour[2]);
}
class Mode
{
startTime = null;
name = null;
pixels = null;
colourWheel = null;
constructor()
{
logToServer("Creating pixels with len of " + NUMPIXELS);
pixels = array(NUMPIXELS);
clearPixels();
}
function timer(stop=false)
{
if(debug)
{
if(!stop)
{
startTime = hardware.millis();
} else
{
logToServer(format("Took %fms", hardware.millis()-startTime));
}
}
}
function outputArray()
{
if(debug)
{
local message = "";
for(local i = 0; i < NUMPIXELS; i++)
{
message = format("%s%s", message, colourString(pixels[i]));
}
server.log(message);
}
}
function drawPixels()
{
for(local i = 0; i < NUMPIXELS; i++)
{
logToServer("Writing pixel " + i + " to " + colourString(pixels[i]));
pixelStrip.writePixel(i, pixels[i]);
}
}
function setPixel(i, colour)
{
pixels[i] = colour;
logToServer("Set pixels[" + i + "] to " + colourString(pixels[i]));
}
function max(num, maxnum=0)
{
return (num > maxnum) ? num : maxnum;
}
function setColour(colour, fadeby=1)
{
local fadedColour = [(colour[0]*fadeby).tointeger(), (colour[1]*fadeby).tointeger(), (colour[2]*fadeby).tointeger()];
logToServer(colourString(fadedColour));
return fadedColour;
}
function rotate(num=1)
{
for(local i = 0; i < num; i++)
{
local lastPixel = pixels.pop();
pixels.insert(0, lastPixel);
}
}
function clearPixels(colour=BLACK)
{
for(local i = 0; i < NUMPIXELS; i++)
{
setPixel(i, colour);
}
}
function genColourWheel()
{
colourWheel = array();
local steps = 20;
local rgbColour = [255, 0, 0];
for(local decColour = 0; decColour < 3; decColour++)
{
local incColour = (decColour == 2) ? 0 : decColour + 1;
for(local i = 0; i < steps; i++)
{
local changeBy = 255/steps;
rgbColour[decColour] = changeColourBy(rgbColour[decColour], -(changeBy));
rgbColour[incColour] = changeColourBy(rgbColour[incColour], changeBy);
logToServer("Inserting " + colourString(rgbColour));
colourWheel.insert(0, [rgbColour[0], rgbColour[1], rgbColour[2]]);
}
}
if(debug)
{
logToServer("Generated Array:")
for(local i = 0; i < colourWheel.len() ; i++)
{
logToServer("[" + i + "] " + colourString(colourWheel[i]));
}
}
}
function getFromColourWheel()
{
genColourWheel();
for(local i = 0 ;; i++)
{
i = i % colourWheel.len();
logToServer("Yielding [" + i + "] " + colourString(colourWheel[i]));
yield colourWheel[i];
}
}
function changeColourBy(colour, value)
{
local returnValue = colour + value;
returnValue = (returnValue < 0) ? 0 :returnValue;
returnValue = (returnValue > 255) ? 255 : returnValue;
return returnValue.tointeger();
}
function draw()
{
timer();
pixelStrip.clearFrame();
update();
drawPixels();
pixelStrip.writeFrame();
imp.wakeup(delay, setMode);
timer(true);
}
}
class Clock extends Mode
{
lastSec = null;
fillClock = null;
PENTDIVCOL = null;
DIVCOL = null;
SECCOL = null;
MINCOL = null;
HOURCOL = null;
constructor(_fillClock=false)
{
base.constructor();
lastSec = date(time()).sec;
PENTDIVCOL = LIGHTGREY;
DIVCOL = DARKGREY;
SECCOL = RED;
MINCOL = GREEN;
HOURCOL = BLUE;
fillClock = _fillClock;
name = "Clock"
}
function update()
{
local d = date(time());
logToServer("Clocking");
logToServer(format("%d:%d:%02d", d.hour, d.min, d.sec));
local hourPixel = ((d.hour % 12) * 5);
for(local i = 0; i < NUMPIXELS; i++)
{
setPixel(i, DIVCOL);
if(i % 5 == 0) setPixel(i, PENTDIVCOL);
if(fillClock)
{
local secondGreatThanMinAndHour = ((i < d.sec) && (d.sec > d.min) && (d.sec > (hourPixel)));
local minLessThanHour = ((d.min < (hourPixel) && (i < d.min)));
if(secondGreatThanMinAndHour) setPixel(i, SECCOL);
if(i < d.min) setPixel(i, MINCOL);
if(i < hourPixel) setPixel(i, HOURCOL);
if(minLessThanHour) setPixel(i, MINCOL);
}
if(d.min == hourPixel)
{
setPixel(d.min-1, HOURCOL);
setPixel(d.min+1, HOURCOL);
}
if(i == hourPixel) setPixel(i, HOURCOL);
if(i == d.min) setPixel(i, MINCOL);
if(i == d.sec) setPixel(i, SECCOL);
}
}
}
class Pac extends Mode
{
direction = null;
offset = null;
start = null;
constructor()
{
base.constructor();
direction = 1;
offset = 0;
start = 15;
name = "Pac";
}
function update()
{
for(local i = 0; i < NUMPIXELS; i++)
{
setPixel(i, PACYELLOW);
}
for(local i = start; i < start+offset; i++)
{
setPixel(i+offset, BLACK);
setPixel(i, BLACK);
setPixel(i-offset, BLACK);
}
offset = offset + direction;
if(offset >= 5 || offset == 0 ) direction *= -1;
logToServer("Pacing");
}
}
class Chase extends Mode
{
chase_start = 0;
constructor()
{
base.constructor();
name = "Chase";
clearPixels();
setPixel(chase_start, RED);
}
function update()
{
logToServer("Chasing");
rotate()
}
}
class Rainbow extends Mode
{
genColour = null;
rgbColour = null;
constructor()
{
base.constructor();
genColour = getColour();
name = "Rainbow";
clearPixels();
}
function getColour()
{
local colours = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE];
for(local i = 0 ;; i++)
{
i = i % colours.len();
local count = NUMPIXELS/colours.len();
for(local j=0 ; j < count ; j++)
{
// server.log(colourString(colours[i]));
yield colours[i];
}
}
}
function update()
{
logToServer("Rainbowing");
local lastPixel = pixels.pop();
local colour = resume genColour;
logToServer("Pixel is: " + colourString(colour));
pixels.insert(0, colour);
}
}
class Segment extends Mode
{
lit = null;
length = null;
colour = null;
pixels = null;
constructor(_lit, _length, _colour)
{
lit = _lit;
length = _length;
colour = _colour;
pixels = array(length);
for(local i = 0; i < length; i++)
{
local setColour = (i <= lit) ? colour : BLACK;
setPixel(i, setColour);
}
}
function update()
{
rotate();
}
}
class Windmill extends Mode
{
numOfSegments = null;
colour = null;
length = null;
litPerSeg = null;
segments = null;
constructor(_numOfSegments, _colour)
{
base.constructor();
numOfSegments = _numOfSegments;
colour = _colour;
length = NUMPIXELS / numOfSegments;
litPerSeg = length / 3;
segments = array(numOfSegments);
name = "Windmill"
for(local i = 0; i < numOfSegments; i++)
{
segments[i] = Segment(litPerSeg, length, colour);
}
}
function update()
{
for(local i = 0; i < numOfSegments; i++)
{
for(local j = 0; j < length; j++)
{
setPixel(( j + i * length), segments[i].pixels[j]);
}
segments[i].update();
}
}
}
class Kitt extends Mode
{
length = null;
direction = null;
offset = null;
fadeArray = null;
constructor(_length)
{
base.constructor();
length = _length;
direction = 1;
offset = 0;
name = "Kitt";
fadeArray = array(length);
for(local i = 0 ; i < fadeArray.len() ; i++)
{
fadeArray[i] = [(255-(50*i)).tointeger(),0,0];
}
}
function update()
{
clearPixels();
if(offset+length == NUMPIXELS)
{
direction = -1;
fadeArray.reverse();
}
if(offset == 0)
{
direction = 1;
fadeArray.reverse();
}
for(local i = offset; i < offset+length; i++)
{
setPixel(i, fadeArray[i-offset]);
}
offset = offset+direction;
if(offset == NUMPIXELS) offset = 0;
}
}
class Pulse extends Mode
{
leds = null;
colour1 = null;
colour2 = null;
constructor(_colour1, _colour2)
{
base.constructor();
colour1 = _colour1;
colour2 = _colour2;
name = "Pulse";
for(local i = 0; i < NUMPIXELS; i++)
{
local setColour = (i % 5 != 0) ? colour1 : colour2;
setPixel(i, setColour);
}
}
function update()
{
local oldPixel = pixels[30];
pixels.remove(30);
pixels.insert(0, oldPixel);
oldPixel = pixels[30];
pixels.remove(30);
pixels.insert(59, oldPixel);
}
}
class Sunlight extends Mode
{
rise = null;
down = null;
NIGHTCOLOUR = null;
DAYCOLOUR = null;
constructor()
{
base.constructor();
rise = 0;
down = 0;
NIGHTCOLOUR = BLUE;
DAYCOLOUR = YELLOW;
name = "Sun times";
}
function sinFade(i, colour)
{
local totalSun = down - rise;
local led = i - rise;
local sunPi = (totalSun)/PI
local fadeby = math.sin(led/sunPi);
logToServer("i = " + i + " led = " + led + " sunPi = " + sunPi + " fadeby = " + fadeby);
local fadedColour = setColour(colour, fadeby);
return fadedColour;
}
function update()
{
local d = date(time());
local now = ((d.hour/2)*5 + (d.min/12));
for(local i = 0; i < NUMPIXELS; i++)
{
local colour = NIGHTCOLOUR;
if ((i >= rise)&&(i <= down))
{
colour = sinFade(i, DAYCOLOUR);
}
logToServer(format("[%d, %d, %d]", colour[0], colour[1], colour[2]));
setPixel(i, colour);
}
setPixel(now, RED);
}
}
class Temperature extends Mode
{
temp = null;
TEMPCOLOUR = null;
constructor()
{
base.constructor();
temp = 0;
TEMPCOLOUR = RED;
name = "Temperature";
}
function update()
{
for(local i = 0; i < NUMPIXELS; i++)
{
local colour = BLACK;
if (i <= temp)
{
colour = ((i % 5 == 0) && (i != 0)) ? WHITE : TEMPCOLOUR;
}
setPixel(i, colour);
}
}
}
class Fader extends Mode
{
genColour = null;
constructor()
{
base.constructor();
name = "Fader";
genColour = getFromColourWheel();
}
function update()
{
local colour = resume genColour;
pixels.pop();
pixels.insert(0, colour);
}
}
class Waiting extends Mode
{
colours = null;
offset = null;
direction = null;
constructor()
{
base.constructor();
colours = [RED, YELLOW, GREEN, BLUE];
offset = 0;
direction = 0;
name = "Waiting"
}
function update()
{
for(local i = 0; i < offset; i++)
{
local px1 = (((direction * 15 + i) % 60) + 60) % 60;
local px2 = (((direction * 15 - i) % 60) + 60) % 60;
setPixel(px1, colours[direction]);
setPixel(px2, colours[direction]);
if(offset == 32)
{
direction = (direction + 1) % 4;
offset = 0;
}
}
offset++;
}
}
function addMode(modeName)
{
modes.push(modeName);
}
function setMode()
{
modes[current_mode].draw();
if(demo) demoMode();
}
function demoMode()
{
local timeSec = date(time()).sec
if((timeSec % 10 == 0) && (demoTime != timeSec))
{
demoTime = timeSec
current_mode = (current_mode++) % modes.len();
}
}
function sendNames() {
local names = [];
foreach(mode in modes)
{
names.push(mode.name);
}
agent.send("setModes", names);
}
function setCurrentMode(mode)
{
current_mode = mode;
logToServer("Set mode: " + current_mode + " : " + modes[mode].name);
}
function changeWindmill(data)
{
modes.remove(data.i);
modes.insert(data.i, Windmill(data.segments, RED));
}
function setFillClock(mode)
{
logToServer(format("Set fillclock %s", mode ? "true" : "false"));
modes[0].fillClock = mode;
}
function setDebug(mode)
{
if((mode == true)||(mode == false)) debug = mode;
}
function setDemo(mode)
{
if((mode == true)||(mode == false)) demo = mode;
}
function setDelay(delay)
{
delay = delay;
}
function setSun(data)
{
modes[data.i].rise = data.rise;
modes[data.i].down = data.down;
}
function setTemp(data)
{
modes[data.i].temp = data.temp;
}
agent.on("mode", setCurrentMode);
agent.on("fillclock", setFillClock);
agent.on("debug", setDebug);
agent.on("demo", setDemo);
agent.on("sun", setSun);
agent.on("temp", setTemp);
agent.on("windmill", changeWindmill);
agent.on("delay", setDelay);
modes <- [];
current_mode <- 0;
debug <- false;
demo <- false;
delay <- 0.001;
demoTime <- 1;
addMode(Clock()); //0
addMode(Chase()); //1
addMode(Rainbow()); //2
addMode(Pac()); //3
addMode(Windmill(4, RED)); //4
addMode(Kitt(6)); //5
addMode(Pulse(GREEN, RED)); //6
addMode(Sunlight()); //7
addMode(Temperature()); //8
addMode(Fader()); //9
addMode(Waiting()); //10
setMode();
sendNames();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment