How I control my Hue lights on my Mac with BitBar

I recently installed some Hue lights in my home. I can control them with HomeKit on my iPhone or with some physical switches. 
But I needed to control them on my Mac too.

As HomeKit is not (yet) available on macOS, I had to search for an alternative.

I recently discovered a nice tool named BitBar (https://getbitbar.com/). It’s a tool that allows you to add almost what you want in the macOS menu bar.
It uses scripts to create a menu and populate it.

I also know that it is possible to control Philips Hue lights through a REST API (https://www.developers.meethue.com/).

So the idea to use both came to my mind.
I will explain you how I combined these technologies to control my lights directly and easily from the menu bar of my Mac

My current configuration

The Hue command line tool

The first step was to create a command line tool that could trigger an action on my Hue bridge.

The use of this tool is as simple as

./HueCommandLine OfficeON

and

./HueCommandLine OfficeOFF

The tool uses a config file to translate the parameter (OfficeON, OfficeOFF in the examples above) into actions to send to the Hue bridge. This file must be named settings.plist and put in the same directory as the HueCommandLine tool.

The content of settings.plist

Here is an example of the file:

<?xml version=”1.0" encoding=”UTF-8"?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0">
<array>
<dict>
<key>key</key>
<string>OfficeOff</string>
<key>calls</key>
<array>
<dict>
<key>host</key>
<string>192.168.0.10</string>
<key>userName</key>
<string>98B7jfku9NJ9-Bmltd9bhJNIyhOIQbp075EPPmke</string>
<key>address</key>
<string>/groups/3/action</string>
<key>httpMethod</key>
<string>PUT</string>
<key>httpBody</key>
<string>{“on”: false}</string>
</dict>
<dict>
<key>host</key>
<string>192.168.0.10</string>
<key>userName</key>
<string>98B7jfku9NJ9-Bmltd9bhJNIyhOIQbp075EPPmke</string>
<key>address</key>
<string>/sensors/3/state</string>
<key>httpMethod</key>
<string>PUT</string>
<key>httpBody</key>
<string>{“status”: 0}</string>
</dict>
</array>
</dict>
</array>
</plist>

This example file contains one action, named OfficeOff.
This action, when used as the parameter of the HueCommandLine tool, will trigger 2 REST calls on the Hue bridge:

So the structure of the file is the following :

  • First level is an array of actions.
  • each action contains:
    - a key: this is the value used as the parameter of the HueCommandLine tool;
    - an array of calls: these are the REST calls that will be triggered by the HueCommandLine tool when the key is passed to it
  • each call contains:
    - host: the ip address or domain name of the Hue bridge on which to make the REST call;
    - userName: the userName known by the Hue bridge that has correct access rights to call the REST api (see https://www.developers.meethue.com/ for more information);
    - address: the REST api address;
    - httpMethod: the http method of the REST api call;
    - httpBody: the body sent to the REST api

The host and userName have been added in the calls level instead of being added in the action level to allow more flexibility.

So, basically, you can add as much actions as you want, and in each action, you can add as much calls as you want.

The HueCommandLine tool is written in Swift 3.1 and can be downloaded here


The BitBar script

The BitBar app uses scripts to add and populate a new menu in the menu bar of macOS.

Basically, to create a new menu, you create a new shell script in the BitBar plugin folder. The menu title (or image) and the menu content will be generated with the output of the script.

The name of the script can contain information to let BitBar know when to refresh it, for example the following name

hue.1d.sh

means that the menu will be automatically refreshed every day.
A detailed information about how to write a script can be found here.

In the case of the Hue plugin, I created a new script named hue.1d.sh (no need to refresh it too much, once a day is really enough).
This script is written in Swift. I used the following shebang header to let BitBar know that it must use the Swift executable to run the script:

#!/usr/bin/swift

The content of the script is really simple:

#!/usr/bin/swift
let dir = "/Users/mj/BitBar"
print("💡")
print("---")
print("Home Hue lights")
print("Select an action in the sub menus")
print("---")
print("Office")
print("--Low|bash=\"\(dir)/hue/run.sh\" param1=OfficeLow terminal=false")
print("--High|bash=\"\(dir)/hue/run.sh\" param1=OfficeHigh terminal=false")
print("--Night|bash=\"\(dir)/hue/run.sh\" param1=OfficeNightLight terminal=false")
print("-- ⎯⎯⎯⎯⎯")
print("--Off|bash=\"\(dir)/hue/run.sh\" param1=OfficeOff terminal=false")
print("---")
print("Night lights")
print("--On|bash=\"\(dir)/hue/run.sh\" param1=NightLightOn terminal=false")
print("-- ⎯⎯⎯⎯⎯")
print("--Off|bash=\"\(dir)/hue/run.sh\" param1=NightLightOff terminal=false")

It just makes a lot of prints on the standard output. That’s it. My script is ready and when I put it in the BitBar plugin folder, the menu in the image at the begining of this article is shown. Thanks to BitBar !

The first print is the text that appears in the menu bar, here I choose the emoji 💡 that fits well for a menu about Hue lights 😀

The first --- print means all below it will appear in the dropdown of the menu.

Then I added a small description of the plugin:

print("Home Hue lights")
print("Select an action in the sub menus")

Then I added a separator:

print("---")

Then, this is the first sub menu, for the lights in my office:

print("Office")
print("--Low|bash=\"\(dir)/hue/run.sh\" param1=OfficeLow terminal=false")
print("--High|bash=\"\(dir)/hue/run.sh\" param1=OfficeHigh terminal=false")
print("--Night|bash=\"\(dir)/hue/run.sh\" param1=OfficeNightLight terminal=false")
print("-- ⎯⎯⎯⎯⎯")
print("--Off|bash=\"\(dir)/hue/run.sh\" param1=OfficeOff terminal=false")

Here, first is the name of the sub menu (Office), then the 4 items of the sub menu (+ the separator before the fourth item).

This is where it starts to be interesting:

  • -- means a sub menu item, the name is the text that follows (Low for the first sub item);
  • |bash= is used to create a clickable item, so when I click on the Low item, the run.sh script will be called with the parameter OfficeLow.
    terminal=false means that the run.sh script will be run without opening a terminal window.

The run.sh script content is the following:

#!/bin/bash
cd /Users/mj/BitBar/hue
./HueCommandLine $1

It just calls the HueCommandLine with the wanted parameter.

So when the Low item menu is clicked, it actually triggers a call to:

/Users/mj/BitBar/hue/HueCommandLine OfficeLow

which will turn the lights of my office on with a low brightness.

Voila, with BitBar, my HueCommandLine tool and my simple scripts, I’m now able to turn my Hue lights on or off.

The complete plugin can be downloaded here, feel free to adapt it with your Hue configuration !