MQTT

EMQX 5.x HTTP ACL server using NodeJS

In our previous post EMQX 5.x HTTP password authentication server minimal example using NodeJS we provided a complete example of how to implement EMQX HTTP authentication.

This post provides an extension to our previous HTTP auth by adding a Koa router (i.e. a HTTP endpoint / URL) to provide ACL authentication, i.e. allow or deny topic level access with custom logic.

router.post('/emqx/acl', async ctx => {
    const body = ctx.request.body;
    console.log(body)
    // TODO: This example always returns true
    // You need to implement your authentication logic
    ctx.body = {
        result: "allow",
    };
});

Add that code before app.use(router.routes()); in the script from EMQX 5.x HTTP password authentication server minimal example using NodeJS.

My recommended Authorization configuration body which you can set in the EMQX dashboard is

{
  "action": "${action}",
  "client_id": "${clientid}",
  "ip": "${peerhost}",
  "topic": "${topic}",
  "username": "${username}"
}

 

Posted by Uli Köhler in EMQX, MQTT, NodeJS

EMQX 5.x HTTP password authentication server using NodeJS

Note: If you also want to implement ACL authorization via HTTP, see our extension to this example: EMQX 5.x HTTP ACL server using NodeJS

This server implements a minimal HTTP authentication server. In this minimal example, it will always allow authentication – you need to implement your own logic to verify passwords. Note: This server is written for EMQX versionx5.0 and will not work for EMQX 4.x without modification. See the official documentation on EMQX 5.x HTTP auth for more information.

#!/usr/bin/env node
const router = require('koa-router')();
const koaBody = require('koa-body');
const Koa = require('koa');
const app = new Koa();

app.use(koaBody());

router.post('/emqx/auth', async ctx => {
    const body = ctx.request.body;
    const username = body.username;
    const password = body.password;
    // TODO: This example always returns "allow"
    // You need to implement your authentication logic
    ctx.body = {
        result: "allow",
        is_superuser: false
    };
});

app.use(router.routes());

if (!module.parent) app.listen(19261);

This script is based on our previous post Minimal Koa.JS example with Router & Body parser, hence you can install the dependencies using

npm i --save koa koa-router koa-body

The request body config which you can set in the EMQX dashboard is

{
  "client_id": "${clientid}",
  "password": "${password}",
  "username": "${username}"
}

 

Posted by Uli Köhler in EMQX, MQTT, NodeJS

How to install mosquitto_sub on Ubuntu 22.04

You can install the mosquitto client (mosquitto_sub) by running

sudo apt -y install mosquitto-clients

 

Posted by Uli Köhler in Linux, MQTT

How to load & start EMQX plugin using emqx_ctl

You can easily load (& start) an EMQX plugin such as emqx_auth_mnesia

./bin/emqx_ctl plugins load emqx_auth_mnesia

If you are using docker-compose and your container is named emqx, you can use

docker-compose exec emqx ./bin/emqx_ctl plugins load emqx_auth_mnesia

After running this command, the plugin will show up as Running in the dashboard:

Posted by Uli Köhler in EMQX, MQTT

How to change EMQX admin password

Changing the password is as simple as

./bin/emqx_ctl admins passwd admin "[new password]"

If you are using docker-compose and your container is named emqx, you can use

docker-compose exec ./bin/emqx_ctl admins passwd admin "[new password]"
Posted by Uli Köhler in EMQX, MQTT

What is the EMQX default username & password

The default credentials for EMQX are:

  • Username: admin
  • Password:public

It should go without saying that you must change the password!

Posted by Uli Köhler in EMQX, MQTT

What is the EMQX default password for the ‘admin’ account?

The default password for the EMQX admin account is publicChange it as soon as possible 🙂

Posted by Uli Köhler in EMQX, MQTT

How to run emqx_ctl for docker-compose-based EMQX setups

You can simply run emqx_ctl using the following command:

docker-compose exec emqx ./bin/emqx_ctl [command]

where emqx is the name of the container to run emqx_ctl in.

Example:

docker-compose exec emqx ./bin/emqx_ctl status

 

Posted by Uli Köhler in EMQX, MQTT

How to fix docker emqx_ctl Node ’[email protected]’ not responding to pings.

Problem:

When trying to run emqx_ctl in a dockerized emqx setup using a command like

docker-compose exec emqx ./bin/emqx status

you see an error message like

Node '[email protected]' not responding to pings.
/opt/emqx/bin/emqx: line 41: die: command not found

Solution:

The problem here is that emqx_ctl is trying to connect to the IP address for node1.emqx.mydomain.com but that IP address does not point to the IP address for the docker container (maybe it’s the public IP address for your server?)

The solution here is to create a network alias within docker/docker-compose so that the Docker DNS system resolves node1.emqx.mydomain.com to the internal IP address of the container.

For example, in docker-compose, you can create your network using

networks:
  emqx:
    driver: bridge

and then configure the alias for the container using

services:
  emqx:
    image: emqx:4.4.4
    environment:
      - "EMQX_NAME=emqx"
      - "EMQX_HOST=node1.emqx.mydomain.com"
      - "EMQX_LOADED_PLUGINS=emqx_recon,emqx_retainer,emqx_management,emqx_dashboard"
    ports:
      - 18083:18083
      - 1883:1883
    volumes:
      - ./emqx_data:/opt/emqx/data
      - ./emqx_log:/opt/emqx/log
    networks:
      emqx:
        aliases:
          - "node1.emqx.mydomain.com"

 

 

Posted by Uli Köhler in Container, Docker, EMQX, MQTT

How to link Paho MQTT C++ binding using CMake

target_link_libraries(myexecutable paho-mqttpp3 paho-mqtt3as ssl crypto)

 

Posted by Uli Köhler in C/C++, MQTT

How to fix Tasmota Upload Failed: Upload buffer miscompare on Nous A1T

Problem:

When trying to do a Tasmota firmware upgrade on the Nous A1T, you see this error message:

Upload Failed
Upload buffer miscompare


Solution:

This issue occurs because in the default configuration there is not enough flash space to flash the firmware.
However, this is easy to fix: First, flash the tasmota-minimal.bin.gz firmware, then flash the regular tasmota.bin.gz firmware using the webinterface of the minimal firmware.

Download link for the minimal firmware
Download link for the regular firmware

After that, upgrades will work just fine.

Posted by Uli Köhler in Home-Assistant, MQTT

How to fix Tasmota MQT: Connect failed to …, rc 5

Problem:

On the Tasmota console, you see an error message like

17:56:11.326 MQT: Connect failed to 10.19.50.10:1883, rc 5. Retry in 50 sec

Solution:

Your MQTT username/password is wrong. Check if they match what you have configured in your server in the Tasmota MQTT configuration page.

Posted by Uli Köhler in MQTT

NodeJS MQTT minimal subscribe example with JSON messages

const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://user:[email protected]')

client.on('connect', () => {
  client.subscribe('mytopic');
})

client.on('message', (topic, message) => {
  console.log(topic, JSON.parse(message))
})

If required, you can install the mqtt library using

npm i --save mqtt

 

Posted by Uli Köhler in Javascript, MQTT, NodeJS

NodeJS MQTT minimal subscribe example

Also see: NodeJS MQTT minimal subscribe example with JSON messages

const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://user:[email protected]')

client.on('connect', () => {
  client.subscribe('mytopic');
})

client.on('message', (topic, message) => {
  console.log(topic, message)
})

If required, you can install the mqtt library using

npm i --save mqtt

 

Posted by Uli Köhler in Javascript, MQTT, NodeJS

How to set username & password in Paho-MQTT

Set username & password in Paho-MQTT using

client.username_pw_set("myusername", "aeNg8aibai0oiloo7xiad1iaju1uch")

You need to call that before calling connect()!

Example of how to connect with username & password:

client = mqtt.Client("mqtt-test") # client ID "mqtt-test"
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("myusername", "aeNg8aibai0oiloo7xiad1iaju1uch")
client.connect('127.0.0.1', 1883)
client.loop_forever()  # Start networking daemon

 

Posted by Uli Köhler in MQTT, Python

How to fix Paho-MQTT result code 5

When you see result code 5 in paho-mqtt this means Unauthorized! Typically it means you don’t have the correct username and password set.

Set username & password using

client.username_pw_set("myusername", "aeNg8aibai0oiloo7xiad1iaju1uch")

Example of how to connect with username & password:

client = mqtt.Client("mqtt-test") # client ID "mqtt-test"
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("myusername", "aeNg8aibai0oiloo7xiad1iaju1uch")
client.connect('127.0.0.1', 1883)
client.loop_forever()  # Start networking daemon

 

Posted by Uli Köhler in MQTT, Python

Python MQTT subscribe minimal example (Paho-MQTT)

#!/usr/bin/env python3
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    # This will be called once the client connects
    print(f"Connected with result code {rc}")
    # Subscribe here!
    client.subscribe("my-topic")

def on_message(client, userdata, msg):
    print(f"Message received [{msg.topic}]: {msg.payload}")

client = mqtt.Client("mqtt-test") # client ID "mqtt-test"
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("myusername", "aeNg8aibai0oiloo7xiad1iaju1uch")
client.connect('127.0.0.1', 1883)
client.loop_forever()  # Start networking daemon

 

Posted by Uli Köhler in MQTT, Python

How to fix Python ModuleNotFoundError: No module named ‘paho’

Problem:

When running your Python script, you see an error message like

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    import paho.mqtt.client as mqtt
ModuleNotFoundError: No module named 'paho'

Solution:

Install the paho-mqtt package using

pip3 install paho-mqtt

or

pip install paho-mqtt
Posted by Uli Köhler in MQTT, Python

Simple HomeAssistant docker-compose setup

First, create a directory where HomeAssistant will reside. I use /opt/homeassistant.

Create docker-compose.yml:

version: '3.5'
services:
  homeassistant:
    container_name: homeassistant
    restart: unless-stopped
    image: ghcr.io/home-assistant/home-assistant:stable
    network_mode: host
    privileged: true
    environment:
      - TZ=Europe/Berlin
    volumes:
      - ./homeassistant_config:/config
    depends_on:
      - mosquitto
  mosquitto:
    image: eclipse-mosquitto
    network_mode: host
    volumes:
      - ./mosquitto_conf:/mosquitto/config
      - ./mosquitto_data:/mosquitto/data
      - ./mosquitto_log:/mosquitto/log

Now start homeassistant so it creates the default config files:

docker-compose up

Once you see

homeassistant    | [services.d] done.

Press Ctrl+C to abort.

Now we’ll create the Mosquitto MQTT server config file in mosquitto_conf/mosquitto.conf:

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log

listener 1883
## Authentication ##
allow_anonymous false
password_file /mosquitto/config/mosquitto.passwd

Now create the mosquitto password file and fix the permissions using

touch mosquitto_conf/mosquitto.passwd
chown -R 1883:1883 mosquitto_conf

We can now start create the homeassistant mosquitto user using

docker-compose run mosquitto mosquitto_passwd -c /mosquitto/config/mosquitto.passwd homeassistant

Enter a random password that will be used for the homeassistant user

Now we can edit the homeassistant config homeassistant_config/configuration.yml. This is my config – ensure to insert the random MQTT password we used before instead of ep2ooy8di3avohn1Ahm6eegheiResh:

# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:

http:
  use_x_forwarded_for: true
  trusted_proxies:
  - 127.0.0.1
  ip_ban_enabled: true
  login_attempts_threshold: 5

mqtt:
  broker: "127.0.0.1"
  username: "homeassistant"
  password: "ep2ooy8di3avohn1Ahm6eegheiResh"

# Text to speech
tts:
  - platform: google_translate

group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

Now we can start the server using

docker-compose up

You can also use our script to generate a systemd service to autostart the docker-compose config on boot:

curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin

Now login to the web interface on port 8123 and configure your HomeAssistant!

Posted by Uli Köhler in Container, Docker, Home-Assistant, MQTT

How to fix error: invalid conversion from ‘int’ to ‘esp_mqtt_event_id_t’ on the ESP8266 or ESP32

If you see an error message like

src/main.cpp: In function 'void InitMQTT()':
/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include/esp_event_base.h:37:32: error: invalid conversion from 'int' to 'esp_mqtt_event_id_t' [-fpermissive]
 #define ESP_EVENT_ANY_ID       -1               /**< register handler for any event id */

src/main.cpp:80:44: note: in expansion of macro 'ESP_EVENT_ANY_ID'
     esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
                                            ^~~~~~~~~~~~~~~~

replace ESP_EVENT_ANY_ID by MQTT_EVENT_ANY and recompile. This will fix the issue. Using ESP_EVENT_ANY_ID was possible in an outdated version of the MQTT library.

 

Posted by Uli Köhler in Arduino, Embedded, ESP8266/ESP32, MQTT, Networking, PlatformIO