My work schedule can get pretty crazy! Really crazy… I thought it might be cool to come up with a way to communicate to that to folks I work with.
I built a little wifi connected RGB LED that will display whether I’m busy, free or about to be busy inside of a 3d printed case. I’ve got all of the 3d files and code here available for download.
3d files
The construction was in two parts, the 3d Files were sent to Shapeways and printed with a SLS process. (They call it ‘strong and flexible’). The topper (transparent shark piece) was ‘clear detail’. Both the case and the topper aren’t particularly well suited to a home 3d printer because of hard drop offs on the case and the topper is very small with fine detail.
Build Gallery
The wooden base was a pre-cut railing piece from home depot that I drilled holes for the case pegs to push into. I used a lazy method of putting a little paint from a paint pen on the bottom of the pegs, pushed it against the wood for a close approximation of where to drill. This method isn’t precise but in this case it worked well because the slightly imprecise hole placement put a little lateral pressure on the pegs and friction helps keep the case on the wood.
Photon Code
The brains behind the LED is a photon, wifi connected microcontroller. The code is pretty simple, it’s basically waiting for an rgb hex value from the Particle API. When it sees it, it parses it out and sets the three PWM channels appropriately. This is mostly from a quick example I found somewhere on the web.
#include // only for round();
#define MAX_PARAMS 3 // 3 color channels
String firstArgs = "15,221,222"; // for testing, ints only
String secondArgs = "120.0,121.7,222.9"; // for testing, floats
int led[] = {A4,A5,A6}; // You'll need to wire the RGB-LED:
int onBoardLED = D7; // This one is the built-in tiny one to the right of the USB jack
int sensorReading = 0;
const int knockSensor = A7; // the piezo is connected to analog pin 0
const int threshold = 2080; // threshold value to decide when the detected sound is a knock or not
void setup() {
/*
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(A6, OUTPUT);
pinMode(A7, OUTPUT);
*/
for(int i=0;i MAX_PARAMS) ? MAX_PARAMS : allValuesCount;
for(int i=0; i 255) ? 255: value;
// apply the value on the LED
analogWrite(led[i], value) ;
//Spark.publish(String(value));
}
/*
for(int i=0;i<30;i++)// just blink and wait
{
digitalWrite(onBoardLED, HIGH);
delay(100); // Wait for 100mS = 1/10 second
digitalWrite(onBoardLED, LOW);
delay(100); // Wait for 1/10 second in off mode
}
*/
return 1;
}
Color Server
On the server side, I put together a small nodeJS Script that handles colors with an API. Given a server address, it can constantly check for a color from that URL. Or it can accept arbitrary colors through GET requests.
It’s not quite fleshed out here but I thought a fun way to extend this script would be a robust way of keeping track of ‘color devices’, what their current color is, an API to set a new one and an ‘input’ source that would affect it’s color automatically.
var http = require("http");
var request = require('request');
var Router = require('routes');
var router = Router();
var url = require('url')
var handle = null;
var current_color = null;
handle = setInterval(checkColor, 10000);
router.addRoute('/', handleHome);
router.addRoute('/color/:red/:green/:blue/:time', handleColor);
router.addRoute('/*', handle404);
http.createServer(function (req, res) {
var path = url.parse(req.url).pathname;
var match = router.match(path);
match.fn(req, res, match);
}).listen(12415)
function handleHome(req, res, match) {
fs = require('fs')
fs.readFile('~/webapps/rgb/index.html', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
res.statusCode = 200;
res.write(data);
res.end();
});
}
function handle404(req, res, match) {
res.statusCode = 404;
res.write("404, page not found");
res.end();
}
function handleColor(req, res, match) {
clearInterval(handle);
res.statusCode = 200;
res.end();
current_color = null;
console.log(match);
setColor(match.params.red, match.params.green, match.params.blue);
handle = setInterval(checkColor, match.params.time * 1000);
}
function setColor(r,g,b) {
console.log("set the color!" + r + "," + g + "," + b);
request.post('https://api.spark.io/v1/devices/YOUR_DEVICE_ID/changeColor',
{ form: { "access_token": 'YOUR_ACCESS_TOKEN', "args": r + "," + g + "," + b } },
function (error, response, body) {
if (!error) { // && response.statusCode == 200) {
console.log(body)
}
}
);
}
function checkColor() {
request('BUSY_URL_HERE', function (error, response, body) {
if (!error && response.statusCode == 200) {
if(current_color != body) {
console.log(body) // Show the HTML for the Google homepage.
switch(body) {
case "yes":
setColor(255,1,1);
break;
case "no":
setColor(1,255,1);
break;
case "almost":
setColor(255,255,1);
break;
}
current_color = body;
} else {
console.log("already set this color");
}
}
});
}
Outlook Calendar (Busy/Free) Parser
This server side php file will look at a local .VFB file, and parse it out to figure out, am I busy, free or about to be busy (15 minutes or less from being busy) and returns a JSONP file. Pretty simple, the color server will look for this file at it’s URL and use it to determine color!
Basically, have a look at this link about how to publish your free/busy schedule to an FTP location. Then, put this php script somewhere that can see the file locally.
< ?php
$busyonly = $_REQUEST['busyonly'];
// Output one line until end-of-file
$myfile = fopen("tom.vfb", "r") or die("Unable to open file!");
$busy = false;
date_default_timezone_set('America/New_York');
$now = date(time());
$busy = "no";
$json = 'jsonCallback({"events": [';
$myfile = fopen("tom.vfb", "r") or die("Unable to open file!");
while(!feof($myfile)) {
$line = fgets($myfile);
if( startswith($line, "FREEBUSY:") ){
$start = strtotime(substr($line, 9, 16));
$startminus = $start - 900;
$end = strtotime(substr($line, 26, 16));
if($now > $startminus && $now < $end)
{
$busy = "almost";
}
//date('l dS \o\f F Y h:i:s A', $start)
}
}
fclose($myfile);
$myfile = fopen("tom.vfb", "r") or die("Unable to open file!");
while(!feof($myfile)) {
$line = fgets($myfile);
if( startswith($line, "FREEBUSY:") ){
$start = strtotime(substr($line, 9, 16));
$end = strtotime(substr($line, 26, 16));
if($now > $start && $now < $end)
{
$busy = "yes";
}
//date('l dS \o\f F Y h:i:s A', $start)
$json .= '{"start":"' . date('Y-m-d H:i:s', $start) . '","end":"' . date('Y-m-d H:i:s', $end) . '"},';
}
}
fclose($myfile);
$json = rtrim($json, ",");
//$busystring = ($busy) ? 'true' : 'false';
$busystring = $busy;
$json .= '],"busy": "' . $busystring . '"});';
if($busyonly == "true") {
echo $busystring;
} else {
header('Content-Type: application/javascript');
echo $json;
}
function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
?>





