In the recent Maker Faire I demonstrated an ESP8266 MQTT VFD clock. Some readers had wrote to ask for the soure code. Because the project was builtup within only 2 days, the actual source code is more or less of spaghette type. However the underlying MQTT client may be useful to someone who likes the RTOS SDK.
If you search MQTT and ESP8266 on the intraweb, most likely all hits can be traced back to the great work done by TuanPM. However Tuan’s code is based on Espressif’s NON-OS SDK. There has been some great debates about embedded programming with-or-without an OS. To me programming with OS vs NON-OS is like programming with C vs Assembly. I like programming in C, so I wrote a new MQTT client for Espressif’s RTOS SDK.
The source code is published at https://github.com/baoshi/ESP-RTOS-Paho
Here are some notes:
- The code is based on the Eclipse Paho project, specifically the embedded C client.
- Socket-level APIs used, the code is thread-safe.
- Many error handlings were added to the original Paho client, including time-out for most of the network functions. These are designed to work with an RTOS to support automatic error correction at various abused conditions.
- I’m compiling using the “Unofficial ESP8266 DevKit“. Other toolchain such as esp-open-sdk can be used as well (adjust pathes in Makefile).
- Skeleton code for connecting a MQTT broker is as follows:
struct Network network;
MQTTClient client = DefaultClient;
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
unsigned char mqtt_buf;
unsigned char mqtt_readbuf;
ConnectNetwork(&network, MQTT_HOST, MQTT_PORT);
NewMQTTClient(&client, &network, 5000, mqtt_buf, 100, mqtt_readbuf, 100);
data.willFlag = 0;
data.MQTTVersion = 3;
data.clientID.cstring = mqtt_client_id; // you client’s unique identifier
data.username.cstring = MQTT_USER;
data.password.cstring = MQTT_PASS;
data.keepAliveInterval = 10; // interval for PING message to be sent (seconds)
data.cleansession = 0;
To subscribe to a MQTT topic, use
MQTTSubscribe(&client, "/mytopic", QOS1, topic_received);
The parameter topic_received is a callback function handling the received message:
// Callback when receiving subscribed message
LOCAL void ICACHE_FLASH_ATTR topic_received(MessageData* md)
MQTTMessage* message = md->message;
dmsg_puts("Received Topic ");
for (i = 0; i t; md->topic->lenstring.len; ++i)
dmsg_puts(", Message ");
for (i = 0; i < (int)message->payloadlen; ++i)
To publish a MQTT topic, use
message.payload = msg;
message.payloadlen = PUB_MSG_LEN;
message.dup = 0;
message.qos = QOS1;
message.retained = 0;
MQTTPublish(&client, "topic", &message);
The demo project included in the library shows how the MQTT related functions can be organized inside a FreeRTOS task and interact with other tasks, such as retry connection after server error, WiFi error, etc. The following diagram may be helpful to understand the code. (Imaging how this can be done using NON-OS SDK)
As Espressif had just teased us with the new ESP32 chip and RTOS is rumored to be the default SDK, I hope this piece of code will be useful.