monotux.tech

EMQX Primer

MQTT, Primer, EMQX

I’ve been meaning to move my MQTT broker to my Home Assistant machine, and while doing that I started experimenting with a new broker, EMQX. Below is a short introduction and HOWTO where I reproduce my older Mosquitto setup.

My old setup was managed by Ansible, running on a SBC in my home network. Most of it is centered around Home Assistant so I installed EMQX as an addon in Home Assistant and started experimenting.

Table of Contents

why, though? #

I was just curious! Also, I’ve found the builtin web ui to be pretty decent to use – but the best feature is probably the builtin diagnostics tools.

The log trace was really helpful when troubleshooting ACLs, and having a builtin client is also really handy. I can do both of these using the standard Mosquitto tooling, though.

Trace creation view

Access control #

Authentication (“who is it?”) and authorization (“what are they allowed to do?”) are optional with EMQX (!) but it is highly recommended to setup this before doing anything more.

Authentication #

  1. On the web ui, go to Access Control → Authentication
  2. Create a backend, for this I’ve used “Password-based” with “Built-in Database” to avoid external dependencies. I went with the defaults for all options.
  3. Now you can create traditional users (with passwords)

Authorization #

  1. On the web ui go to Access Control → Authorization
  2. Create a backend, I’ve used “File” and all defaults.
  3. Now you can setup ACL rules for your users and topics!

Deny by default #

One thing to notice here is that the default ACL is setup to permit anyone access to any topic! At the end of the ACL (found under Access Control → Authorization → Backend → Settings) you can find this comment:

%% NOTE! when deploy in production:
%% - Change the last rule to `{deny, all}.`
%% - Set config `authorization.no_match = deny`

In my case I’m running this as a Home Assistant addon, so I don’t have (easy) access to the configuration file – luckily we can inject configuration as environment variables!

In Home Assistant → Settings → Addons → EMQX → Settings → env_vars:

- name: EMQX_AUTHORIZATION__NO_MATCH
  value: deny

Restart the addon to apply.

ACLs #

The ACLs for the file backend are done as Erlang tuples, which at first glance looks complicated but isn’t (just don’t miss the period at the end of each expression!).

%% Default ACL entries
{allow, {username, {re, "^dashboard$"}}, subscribe, ["$SYS/#"]}.

{allow, {ipaddr, "127.0.0.1"}, all, ["$SYS/#", "#"]}.

{deny, all, subscribe, ["$SYS/#", {eq, "#"}, {eq, "+/#"}]}.

%%%% My custom ACLs below

%% homeassistant is allowed read-only access to a few topics
{allow, {username, {re, "^homeassistant$"}}, subscribe,
 ["owntracks/#", "rtl_433/#", "cheerlightsRGB/#"]}.

%% You can use and/or conditions like so
{allow, {'or', [{username, {re, "^zigbee2mqtt$"}},
                {username, {re, "^homeassistant$"}}]},
 all, ["home/#", "homeassistant/#", "zigbee2mqtt/#"]}.

%% homeassistant is allowed read/write to a tasmota topics in addition to
%% zigbee2mqtt/# and homeassistant/#
{allow, {username, {re, "^homeassistant$"}}, all,
 ["tele/#", "cmnd/#", "stat/#", "tasmota/discovery/#"]}.

%% Regexp to allow tasmota devices (each with their own username) to
%% read/write on their own topics, based of their usernames
{allow, {username, {re, "^tasmota_"}}, all,
 ["tele/${username}/#", "cmnd/${username}/#", "stat/${username}/#",
  "tasmota/discovery/#"]}.

%%%% default, deny anything else
{deny, all}.

More information in the documentation.

Bridge setup #

Setting up bridges in EMQX is slightly more involved than in Mosquitto, but in return does offers more flexibility in the action stage. You essentially need to setup a Connector to the other broker, and then a republishing rule.

In the example below I’m setting up a MQTT bridge from mqtt.cheerlights.com to my local broker for the top level topic cheerlightRGB.

  1. Setup Integration → Connector (I’ve used MQTTv5 due to reasons)

    Connector setup view
  2. Create rule with connector as data input, remove the default placeholder.

    Input rule view

    The SQL should look something like this:

    SELECT
      payload
    FROM
      "$bridges/mqtt:cheerlightsRGB"
    
  3. Create an Action Output of type Republish. Topic is where the received message will be republished on your local broker, and for payload you can just insert ${payload} to just republish the content as-is. Here’s a link to the documentation.

    Republish view

After this is setup, any messages published at mqtt.cheerlights.com on topic cheerlightsRGB will be republished on our broker, as-is, on the same topic.