For a complete view : with UML sequence diagrams
MQTT for all micro-controllers ! The purpose is to offer MQTT publisher/subscriber functionality to all small micro controllers. Those with just a UART or USB interface.
Example : a cheap STM32 board on ebay.
This program will act as a full MQTT Client gateway and make integration as simple as possible.
This was created because Ethernet or WiFi is still absent in most ( cheap ) controllers .
Also the concept behind is that a central PC or Raspberry PI can act as the intelligent mind behind commodity components.
Arduino Sample program to communicate with the serial2mqtt gateway
#include <ArduinoJson.h>
class Mqtt {
public:
static String device;
static void publish( String topic, String message, int qos = 0, bool retained = false ) {
StaticJsonBuffer<200> jsonBuffer;
JsonObject& data = jsonBuffer.createObject();
data["cmd"] = "MQTT-PUB";
data["topic"] = "src/" + device + "/" + topic;
data["message"] = message;
if ( qos != 0 ) data["qos"] = qos;
if ( retained) data["retained"] = retained;
data.printTo(Serial);
Serial.println();
}
static void handleLine(String& line) {
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(line);
onMqttMessage(root["topic"], root["message"], root["qos"], root["retained"]);
}
static void onMqttMessage(String topic, String message, int qos, bool retained) {
// add your own subscriber here
Serial.printf(" Mqtt Message arrived");
}
};
// create a name for this device
String Mqtt::device = "ESP32-" + String((uint32_t)ESP.getEfuseMac(), HEX);
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
String line;
void loop() {
while (Serial.available()) {
char ch = Serial.read();
if ( ch == '\r' || ch == '\n' ) {
Mqtt::handleLine(line);
line = "";
} else
line += ch;
}
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a 0.1 second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a 0.1 second
Mqtt::publish( "system/upTime", String(millis(), 10), 0, false);
Mqtt::publish("system/host", Mqtt::device, 0, false);
Mqtt::publish("system/alive", "true", 0, false);
}
The serial2mqtt should be able to reset the device ( hard reset )
{ "cmd":"MQTT-PUB","topic":"src/device/service/property","message":"1234.66","qos":0,"retained":false }\n
<END><SLIP ENCODED MESSAGE><END>
<SLIP ENCODED MESSAGE> == <'M'><"PUB">,<qos Integer><retain boolean><topic string><message binary><CRC integer>
A command line utility will send a single mqtt request to the serial2mqtt gateway to program the microcontroller.
The micrcontroller will also log to the central logging system
Or just deploy the pre-build versions from the Debug directory , 2 versions available : Linux 64bits Intel and Raspberry Pi ARM.
Per serial port there is a main thread and mqtt threads for callback
The main thread waits for events and handle these primarily. 2 timers in this thread are checked for expiry ( not time critical ) : serial-watchdog and mqtt-connect.
To avoid concurrency issues , the callbacks of the mqtt threads are communicated back by writing an event code on a pipe.
The main threads waits on events : timeout of 1 sec, data on serial file-descriptor or pipe file-descriptor.
The mqtt event of received message is handled directly by writing the message on the serial port.