This page explains how to use ArduinoJson with PubSubClient, a popular MQTT library for Arduino. It shows how to use the JSON format in MQTT messages, but you can easily adapt the examples to use MessagePack instead.

Deserializing a JSON document in MQTT message

Once your program has subscribed to an MQTT topic, you can call deserializeJson() from the callback function.

void callback(char* topic, byte* payload, unsigned int length) {
  StaticJsonDocument<256> doc;
  deserializeJson(doc, payload, length);
  // use the JsonDocument as usual...

Note that you don’t need to cast the payload pointer because deserializeJson() supports byte* too.

Serializing a JSON document into an MQTT message

To publish a JSON document to an MQTT topic, you need to serialize it to a temporary buffer:

char buffer[256];
serializeJson(doc, buffer);
client.publish("outTopic", buffer);

You can save a few CPU cycles by passing the size of the payload to publish():

char buffer[256];
size_t n = serializeJson(doc, buffer);
client.publish("outTopic", buffer, n);

By default, PubSubClient limits the message size to 256 bytes (including header); see the documentation.

Can we avoid the temporary buffer?

It’s tempting to remove the temporary buffer to save some memory. For example, we can write:

client.beginPublish(topic, measureJson(doc), retained);
serializeJson(doc, client);

However, this code is much slower than the one with a temporary buffer (100 to 200 times slower from our experience).

This slowness is due to the Client class that sends bytes one by one. To improve the speed, we need to insert a small buffer as show in How to improve (de)serialization speed?:

client.beginPublish(topic, measureJson(doc), retained);
WriteBufferingPrint bufferedClient(client, 32);
serializeJson(doc, bufferedClient);

Notice that I used a WriteBufferingPrint instead of WriteBufferingClient because, despite its name, the PubSubClient class doesn’t implement the Client but the Print interface. For more information on WriteBufferingPrint, see the README of the StreamUtils library.

This works, but as you can see, it’s much more complicated than the original code, so I don’t think it’s worth the effort.

See also