MQTT Client library for Arduino based on the
Eclipse Paho project.
This library bundles the C/C++ MQTTPacket library of the Eclipse Paho project
with simple synchronous C++ MQTT Client implementation to get the Arduino like API.
- Support of
MQTTQoS0,QoS1and simplifiedQoS2 - Synchronous implementation. The method
yieldmust be called regularly to allow incoming message processing and to send keep-alive packets in time TCPnetwork communication is out of the library scope.MqttClient::Networkobject must be provided withreadandwriteimplementations- System current time and other functions are provided externally by
MqttClient::Systemobject to allow easy adaptation to any other environments - External logger.
MqttClient::Loggerobject is used to print logs with any convenient way for particular environment - No heap memory allocations.
All required resources must be provided at the moment of
MqttClientconstruction. It allows the full control and limiting of the used resources externally:MqttClient::Bufferobjects are used as send/receive temporary buffersMqttClient::MessageHandlersobject is used as storage of subscription callback functions
- Idle interval calculator (See
getIdleIntervalmethod). Could be very useful If you going to put board/radio into low-power mode between data transmissions
Search for ArduinoMqtt using official Library Manager.
Add ArduinoMqtt to the platformio.ini file to enable automatic installation:
lib_deps = ArduinoMqttSee full Arduino example that covers Publish
and Subscribe logic.
Logging is disabled by default. Define MQTT_LOG_ENABLED equal 1 to enable.
If you can't add the define using compiler options (in case of Arduino IDE) just define it before including the library header:
#define MQTT_LOG_ENABLED 1
#include <MqttClient.h>Provide class implementing the MqttClient::Logger interface.
Alternatively just instantiate the MqttClient::LoggerImpl template class that
allows direct use of the Arduino HardwareSerial class or any other object with
implemented void println(const char*) method:
#define HW_UART_SPEED 57600L
// Setup hardware serial for logging
Serial.begin(HW_UART_SPEED);
while (!Serial);
// Create MqttClient logger
MqttClient::Logger *mqttLogger = new MqttClient::LoggerImpl<HardwareSerial>(Serial);Provide class implementing the MqttClient::System interface to allow library
access to the system resources.
Used to access the system time. The implementation must return the current time in milliseconds.
Arduino simple implementation:
class System: public MqttClient::System {
public:
...
unsigned long millis() const {
return ::millis();
}
...
}General C++ implementation might be like:
#include <chrono>
class TestSystem: public MqttClient::System {
...
unsigned long millis() const {
return std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();
}
...
}Used to access the system yield.
Method is called regularly while long waits.
Some systems like ESP requires calling of the yield regularly to:
- maintain WiFi connection
- reset watchdog timer
ESP8266 simple implementation:
class System: public MqttClient::System {
public:
...
void yield(void) {
::yield();
}
...
}Provide class implementing the MqttClient::Network interface.
Instantiate the MqttClient::NetworkImpl template class that
allows usage of any class with implemented methods like:
int read(unsigned char* buffer, int len, unsigned long timeoutMs)int write(unsigned char* buffer, int len, unsigned long timeoutMs)
Proposed example assumes that TCP stack is connected using serial interface to
Arduino pins 10(RX) and 11(TX). The SoftwareSerial library is used for actual
communication:
#define SW_UART_PIN_RX 10
#define SW_UART_PIN_TX 11
#define SW_UART_SPEED 9600L
class Network {
public:
Network() {
mNet = new SoftwareSerial(SW_UART_PIN_RX, SW_UART_PIN_TX);
mNet->begin(SW_UART_SPEED);
}
int read(unsigned char* buffer, int len, unsigned long timeoutMs) {
mNet->setTimeout(timeoutMs);
return mNet->readBytes((char*) buffer, len);
}
int write(unsigned char* buffer, int len, unsigned long timeoutMs) {
mNet->setTimeout(timeoutMs);
for (int i = 0; i < len; ++i) {
mNet->write(buffer[i]);
}
mNet->flush();
return len;
}
private:
SoftwareSerial *mNet;
}
MqttClient::System *mqttSystem = new System;
MqttClient::Network *mqttNetwork = new MqttClient::NetworkImpl<Network>(*network, *mqttSystem);Another alternative allows using of Arduino Client compatible network classes
like EthernetClient or WiFiClient of ESP8266 etc...
To have this just instantiate the MqttClient::NetworkClientImpltemplate class:
EthernetClient network;
MqttClient::System *mqttSystem = new System;
MqttClient::Network * mqttNetwork = new MqttClient::NetworkClientImpl<Client>(network, *mqttSystem);Provide two buffers the one for transmitting message and another one for receiving
message processing. Buffer is a class implementing the MqttClient::Buffer interface.
Use the MqttClient::ArrayBuffer template class to get simplest implementation
based on C array:
// Make 128 bytes send buffer
MqttClient::Buffer *mqttSendBuffer = new MqttClient::ArrayBuffer<128>();
// Make 128 bytes receive buffer
MqttClient::Buffer *mqttRecvBuffer = new MqttClient::ArrayBuffer<128>();Provide class implementing the MqttClient::MessageHandlers interface to keep
subscription callback functions.
Instantiate the MqttClient::MessageHandlersImpl template
class to get simplest implementation based on C array:
// Allows up to 2 subscriptions simultaneously
MqttClient::MessageHandlers *mqttMessageHandlers = new MqttClient::MessageHandlersImpl<2>();This implementation does not copy the topic string and keeps only pointer. Please ensure the pointer remains valid while topic is subscribed. This is preferred implementation because of minimal resources requirements.
Instantiate the MqttClient::MessageHandlersStaticImpl template class:
// Allows up to 2 subscriptions simultaneously
// Allows up to 64 bytes for topic string including 1 byte for string termination symbol
MqttClient::MessageHandlers *mqttMessageHandlers = new MqttClient::MessageHandlersStaticImpl<2, 64>();This implementation preallocates buffers to store topic strings in advance.
This implementation does copy the topic string.
This is preferred implementation when the maximum topic length could be predicted
because it avoids the heap allocations at the moment of subscribe call.
Instantiate the MqttClient::MessageHandlersDynamicImpl template class:
// Allows up to 2 subscriptions simultaneously
MqttClient::MessageHandlers *mqttMessageHandlers = new MqttClient::MessageHandlersDynamicImpl<2>();This implementation allocates buffer to store topic string at the moment of subscribe call.
This implementation does copy the topic string.
- Install IDE and extension, see official installation guide.
- Open the project (
File -> Open). - Use the PlatformIO Toolbar or PlatformIO CLI to build the project.
- MQTT 3.1.1 protocol