Controlling a Philips Hue light via the command line

How I made a status/presence light to show how busy I am.

September 29, 2020

Node

Philips Hue

This post has a bit of background to it. A bit like the story you see above a recipe.

If you don't want to read it - Go to the tutorial by clicking here.

I've been working from home a lot because of the COVID-19 pandemic - and a problematic... problem that arose quite quickly is that other people in my house doesn't seem to understand or know when I'm free or not.

Now don't get me wrong, it's nice to see other people and talk about the weather or a funny cat video - but when it's in the middle of a meeting or video call - sometimes they are quite important, and I don't want to be disturbed. And I definitely don't want other people waltzing into my room, especially when my webcam is pointed directly at my door...

So what did I do about it? Well... I made a sign. And put it directly at eye level on my door.

I made a sign that said basically said:

Door closed? I'm probably on a call. Please don't come in.

I don't know what it was. Was I being too polite? Did I need to remove the "please"? But even with that sign people still came into my room. Although - they we're more of a poke your head around the door and saying "Sam - are you busy?" kind of thing.

But it's still incredibly annoying. Deeply embarrassing. And quite unprofessional.

Despite many people living with a partner, children, or pets (Although I have no issues with pets as they tend to improve work calls) - it doesn't seem to be an issue with other people. I've been working from home for just over six months - and it happens to me three, four times during a bad week. Just last week was the first time I saw someone else, on a call being disrupted by someone in their household.

So obviously - I needed to do something. Something that was distracting, something in your face. So after a rant to a few other of my co-workers about someone walking in for approximately the 100th time when I was on a call including some high high ups (Thank god I had my camera off...) - a suggestion about getting a status or presence light outside my office was put towards me.

Now I'm the kind of guy who likes to do something interesting now and again, and so I thought I'd turn a Philips Hue Go lamp into a status light. A bit like a traffic light.

Green? Come on in! Red? Leave me alone!

So I set out over a weekend putting something together that I can easily and quickly change the colour of a lamp outside of my office. I did try and integrate it with some of the other apps I use at work, but I'll get to that later.

For now, here's how I managed to easily control lamps using my command line and the Philips Hue API.

Setting up the light

I already had a Philips Hue Go lamp which I didn't really use all that much. Although any Philips Hue light would work for what I'm doing - I even contemplated replacing the bulb in a lamp that was already there - but the only bulb I had was a bayonet - and the lamp was a screw one...

Anywho - Once I found an appropriate place to put it, I was ready to start working on the API. I kept the lamp with me while I was working on the API so I wouldn't have to run back and forth to see if it's working or not.

Controlling lights via the API

Accessing the API

Philips Hue has an API which allows you to send requests to in order to control lights or even your whole smart lights setup.

Accessing this API is fairly straightforward. You first need to find the internal IP address of your Hue bridge. In my case, this was 192.168.1.2.

Hue has quite a really cool and easy debugging/sandbox/playground tool - this can be accessed by visiting <BRIDGE IP>/debug/clip.html.

The Philips Hue debugger tool

The first thing we need to do in order to use the API is create a username. This is randomly generated by Hue itself, but to request one, enter the URL of /api, and add a body of {"devicetype": "my_hue_app"}. Now click the POST button.

You should see an error - regarding the link button not being pressed. This is actually a really cool bit of security to stop other people controlling your lights. Well... I think it's cool anyway.

The Philips Hue debugger tool showing a response of an error message with the description of "link button not pressed"

Press the big link button on your Hue Bridge - and press POST again - you should get a different response with a username.

Keep this value - as all our requests from now on will use that as our username.

Getting light information.

Now that we have our username, we can make requests to our Hue lights! In our case, we need to get the light that I'd be using as the status light. Probably the easiest to do this is by making a request using only our username as our endpoint - /api/<USERNAME>. This will show us all kinds of information including rooms, groups, and what we're after - lights.

Screenshot of the root endpoint containing an array of lights

Each light has an ID - the key of the object. You can tell which light to use by looking at the name property of the object - in my case I had named it "Status Light".

You can confirm this is the right light by using the lights/:id endpoint - e.g. /api/<USERNAME>/lights/3. This should only show information about the light with an ID of 3.

Controlling the lights

Now we know what light ID to use - we can control it using PUT requests. We can do this by changing the state. In the debug editor, set the URL to /api/<USERNAME>/lights/<LIGHT ID>/state - set the body to {"on": false}. Press the PUT button and this will turn it off.

If the light is already off, you can change it to true, and it will switch on!

You can also control the brightness and colour of the lights - but we'll get to that later.

Writing a Node application

Yeah... I'm using Node because it's something I'm quite familiar with - and in my opinion easy to expand uppon later on down the line for things like creating an API or integrating it with other tools or services. However, you could just save all the requests to Postman and trigger them that way when needs be.

Getting started

But anywho - we can start by writing one of our commands. First install axios by running the NPM command:

npm install axios

In a index.js file - write:

const axios = require('axios');

axios.put('http://<BRIDGE IP>/api/<USERNAME>/lights/<LIGHT ID>/state', { 
  "on": false 
})

Running node index will result in the same result we had in the debugger - the light should switch off!

Command line arguments/variables

With node, you can process command lines arguments using process.argv - which effectively returns an array of your command line inputs.

We can use this to our advantage to easily changing the light without modifying our script.

For example, modify the index.js file to execute the PUT request, but instead of passing through a hardcoded bool as our "on" value - set it to be our process.argv item.

const axios = require('axios');

axios.put('http://<BRIDGE IP>/api/<USERNAME>/lights/<LIGHT ID>/state', { 
  "on": process.argv[2] == 'true'
})

So... What does process.argv[2] == 'true' do?

Effectively - the API is expecting a bool as a value - and won't expect a string. So instead, the code would send a bool that's equal to true, if the string is equal to true - otherwise, it would send the bool of false.

Simply put - it converts a string to a bool...

So, running the command node index false will turn the light off! Running the command node index true will turn it back on!

We won't necessarily use this to directly control the state of the light - we will use it instead to choose which colour to use, but it's an important step nonetheless.

Colours!

Philips Hue bulbs can change colour based on the hue (0 - 65535) and sat (0 - 254) parameter - in our case, we need it to be set to three colours - inside of index.js - create an object containing objects with the desired settings:

const colours = {
  /**
   * Do Not disturb / Unavailable
   */
  red: { hue: 65340, sat: 252 },
  /**
   * Busy
   */
  yellow: { hue: 8647, sat: 252 },
  /**
   * Available
   */
  green: { hue: 26430, sat: 252 }
}

You can also set the brightness of the bulbs by adding the bri (0 - 254) parameter.

To find the right colours - I found that the easiest way of doing so was to use the Philips Hue app on my phone to find the right one, and then make a GET request to the API to get hold of the values.

Putting everything together

Modify the PUT request body to include our colour based on the command line input:

const axios = require('axios');

axios.put('http://<BRIDGE IP>/api/<USERNAME>/lights/<LIGHT ID>/state', { 
  "on": true,
  ...colours[process.argv[2]]
})

Now that's done, your whole script should look something like this:

const axios = require('axios');

const colours = {
  /**
   * Do Not disturb / Unavailable
   */
  red: { hue: 65340, sat: 252 },
  /**
   * Busy
   */
  yellow: { hue: 8647, sat: 252 },
  /**
   * Available
   */
  green: { hue: 26430, sat: 252 }
}

axios.put('http://<BRIDGE IP>/api/<USERNAME>/lights/<LIGHT ID>/state', { 
  "on": true, 
  ...colours[process.argv[2]] 
})

You can add as many colours as you like to the colours array, and you should be able to turn the light to the required colour by running node index <COLOUR> such as node index red.

That's pretty much all there is too it at a minimum. I have a terminal open and I flick through my history using the arrow keys to toggle which colour I need.

Going further

What was originally planed for this was a node script to run every five or so seconds, retrieve my presence status from Microsoft Teams, and then select the colour based on what the value would be.

I did manage to get it somewhat working by making a request to the Graph API to get my presence, however I really struggled to get hold of the auth token. I managed to get it working for five minutes or an hour by copying the token directly to into the header in the code from the Graph Explorer - but I felt this was more effort than what it was - especially if the token lasted five minutes.

I couldn't seem to wrap my head around the Graph API in the end when it came to just authenticating my account using the API. More-so I was using a work account, for a fairly big global company, and there didn't seem to be a "private space" on Azure - and I didn't want to upset anyone for the sake of a light.

I also looked into the Microsoft Power Automate platform, and I was rather disappointed to see that things like presence or status aren't supported as an action or a trigger. I am aware that Microsoft is planning on adding more to Power Automate - but at the time of writing, It didn't seem possible without using Power Automate to call the Graph API.

Wrapping up

I did actually buy a second lamp so I can keep an eye on the status of the lamp outside (which I can't see). I put it behind my monitor so it's not showing a massive red light in my face while I'm on calls - code wise I ended up creating a zone and modified my code to use groups/<GROUP ID>/action instead.

Hopefully you've found this somewhat useful - even if it's just a gateway to using the Philips Hue API to do other fun things. I've had the light running for a few days now, everything seems to be ok - but only time will tell before I buy a giant neon sign to hang on the front of my door.