MQTT, Home Assistant, Hue emulation working together

Alexa, turn off my monitor

A number of years ago I wrote a Hue Bridge Emulator that would let you emulate light bulbs in shell script in such a way that these devices could be controlled by Alexa (and so used in routines and the like). It worked well.

But recently Amazon appear to be changing how hue bridges are detected. The big challenge appears to be it wants the server to listen on port 80. This is annoying for a number of reasons, including that it needs privileges to bind to that port, and it may conflict with a web server already on that port.

Now I also run Home Assistant which has an inbuilt Hue emulator. So I figured we can use that functionality, and let you control more things through HA which don’t normally have integrations. A simple example might be turning your screen on/off; have a “bed time” routine that turns your screen off!

We do this by configuring a light in a MQTT configuration, and have code to subscribe to topics so it sees when to turn/off or (optionally) change brightness. It will pass this data down to your program (which could be a shell script) and update MQTT status topics with any feedback from the program.

In theory this could all be done from shell scripts (eg using mqttcli commands and coprocesses and more) but I feel this approach is simpler; your program only needs to deal with stdin/stdout and doesn’t need to care about MQTT at all.

Configuring Home Assistant for MQTT

You need to set up (if you haven’t already) the MQTT integration. Running an MQTT broker and configuring the integration is beyond the scope of this doc. I, personally, use mosquitto as the broker; it comes with many Linux distributions and is easy to install.

Now we need to define a light. This is done in the mqtt: section of configuration.yaml.

After manually configuring MQTT instances the way I’m describing here you will need to tell HA to reload the configuration (e.g from Developer tools), or else restart HA totally.

There are two kinds of lights we can model:

On/Off only

mqtt:
  light:
  - name: "Test Light"
    command_topic: "mqttlight/test/command"
    state_topic: "mqttlight/test/state"

With this light it will create a new light. entity in HA (probably light.test_light). If you click the ON button it will send an “ON” message to mqttlight/test/command. The state of the button will be reported back to HA on mqttlight/test/state.

On/Off with brightness

This emulates a dimmer switch; it has on/off and brightness controls.

mqtt:
  light:
  - name: "Test Light"
    command_topic: "mqttlight/test/command"
    state_topic: "mqttlight/test/state"
    brightness_command_topic: "mqttlight/test/bright_command"
    brightness_state_topic: "mqttlight/test/bright_state"
    brightness_scale: 100

Exposing these lights to Alexa (maybe even Google?)

Once the MQTT entries have been configured you will be able to see the entity IDs in Settings / Devices / Entities. If you search for the name you set you’ll see it show in the entity list. We’ll need this.

Now in configuration.yaml we need to tell HA to expose these lights to Alexa, via the emulated_hue configuration. I normally don’t expose every device, just the ones I select:

emulated_hue:
  listen_port: 80
  expose_by_default: false
  entities: !include emulated_hue.yaml

This lets me use a new file emulated_hue.yaml to list the devices I want. You don’t need to have it as an included file, I just find it simpler this way.

The contents of this file are now the entities we want to expose.

light.test_light:
  name: "Test light with brightness"
  hidden: false

The entity ID is the one we found earlier; the name is the how we want this light to show in Alexa.

That’s it! That’s the whole emulated_hue configuration.

Changing this file requires a full HA restart.

The emulated_hue setup can be made a lot more complex; such setups are described in the documentation.

Once you’ve started it you should be able to confirm the bulb shows up by talking to the emulated hue endpoint.

e.g.

% curl http://your_ha_ip_address:80/api/v2/lights | jq .
{
  "1": {
    "state": {
      "on": true,
      "reachable": true,
      "mode": "homeautomation",
      "bri": 1
    },
    "name": "Test light with brightness",
    "uniqueid": "00:42:af:28:ad:f5:e0:ea-de",
    "manufacturername": "Home Assistant",
    "swversion": "123",
    "type": "Dimmable light",
    "modelid": "HASS123"
  }
}

(jq is a nice command that make the JSON look pretty).

You can now tell Alexa to discover new devices… and it should(!) work.

More complex emulated_hue setups are described in the HA documentation.

Communication between bridge and program

The communication patterns are asynchronous. The bridge can send commands to the program and the program can send status updates back to the bridge at any time. It’s a very simple protocol.

Commands:

There’s only one command:

LIGHT#name#on/off#brightness – Set the light named “name” to the on/off status and the brightness (0-100). The name must not contain a # since that is used as the separator. If either the on/off or brightness values are - or missing then that value should be left unchanged.

examples:

LIGHT#test##70
LIGHT#test#on#
LIGHT#test#on#70

Status Updates:

The child can send two messages to the bridge. These are best sent periodically (e.g. every 5 seconds).

LIST#name1#name2#name3 ... – This can be used to tell the bridge of the complete set of lights being controlled. For example, if you have an environment where devices may join and leave (a mobile phone, perhaps?) then this can be used as a way of refreshing the bridge’s knowledge and to stop telling clients about lights that no longer exist.

The bridge uses this list to filter out what messages seen on MQTT topics should be sent to the child program or not.

LIGHT#name#on/off#brightness – This is the current state of the light. When this is sent it will trigger an update of the relevant MQTT topics. The brightness may be left blank if it’s not relevant. If this is a new light then it will be added to the list seen from the LIST command.

e.g.

LIST#monitor
LIGHT#monitor#ON#

Importantly, the name of the light sent in the LIGHT command will be used to create the topic name. e.g. LIGHT#monitor#ON# will cause an ON message to be sent on topic mqttlight/monitor/status. This is case sensitive; “monitor” is different to “Monitor”

Running the program

Usage of ./mqttlight_bridge:
  -app string
        Application to run
  -base string
        MQTT Base (default "mqttlight")
  -debug
        Allow CLI entry to child
  -pass string
        MQTT Password
  -port int
        MQTT Port (default 1883)
  -server string
        MQTT server (default "localhost")
  -user string
        MQTT Username

The -app value is mandatory, the rest are optional. If your MQTT broker requires a username and password then these should be specified.

Examples

Two simple example scripts are provided in the source repo.

  • small-example - acts as a simple light called “test” which can be turned on or off and have the brightness changed

  • screen_on_off - an On/Off light that uses xset q to determine if the monitor is on or off, and xset dpms to change the state.

Possible gotchas

I’ve sometimes seen that changing the brightness from the Alexa app may cause two updates to be sent; the brightness value and then an ON message. This would cause two commands to be sent to the child

  LIGHT#name##brightness
  LIGHT#name#ON#

you should be careful that actions taken in response to “ON” without a brightness value should not change the brightness by mistake.

I’ve seen Home Assistant get confused; I originally created an mqtt light as on/off and then later changed it to one with brightness. HA then wasn’t sure how to present it; the GUI presented on/off and brightness slider, and the slider did change cause a brightness command to be sent… but it never reflected the actual brightness. I found I had to stop HA and edit the .storage/core.restore_state to remove the existing entry for the light before it would pick up the new definition.

Building the code.

This uses pretty simple GoLang and so should compile and work on any of the main supported platforms (Linux, MacOS, Windows, etc). You obviously need the GoLang compiler and git.

An example session might look like:

$ git clone https://github.com/sweharris/mqttlight_bridge
Cloning into 'mqttlight_bridge'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 18 (delta 2), reused 15 (delta 2), pack-reused 0
Unpacking objects: 100% (18/18), done.
$ cd mqttlight_bridge/
$ go mod tidy
$ go build

And that’s it! The go mod tidy may download modules from github and golang sites if the dependencies are not present.

You can now use the program; e.g.

./mqttlight_bridge -app ./screen_on_off -server mqtt_server

Conclusion

I have a love/hate relationship with Home Assistant. I think it’s a very useful program and my home automation is totally dependent on it. I’m just that much of a fan of its internal architecture; I would much preferred a decoupled setup. Indeed, using MQTT in this way is very decoupled; we can restart the bridge code and the child app and Home Assistant doesn’t care.

I’m annoyed that Amazon keeps changing what they expected for a “fake hue” setup, but at least Home Assistant can fill in the gap!