Control our office lights from our website
Starting today you can change the colour of our office lights from q42.com and q42.nl (in fact, you can do it from this page!). Each page features a colour wheel at the top right in the navigation bar which you can click to open a colour picker. Just pick a colour, any colour, and within milliseconds, the colour of our Hue LED lights in our office in The Hague will change as well as the background colour of the header bar. Awesome!
Read below for some more technical details of how we built this.
Talking to our Hue lights
Since working together with Philips last year to launch the Hue LED lighting system we’ve been itching to build something with it ourselves. The first project was Huelandsspoor, which allows visitors to that website to control the colour of various areas of our office. Ever since we felt that a feature like this should be available from our homepage, but we never got around to building it in. Until today.
To get Huelandsspoor working, our team built a C# web service that talks to our internal Hue bridge, working as a proxy to allow public calls to it. That web service is exposed over HTTP with a REST interface and used directly by Huelandsspoor itself. So to get things working on q42.nl, we merely had to call the web service:
$.get("http://huelandsspoor.nl/api/lamps/setcolor?color=" + color)
But asking our visitors to call that URL isn’t very user friendly or attractive, so the next step was to add some sort of UI.
Native colour picker with HTML5
It turns out Chrome shipped a working implementation of input type=“color” a while back. Geeks that we are, it felt obligatory to try our hand at implementing it. And it works pretty well. In our navigation bar, we place the input:
<input type="color" id="lights-color" />
Here’s what it looks like by default:
And attach some events (Meteor style):
Template.header.events({
"input #lights-color": function(evt) {
var color = $(evt.target).val().replace("#", "");
$.get("http://huelandsspoor.nl/api/lamps/setcolor?color=" + color);
}
});
When clicking on a colour in the native colour picker, the input element receives an input event (rather than the more traditional change event we’re so used to seeing — btw, Googling for “input type color input event” doesn’t work so well…) and calls the Huelandsspoor API with the selected color. Let’s also go ahead and update the input’s value and style itself so it reflects the new selection:
$(evt.target).attr("value", "#" + color).css("background-color", "#" + color);
Great! So now we have direct control over the lights in the office with only a few lines of code.
But we need to go deeper. Since we’re using Meteor, it would be nice if everyone viewing q42.nl would see a realtime representation of the current colour of our office lights. That means we need to tell the server what’s going on so it can distribute that information to all the other clients. Let’s start by invoking a server endpoint:
$.get("/updateLightbar");
We’re using an endpoint (exposed by adding the meteor-router package) because we want to be able to call this endpoint from elsewhere, too. Otherwise we might just choose a regular Meteor method.
Now we need to store the lights and then hook them into Meteor’s reactivity so that everything updates automagically. Step one is storing the lights in Mongo:
var Lights = new Meteor.Collection("lights");
So what does the endpoint do? It runs this method:
updateLightbar = function () {
Meteor.http.get("http://huelandsspoor.nl/api/lamps/getlamps", function(err, result) {
_.map(JSON.parse(result.content), function(item) {
Lights.insert({hex: item.ColorHex});
});
});
}
updateLightbar asks Huelandsspoor for the current colours of each light (there are 29 in our office) and inserts them into our Lights collection. Then, once we know that we have some data about the lights, we publish the collection to the client:
Meteor.publish("lights", function() {
return Lights.find();
});
And then we subscribe to them:
Meteor.startup(function() {
Deps.autorun(function() {
Meteor.subscribe("lights");
updateLightbar();
});
});
Hey look, another updateLightbar method! This one’s on the client and handles display of the lights in the lightbar. Since we have 29 lights and 29 (potentially) different colours looked terrible in testing, we’ll only use six specific ones (the same ones used on huelandsspoor.nl). And then we set a Session value:
Session.set("lightsColor", lights[0]);
This is the same session value that we use in the header to change the colour of the colour wheel.
Round trip complete! We now have a colour wheel that can be used to change the colours of our office lights, and when we do change them, anyone else on the site will see the same colour nearly instantaneously.
But what if we don’t support input type color?
At this point, input type=“color” is pretty bleeding edge. Only Chrome and Opera implement it, so we need to devise some sort of fallback for other browsers like Safari and Firefox. To do that, we built an SVG color picker from scratch. To determine whether the browser has support for our radical input, we use this code lifted from a Stack Overflow question:
var supportsInputTypeColor = (function() {
var i = document.createElement("input");
i.setAttribute("type", "color");
return i.type !== "text";
})();
It turns out that browsers that don’t support a particular value for the type attribute just end up reverting to text, so we can check for that. Then we just set a Meteor Session value and render the color picker if it’s set:
Session.setDefault("supportsInputTypeColor", supportsInputTypeColor);
Template.colorpicker.enable = function() {
return !Session.get("supportsInputTypeColor");
}
Why do this?
Ever since we relaunched q42.nl on Meteor we felt that it was a bit of a waste to have access to such a cool realtime platform but only use it to serve what is essentially a static site. Adding integration with our office lights feels like some kind of validation for using the platform. But the real reason is that letting people control our office lights simply by visiting our site is pretty awesome! And that’s actually enough reason, to be honest.
Remember, the source code for our website is hosted on Github so you can check out all the details for yourself there.
Oh, and we also relaunched q42.com on Meteor as well - now you can read all about us in English without having to use Google Translate. Enjoy!
Check out our Engineering Blog for more in-depth articles on pragmatic code for happy users!