iBeacons and Hue Lights Tutorial Part 2: Implementing a Node.JS Server
This is post 2 of 4 in the series “iBeacons and Hue Lights Tutorial Series”
- iBeacons and Hue Lights Tutorial Part 1: Introducing The Beacon Solution
- iBeacons and Hue Lights Tutorial Part 2: Implementing a Node.JS Server
- iBeacons And Hue Lights Tutorial Part 3: Integrating Node.JS with iOS
- iBeacons And Hue Lights Tutorial Part 4: Typhoon Dependency Injection Framework
A small band of Gorillas spent 3 weeks creating an iBeacons and Hue Lights project using different technologies. In our first post, we introduced our project and a tutorial on implementing Beacon SDK and integrating with iOS devices through Bluetooth. In this post, we will discuss how to manage and handle a Philips Hue Bridge with Hue Lights by implementing a Node.JS Server.
- Node.JS Server vs. Native iOS Solution
- Back End Architecture
- How To Setup the Node.JS Server and Third Party Libraries to Manage the Lights
- How To Setup a New User In the Philips Hue Bridge
- How To Manage the Lights – Sending Messages to the Bridge
- Conclusions
Philips Hue Lights
Philips provides great documentation on how to manage lights and other devices through APIs using different solutions like Native iOS, Native Android, Node.JS, Arduino, C, C#, Java, Ruby, and others. Visit Philips Hue developers site for more information about the Hue developer program.
Why a Node.JS Server Over Philips Hue iOS SDK?
Philips provides an SDK in Objective-C for iOS, but the requirements of our project needed a different perspective. Node.JS presented an easy solution to our problem:
- Project requirements: a transparent connection and management of the lights.
- A Node.JS Server provides a single connection to the lights for all iOS App users.
- A Nose.JS Server makes it easier to manage the Bridge.
- The Philips Hue Bridge requires the user login in the Bridge in a pairing process for security reasons. We don’t want unauthorized users sending messages to the bridge, so we created a single connection to fix that login/pairing issue.
Back End Architecture
Using the Express Package, we created an endpoint on the server to interact with our iOS App. With the Node.JS libraries for Philips Hue, we can manage the messages sent to the Hue Bridge.
How To Setup the Node.JS Server and Third Party Libraries to Manage the Lights
Install the Node.JS Server (click here for instructions), then install an npm site. Learn how to install the modules here.
To setup the out Node.JS server we will need 4 different modules:
- Huejay: Huejay is a Node.JS client library for the Philips Hue home lighting system.
- Express: Express is a Web Framework that is really easy to use.
- Body-parser: The body-parser object exposes various factories to create middlewares. All middlewares will populate the req.body property with the parsed body when either the Content-Type request header matches the type option, there is an empty object ({}), the Content-Type was not matched, or an error occurred.
- Hue-module: This is a Node.JS client library for the Philips Hue.
Open the terminal App and go the folder where you will create the project server files.
First, create a Package.JSON file to keep modules in order. In the terminal, create that file through Vim, Atom, or another editor. The package file needs a name and version inside a JSON structure.
Save the file. Now we are going to add our modules to the package file using the command npm install –save {module name}
npm install –save huejay
npm install –save hue-module
npm install –save express
npm install –save body-parser
If you open the package.JSON file, you will see all of our dependencies.
Now we are going to setup a User for the Philips Hue Bridge.
{ "name": "ibeacon-hueligths-server", "version": "1.0.0", "author": { "name": "Jorge Mendoza" }, "dependencies": { "body-parser": "^1.17.2", "express": "^4.15.4", "hue-module": "^0.1.2", "huejay": "^1.7.0" } }
How To Setup a New User In the Philips Hue Bridge
We are going to use a Hue-module library to setup a User in the bridge and get a token username – this token is necessary for all the transactions to the Bridge.
Connect the Bridge and the lights as instructed in the Philips documentation of the product.
Before creating a User, we need to know the IP address of the Bridge. For this process, we are going to use the HueJay Module.
1. Create a Node.JS file using Atom or another editor. For our example, I will call the file: HueBridgeUser.JS
2. In the new file, create a Huejay constance.
3. Using the Huejay instance, call the discover() function as shown in the code below. We are going to obtain the IP address of the Bridge through the console.
4. Run the code and copy the IP address.
- To run the services, go to the terminal and type: node {and the name of the file with the extension}.
- For our case, this is node HueBridgeUser.JS.
let huejay = require('huejay'); huejay.discover() .then(bridges => { for (let bridge of bridges) { console.log(`Hue bridge Discover `); console.log(`Id: ${bridge.id}, IP: ${bridge.ip}`); } }) .catch(error => { console.log(`An error occurred: ${error.message}`); });
5. Create a new variable to hold the IP address and create a constance for the Hue-module library.
6. Copy the code below, run the code, and copy the UserName Token printed in the console.
7. That function loads the Bridge and gets a username from the bridge, and printed in the console.
var hue = require('hue-module'); var hueHost = "192.168.1.87" var loadBridge = function(host) { hue.load({ "host" : host }); hue.getUsername(function(err, result) { if (err) { console.log(err); return; } console.log(`Hue bridge UserName: ${result.username}`); }); }; loadBridge(hueHost)
How To Manage the Lights – Sending Messages to the Bridge
For this part, we need the Token of the username we got from the hue.getusername() function.
We are going to create functions for changing the states of the Lamp like turning it on and off, changing color, or setting an Alert effect.
Get the light’s information:
To get access to the lights (or others devices connected to the bridge) we need to create an instance of HueJay Client.
- Create a new JS File. We are going to call this file: ibeacon-huelights-service.JS.
- Create an instance of Huejay.Client. Set the IP address, the port (80 by default), the username (token), and the timeout.
let huejay = require('huejay'); let client = new huejay.Client({ host: '123.0.12.34', port: 80, // Optional username: 'bridgeusername', timeout: 15000, // Optional, timeout in milliseconds (15000 is the default) });
3. Using the Huejay client.bridge.get method, we will return a Bridge object, which can be used for reading and saving configuration. The code below prints the Bridge information. Copy the code and run the file.
client.bridge.get() .then(bridge => { console.log(`Retrieved bridge ${bridge.name}`); console.log(' Id:', bridge.id); console.log(' Model Id:', bridge.modelId); console.log(' Model Name:', bridge.model.name); });
4. Check the console and look at all the information.
Check this information.
Now we are getting all the lights connected to the Bridge.
Huejay client.lights.getAll will return a list of all registered lights on the bridge. Like client.lights.getNew, the result from the completed Promise will be an array of Light objects.
Copy the code below in our file and run the service again.
client.lights.getAll() .then(lights => { for (let light of lights) { console.log(`Light [${light.id}]: ${light.name}`); console.log(` Type: ${light.type}`); console.log(` Unique ID: ${light.uniqueId}`); console.log(` Manufacturer: ${light.manufacturer}`); console.log(` Model Id: ${light.modelId}`); console.log(' Model:'); console.log(` Id: ${light.model.id}`); console.log(` Manufacturer: ${light.model.manufacturer}`); console.log(` Name: ${light.model.name}`); console.log(` Type: ${light.model.type}`); console.log(` Color Gamut: ${light.model.colorGamut}`); console.log(` Friends of Hue: ${light.model.friendsOfHue}`); console.log(` Software Version: ${light.softwareVersion}`); console.log(' State:'); console.log(` On: ${light.on}`); console.log(` Reachable: ${light.reachable}`); console.log(` Brightness: ${light.brightness}`); console.log(` Color mode: ${light.colorMode}`); console.log(` Hue: ${light.hue}`); console.log(` Saturation: ${light.saturation}`); console.log(` X/Y: ${light.xy[0]}, ${light.xy[1]}`); console.log(` Color Temp: ${light.colorTemp}`); console.log(` Alert: ${light.alert}`); console.log(` Effect: ${light.effect}`); console.log(); } });
The console will print all the information about the lights registered in the Bridge.
Playing with the lights
After retrieving a Light object through previous commands, you can configure the light and save its attributes and states. This allows you to change a light name, color, effect, and so on. You can set various properties on a Light object, and save them via client.lights.save.
The client will only send updated values to the Philips Hue bridge. Sending all configurable attributes and states can affect bridge and light performance.
To save a Light, pass a Light object to client.lights.save. The light is returned after saving for convenient chaining.
Thanks to the function client.lights.getall(), we obtain the light’s ID that is registered in the bridge. Using the same client, we could send messages to a specific light and change the attributes.
In the next example code, the property light.on is set to On. That will be “turn on the light” and if we set it to “off” then it will do the opposite.
Next, we need to save our light property in line:
return client.lights.save (light); client.lights.getById(4) .then(light => { console.log('Found light:'); console.log(` Light [${light.id}]: ${light.name}`); light.brightness = brightness; light.on = true; return client.lights.save(light); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); });
Change the Brightness and Color of the Lamp. Play with the Brightness properties.
client.lights.getById(4) .then(light => { light.brightness = brightness; light.hue = 65008 return client.lights.save(light); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); });
Notice that color is changed through the light.hue property, but this property doesn’t accept RBG, or other color designation. The documentation from Philips says: The hue to set the light color, representing a color from a Range: 0 – 65535 (which represents 0-360 degrees). Find an explanation here.
That doesn’t explain much, but this is okay for the moment. There is another way to set the color that will be explained in future steps.
Now, we are going to create functions to change the lamp’s state.
turnOnLight Function: Receive 2 parameters; the hueColor and the brightness level.
function turnOnLight (hueColor, brightness) { client.lights.getById(ligthId) .then(light => { console.log('Function turnOnLight:'); console.log(` Light [${light.id}]: ${light.name}`); light.brightness = brightness; light.on = true light.hue = hueColor return client.lights.save(light); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); }); }
setLightWithPulseEffect Function: This function is set to the Alert property. The “lselect” value will create a Pulse Effect in the lamp for 30 seconds.
function setLightWithPulseEffect (hueColor) { client.lights.getById(ligthId) .then(light => { console.log('Function setLightWithPulseEffect: '); console.log(` Light [${light.id}]: ${light.name}`); light.on = true; light.hue = hueColor light.alert = "lselect" return client.lights.save(light); }) .then(light => { console.log(`Updated light [${light.id}]`); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); }); }
stopPulseEffect function: Stop the Pulse Effect in the lamp by setting the Alert property value to “none” and assign a color to the lamp.
function stopPulseEffect (hueColor) { client.lights.getById(ligthId) .then(light => { console.log('Function stopPulseEffect:'); console.log(` Light [${light.id}]: ${light.name}`); light.on = true; light.hue = hueColor light.alert = "none" return client.lights.save(light); }) .then(light => { console.log(`Updated light [${light.id}]`); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); }); }
turnOffLight function: Turn off the lamp by assigning the value: false, to the On property.
function turnOffLight() { client.lights.getById(ligthId) .then(light => { console.log('Function turnOffLight:'); console.log(` Light [${light.id}]: ${light.name}`); light.on = false return client.lights.save(light); }) .then(light => { console.log(`Updated light [${light.id}]`); }) .catch(error => { console.log('Could not find light'); console.log(error.stack); }); }
Adding the Endpoints to our Node.JS Server
Express.JS
Through Express.JS, we are going to create endpoints receiving JSON formatted parameters to communicate with our HueLights functionality.
1. We need to setup express and bodyParser into our ibeacon-huelights-service.JS file.
var express = require('express'); var bodyParser = require('body-parser')
2. Create an instance of express and set what kind of body it will use.
//expressServer var app = express() app.use(bodyParser.json()) app.use(bodyParser.urlencoded({extended: false})) app.listen(3000)
3. Start to create the endpoints.
Always check the parameters. If we are missing something, the response status will be 400. This will send back 400 to represent a bad request.
If all the parameters are fine, we need to identify the turnOnLight function as sending the right parameters.
Post turnOnLight
app.post('/turnOnLight', function(req, res) { console.log(`Hue Xcolor: ${req.body.hueColor}`); console.log(`Hue Brightness: ${req.body.hueBrightness}`); if(!req.body.hueColor || !req.body.hueBrightness) { res.status(400).send("400 Bad Request") } turnOnLight(req.body.hueColor, req.body.hueBrightness) res.status(200).end() })
Check the post to our server using postMan.
If everything is okay, we will do the same with the other functions. Create endPoints to call it.
Post turnOnLightWithPulseEffect
app.post('/turnOnLightWithPulseEffect', function(req, res) { console.log(`HueColor: ${req.body.hueColor}`); if(!req.body.hueColor) { res.status(400).send("400 Bad Request") } setLightWithPulseEffect(req.body.hueColor) res.status(200).end() })
POST stopPulseEffectWithColor
app.post('/stopPulseEffectWithColor', function(req, res) { console.log(`HueColor: ${req.body.hueColor}`); if(!req.body.hueColor) { res.status(400).send("400 Bad Request") } stopPulseEffect(req.body.hueColor) res.status(200).end() })
POST turnOffLight
app.post('/turnOffLight', function(req, res) { console.log('Turn Off the Light'); turnOffLight(req.body.hueColor) res.status(200).end() })
Conclusion
Implementing a Node.JS Server makes interaction with the Philips Hue Bridge simple and easy.
A Node.JS Server fixes our problem with users logging into the Bridge using a single sign-in to the Bridge.
Setting up an express server and all the other modules may have more steps than using the Native Philips Hue SDK. However, it is not complex and is very easy to implement.
We increased the security in the app because only the server can sign into the Bridge rather than individual Users.
In the next part of this series, we will demonstrate Hue Lights integration for Node.JS and our iOS App.