ESP32: serializing DS18B20 temperature measurement to MessagePack format

In this tutorial we will check how to obtain a temperature measurement from the DS18B20 sensor and serialize it using the MessagePack format. The tests were performed using a DFRobot’s ESP32 module integrated in a ESP32 development board and a waterproof version of the sensor.

Introduction

In this tutorial we will check how to obtain a temperature measurement from the DS18B20 sensor and serialize it using the MessagePack format.

For the MessagePack serialization, we will use the ArduinoJson library. We have already covered in detail how to serialize content to this format on this post.

For a detailed tutorial on how to obtain temperature measurements from the DS18B20 sensor, please check here. The mentioned tutorial has the electric diagram of the connection between the sensor and the ESP32 and covers the installation of all the libraries we are going to need.

The tests were performed using a DFRobot’s ESP32 module integrated in a ESP32 development board and a waterproof version of the sensor.

The code

We will start our code by the library includes. We will need the following libraries:

  • ArduinoJson.h – Allows to serialize the data to the MessagePack format;
  • OneWire.h – Allows to interact with devices using the OneWire protocol;
  • DallasTemperature.h – Offers an higher level API to interact with the DS18B20 temperature sensor.
#include <ArduinoJson.h>
#include "OneWire.h"
#include "DallasTemperature.h"

Next we will need to instantiate an object of class OneWire. The constructor of this class receives as input the number of the microcontroller pin that will be connected to the temperature sensor. For this tutorial I’ve used pin 22.

OneWire oneWire(22);

After this, we will instantiate an object of class DallasTemperature, which will expose the higher level methods needed to obtain the measurements from the sensor.

The constructor of this class receives as input the address of a OneWire object. We will pass the address of the object we have just created. The OneWire object will be used under the hood to exchange data with the sensor.

DallasTemperature tempSensor(&oneWire);

Moving on the setup function, we will start by opening a serial connection, so we can output the results of the program.

After that we will call the begin method on the DallasTemperature object. This method takes no arguments and it will initialize the OneWire bus.

void setup(void)
{
  
  Serial.begin(115200);
  tempSensor.begin();
}

We will write the rest of the code in the Arduino loop function, so it runs periodically.

We will start by declaring a StaticJsonDocument object, which will hold the in memory representation of our object. We will declare a capacity of 100 bytes for our object, which is more than enough to hold the data. You can use this assistant for a more accurate estimation.

StaticJsonDocument<100> testDocument;

After this we will obtain a temperature measurement. First we call the requestTemperaturesByIndex method of our DallasTemperature object, in order for the sensor to start doing a temperature conversion.

Since the OneWire protocol supports having multiple devices connected simultaneously to the same bus, we need to pass as input of this method the index of the device we want to use. Since we just have one device connected, we pass the index 0.

Note that, by default, this function call will block until the conversion is performed.

tempSensor.requestTemperaturesByIndex(0);

Once the conversion is finished, we can obtain the temperature value by calling the getTempCByIndex method. As input, we pass again the device index, which should be 0.

float temperature = tempSensor.getTempCByIndex(0);

Next we will set the values in our StaticJsonDocument, using the [] operator. To have a slightly more complex data structure, we will first set a key called “sensorType” that will have the value “Temperature“.

We will then add a key called “sensorValue” that will hold the value of our previously obtained measurement.

testDocument["sensorType"] = "Temperature";
testDocument["sensorValue"] = temperature;

We will now print the temperature value we obtained from the sensor. That way, we can later compare it with was serialized to the MessagePack payload.

Note that, by default, the print method will only output 2 decimal places of float values. Thus, our temperature will only display 2 decimal places when we are checking the result in the serial monitor, whereas it can have more decimal places when we deserialize the MessagePack payload.

Serial.println("Temperature: ");
Serial.print(temperature);
Serial.println(" C");

To finalize, we will now serialize our data to the MessagePack format and print the result. We will first declare a buffer to hold the resulting data and then perform the serialization by calling the serializeMsgPack function.

char buffer[100];

int bytesWritten = serializeMsgPack(testDocument, buffer);

Then we will iterate through all the bytes of the payload and print them to the serial port, in hexadecimal format.

for(int i = 0; i<bytesWritten; i++){
    Serial.printf("%02X ",buffer[i]);
}

The final code can be seen below. We have introduced a small delay of 5 seconds between each iteration of the loop.

Note that using a delay is a simplification to make our code simpler. For more accurate periodic measurements, we should use timer interrupts instead, as covered here.

#include <ArduinoJson.h>
#include "OneWire.h"
#include "DallasTemperature.h"
  
OneWire oneWire(22);
DallasTemperature tempSensor(&oneWire);
  
void setup(void)
{
  
  Serial.begin(115200);
  tempSensor.begin();
}
  
void loop(void)
{
  StaticJsonDocument<100> testDocument;
     
  tempSensor.requestTemperaturesByIndex(0);
  float temperature = tempSensor.getTempCByIndex(0);

  testDocument["sensorType"] = "Temperature";
  testDocument["sensorValue"] = temperature;
  
  Serial.println("Temperature: ");
  Serial.print(temperature);
  Serial.println(" C");

  Serial.println("Serialized message: ");

  char buffer[100];
   
  int bytesWritten = serializeMsgPack(testDocument, buffer);
  
  for(int i = 0; i<bytesWritten; i++){
    Serial.printf("%02X ",buffer[i]);
  }

  Serial.println("\n------------");
  
  delay(5000);
}

Testing the code

To test the code, simply compile and upload it to your ESP32 device, after all the connections to the sensor are done. When the procedure is finished, you should obtain a result like the one shown in figure 1.

Output of the program on the Arduino IDE serial monitor, showing the temperature measurement and the encoded message.
Figure 1 – Output of the program on the Arduino IDE serial monitor.

To test if the encoded message has the expected temperature value, we can use this online tool, which allows to perform the decoding. As can be seen in figure 2, the message correctly decodes to the data structure we defined in our program.

Decoding the Message Pack payload on an online tool
Figure 2 – Decoding the message on an online tool.

Related Posts

4 Replies to “ESP32: serializing DS18B20 temperature measurement to MessagePack format”

  1. And thats how you add complexity to a project in order to add 6 bytes per message (45 byte msgpack size vs 39 bytes optimized JSON message)! And in order to build and decode the messages you need some additional libraries on both ends.

    If you would just use plain old line based messages the message would be about 20 bytes without loosing any information.

    Fact is: only use MsgPack if your messages are bigger and the content not as predictable as shown in the example.

    1. Hi,

      Thank you very much for your feedback 🙂

      This is just a simple example on how to work with MsgPack.

      The focus of the tutorial was to show how we can get a measurement from the sensor and serialize it, and the message fields and names used were just for testing purposes.

      The point was not to focus on if it compensates or not for this particular payload, but on how to use MsgPack if you want to.

      Depending on the use case it might make sense to use the technology or not, and I did not want to make any assumptions about this for the tutorial.

      This is a personal opinion, but a microcontroller like the ESP32 is so powerful that if I’m using HTTP, I prefer to have the overhead of using JSON (the ESP32 is more than capable of handling it) and have a structured message that can be easily parsed by the backend.

      Personally I think this is much less error prone that sending messages byte by byte via HTTP, in a format that is non standard, just to save a few bytes (unless you really have to do it to fill some performance requirements).

      Between using just JSON or MessagePack, that’s an evaluation that I would have to do for the specific application. But it is good to know that if I want to, I can choose either of them.

      Naturally, if we were aiming for serial communication or other similar wired protocol, I would also not go for MessagePack or JSON.

      Note also that I do many tutorials just as proof of concepts, for the fun of discovering and knowing if it is possible to use a given technology and testing the limits of the devices.

      It doesn’t necessarily mean that the particular technology is the best choice for a real scenario application 🙂

      For example, I did a couple of tutorials on how to use HTTP/2 on the ESP32 because it was fun! If it would be my choice to implement a real scenario application? most likely no.

      I don’t usually analyze this because it’s very opinion based 🙂

      Best regards,
      Nuno Santos

      1. Thanks for your response! Maybe add a short section about when it is a good/bad idea to use some method or technology, Just a short section, explaining what would be the usecase for the shown method or what simplifications where made (like using the serial interface instead of the more complex HTTP server). This would make it clear to the reader that it’s just an example and not intended to copy&paste and think this is the best solution.

        1. That’s a very good idea, thanks for the suggestion 🙂

          I’ll try to include a bit more context in the next posts, in the introductory section.

          Best regards,
          Nuno Santos

Leave a Reply