MQTT plugin for DeviceHive server
Additional resource:
DeviceHive Official site
DeviceHive Official playground
The devicehive-mqtt broker is a MQTT transport layer between MQTT clients and DeviceHive server.
The broker uses WebSocket sessions to communicate with DeviceHive Server and Redis server for persistence functionality.
The devicehive-mqtt broker supports QOS0 and QOS1, retain messages and last will.
The devicehive-mqtt broker is powered by Mosca MQTT broker library.
git clone https://github.com/devicehive/devicehive-mqtt.git
)The devicehive-mqtt broker can be launched directly via node, docker container or docker-compose.
With last choice is pretty easy to scale the broker horizontally.
Also you might to specify a set of configurations/environmental variables that are described in the next paragraph.
[path-to-broker-project]/src/config.json
Each configuration field can be overridden with corresponding environmental variable with “BROKER” prefix, for example:
BROKER.BROKER_PORT=6000
Prefix separator can be overridden by ENVSEPARATOR environmental variable. Example:
ENVSEPARATOR=_
BROKER_BROKER_PORT=6000
Through the “DEBUG” (debug) environment variable you are able to specify next modules loggers:
Example:
DEBUG=subscriptionmanager,websocketfactory,websocketmanager
In the folder of cloned devicehive-mqtt repo run next commands:
Install all dependencies:
npm install
Start broker:
node ./src/broker.js
Also, it’s pretty useful to enable process monitoring with PM2 module (ENABLE_PM environmental variables) and
start the broker via PM2.
Firstly, install the PM2 globally:
npm install -g pm2
Then run next command:
pm2 start ./src/broker.js
After that, you will be able to see monitoring information provided by PM2 library.
Type the next command:
pm2 monit
In the folder of cloned devicehive-mqtt repo run next commands:
Build docker container by Dockerfile located in the root folder of cloned devicehive-mqtt repo:
docker build -t <image-tag> .
Run docker container:
docker run -p <external-port:1883> --env-file <path-to-env-file> <image-tag>
Where:
path-to-env-file - path to file with mentioned environmental variables.
Do not specify BROKERPORT variable. In the container it should be 1883, as by default.
_external-port - port that will be used to achieve the broker
To run devicehive-mqtt broker with Docker Compose there is a docker-compose.yml file.
You may edit this file in case you want change environment variables or add broker instances.
To run just type the next command:
docker-compose up
The DeviceHive provides few ways for authentication:
While connecting to the MQTT broker you can specify the username and password fields.
After that you will be able to work with both common MQTT resources and DeviceHive resources.
Also, you can connect to the MQTT broker without credentials. However, you will not be able
to work with DeviceHive resources. From this state you are able to authenticate yourself with
user access token.
DeviceHive has next structure entities:
As far as the broker uses WebSocket to communicate with DeviceHive server
you can use WebSocket API to build request data objects.
To mark topic as a private the MQTT client should add it’s own clientId to the and of the topic over @
sign
To make request the MQTT client should publish to the next topic:
dh/request
To receive responses of request the MQTT client should subscribe to the response topics with request action mentioned:
dh/response/<requestAction>@<clientID>
Where requestAction ia a request action (user/get, device/delete, token/refresh etc.)
Response topic should be always private (e.g. with client ID mentioned)
The MQTT client is able to subscribe to the notification/command/command_update topic to receive notification/command/command_update push messages
dh/notification/<networkID>/<deviceTypeID>/<deviceID>/<notificationName>[@<clientID>]
dh/command/<networkID>/<deviceTypeID>/<deviceID>/<commandName>[@<clientID>]
dh/command_update/<networkID>/<deviceTypeID>/<deviceID>/<commandName>[@<clientID>]
Where:
The devicehive-mqtt broker supports common wildcards in the topic ( +, #)
All topics that are starts with dh
appraised by the broker as a DeviceHive topic.
All other topics are appraised as an ordinary MQTT topic.
In this small code snippets we are using MQTT as a client library.
Connection with username and password:
const mqtt = require("mqtt");
const client = mqtt.connect("mqtt://localhost:1883", {
username: "<deviceHiveUserLogin>",
password: "<deviceHiveUserPassword>",
});
client.on("connect", () => {
//connection handler
});
client.on("error", () => {
//error handler
});
Connection without credentials, authentication with user access token:
const mqtt = require("mqtt");
const client = mqtt.connect("mqtt://localhost:1883");
client.on("message", function (topic, message) {
const messageObject = JSON.parse(message.toString());
if (messageObject.requestId === "12345") {
if (messageObject.status === "success") {
//client authenticated
}
}
});
client.on("connect", () => {
client.subscribe("dh/response/authenticate@" + client.options.clientId);
client.publish("dh/request", {
action: "authenticate",
token: "<userAccessToken>",
requestId: "12345",
});
});
client.on("error", () => {
//error handler
});
Connection with username and password, subscription for notification and command push messages:
const mqtt = require("mqtt");
const client = mqtt.connect("mqtt://localhost:1883", {
username: "<deviceHiveUserLogin>",
password: "<deviceHiveUserPassword>",
});
client.on("message", function (topic, message) {
const messageObject = JSON.parse(message.toString());
//notification/command push messages
});
client.on("connect", () => {
/* Subscribe for notification push messages with name = notificationName
of device with id = deviceId on network with id = networkId */
client.subscribe(
"dh/notification/<networkId>/<deviceTypeId>/<deviceId>/<notificationName>"
);
/* Subscribe for notification push messages with name = notificationName
of any device on network with id = networkId */
client.subscribe(
"dh/notification/<networkId>/<deviceTypeId>/+/<notificationName>"
);
/* Subscribe for command push messages with name = commandName
of device with id = deviceId on network with id = networkId */
client.subscribe(
"dh/command/<networkId>/<deviceTypeId>/<deviceId>/<commandName>"
);
/* Subscribe for command push messages on network with id = networkId
for any device with any command name */
client.subscribe("dh/command/<networkId>/#");
});
client.on("error", () => {
//error handler
});
Connection without credentials subscription and publishing to the ordinary topics:
const mqtt = require("mqtt");
const client = mqtt.connect("mqtt://localhost:1883");
client.on("message", function (topic, message) {
const messageObject = JSON.parse(message.toString());
// messages handler
});
client.on("connect", () => {
client.subscribe("ordinary/topic");
client.publish("another/ordinary/topic", {
data: "someData",
});
});
client.on("error", () => {
//error handler
});
Unit tests:
npm run unitTest
Integration tests (broker should be ran on localhost:1883):
npm run integrationTest