← archive

Philips Hue GUI

Cover image

This week's assignment was to make a web interface for a connected device. I considered building on top of my previous WiFi controlled Servo and tweaking it to make HTTP requests and interfacing with the ESP8266 as the client, but for the purposes of time I decided to work on making a Philip Hue's interface as demonstrated in class.

Set up

It was kind of tricky to get access to a Philip Hues Bridge. The ER only had one available and every time I went to work on it, it was already checked out. I finally caught a classmate using it and joined in.

Connecting with the bridge wasn't too hard. I followed the Philip's Hue developer guide to get started. The only issue I had was in the API documentation they led the url with https://. When I entered that into the debug tool, I would receive an error 0. However, leading the url with http:// had no problems.

Goal

My goal for the project was to try to tie several API's together. An idea I had was to use a location/ weather API so that the Hue would change its color to lighting conditions around the world. I found that Open Weather had an api that could provide help me out with this. While I worked on this when the Hue Bridge was connected, I decided that it would be better to simply get the Hue working this week, and in the future I could revisit this.

For a simpler interface for the Hue, I wanted to make a color picker to set the color as opposed to using sliders. I decided that the background should change color to the Hue light, and to show the color information on the screen.

Process

Rather than create my own color picker, I searched for one that could be used as a jumping of point for my interface. I found an npm package called Iro,js that looked great and simple to use. Essentially when you change a color, a color event is called. With the UI elements found, I had to create the xml requests to the bridge.

Making the xml requests is really simple. While I am happy to use different libraries, I'm conscious of bloat. While I was looking for how to generate XML requests via javascript, many people instructed to use JQuery, but I discovered it is possible with vanilla js.

Here is the code for the xml requests:

var xhr=new XMLHttpRequest();   // xml object 
xhr.open('PUT','<Bridge IP>/api/<user name>/lights/4/state/');  // type of request
xhr.send(colorToSend); // body of request

While sending the request was straightforward to get running, formatting the body of the request was a bit tricky while interfacing with a color palette in addition to the color spaces that the Hue uses - HS (But a weird one ~deg*182), CIE color coordinates, and color temperature. Iro.js returns color as RGB, HEX, or HSL. I found that somebody already solved this and shared a function that creates an xy pair based on an RGB value. Thanks u/Croques

function getXY(red,green,blue){

if (red > 0.04045){
red = Math.pow((red + 0.055) / (1.0 + 0.055), 2.4);
}
else red = (red / 12.92);

 if (green > 0.04045){
green = Math.pow((green + 0.055) / (1.0 + 0.055), 2.4);
}
else green = (green / 12.92);

if (blue > 0.04045){
blue = Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4);
}
else blue = (blue / 12.92);

var X = red * 0.664511 + green * 0.154324 + blue * 0.162028;
var Y = red * 0.283881 + green * 0.668433 + blue * 0.047685;
var Z = red * 0.000088 + green * 0.072310 + blue * 0.986039;
var x = X / (X + Y + Z);
var y = Y / (X + Y + Z);
return new Array(x,y);

}

The full code that is called when a color is selected:

colorPicker.on("color:change", function (color) {
let xy=[];
let rgb=color.rgbString.slice(4,color.rgbString.length-1)
let rgbArray=rgb.split(',');
let newColorXY=getXY(rgbArray[0],rgbArray[1],rgbArray[2]);
console.log(rgb, newColorXY);
let colorToSend='{"xy":['+String(newColorXY[0])+','+String(newColorXY[1])+']}';
body.setAt
values.innerHTML = ["hex: " + color.hexString,
"rgb: " + color.rgbString,
"hsl: " + color.hslString,
].join("<br>");

var cssText = colorPicker.stylesheet.cssText;
css.innerHTML = cssText.replace(/([\n\t])/g, function ($1) {
    switch ($1) {
        case "\n": return "<br>";
        case "\t": return "&nbsp;&nbsp;";
            }
        }

    );

    var xhr=new XMLHttpRequest();
    xhr.open('PUT','http://128.122.151.177/api/9hxMZkjVhURlXdATSgyYhdz2cuHOXjJCBZqVmYnL/lights/4/state/');
    xhr.send(colorToSend);

    }

);