Over a million developers have joined DZone.

Building a Tank Volume Reader Using the ESP32

DZone 's Guide to

Building a Tank Volume Reader Using the ESP32

Particularly helpful for craft brewers, here's how to create a monitoring station to determine how full containers are using an ESP32, some sensors, and Ubidots Cloud.

· IoT Zone ·
Free Resource

The Internet of Things has brought a lot of formerly complex device applications into the homes of many craft brewers and wine makers. Applications with level sensors have been used for decades in large refineries, water treatment plants, and chemical plants. With sensor prices falling, now both industrial and DIY users can monitor the volume of any tank, barrel, or canister.

The sensors available on the open market can sense most anything and are classified accordingly. Sensors used for measuring humidity are called humidity sensors. Then you have your pressure sensors, and for measuring distance, there are position sensors. In a similar fashion, the sensor used for measuring fluid levels is called a level sensor.

Level sensors are used to measure the level of the free-flowing substances. Such substances include liquids like water, oil, slurries, etc. as well as solids in granular/powder form (solids which can flow). These substances tend to settle in container tanks due to gravity and maintain their level in a resting state.

In this guide, you will learn how to build your own home-made level, temperature, and humidity sensor. Also included are instructions for your newly collected data to be utilized via Ubidots, an application enablement platform.


  • Plastic protection case

  • Wires

  • Micro USB cable

Wiring and Casing

The sensor HC-SR04 (Ultrasonic Sensor) works with 5V logic. Please, follow the table and diagram below to make the correct connections between the ESP32 and the ultrasonic sensor:

Please follow the table below to make the correct connections between the ESP32 and the DHT11 sensor (temperature and humidity sensor):

I built a small prototype with a scale-sized tank to shows the functions of the sensor, but a final prototype with its case should look like this:

As you can see, the ultrasonic sensor should be at the top of the tank, so we're going to be able to measure the distance between the up part of the tank and the endpoint of the substance:

Place the temperature and humidity sensors to monitor the environment.

Connect With the Arduino IDE

Before beginning with the ESP32, set up your board with the Arduino IDE. If you are not familiar with that, please reference the article below and follow it step by step until you've compiled the board:

Once your board is compiled, install the libraries required to run the sensors: "PubSubClient" and "DHT:"

Go to Sketch/Program -> Include Library -> Library Manager and install the PubSubClient library. To simply find the correct library, search for PubSubClient within the search bar.

Go to the library repository to download the DHT library. To download the library, click the green button called "Clone or download" and select "Download ZIP".

Now, back in the Arduino IDE, click on Sketch -> Include Library -> Add .ZIP Library

Then, select the ZIP file of DHT and then “Accept” or “Choose

If successful, you will receive a message saying so in the Arduino IDE.

Close the Arduino IDE and open it again. A restart is required; please do not skip this step.

Now, it's time to start coding!

Copy the code below and paste into the Arduino IDE.

 * This Example sends harcoded data to Ubidots using a ESP32. The code sends a distance value 
 * between a device and its opposite endpoint to Ubidots, then the value will be managed in 
 * Ubidots to calculate the volume of a tank with the characteristics of your tank.
 * This example is given AS IT IS without any warranty.
 * Made by María Carlina Hernandez.

 * Include Libraries
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

 * Define Constants
namespace {
    const char * WIFISSID = "Assign_your_wifi_SSID_here"; // Put your WifiSSID here
    const char * PASSWORD = "Assign_your_wifi_SSID_here"; // Put your wifi password here
    const char * TOKEN = "Assign_your_Ubidots_token_here"; // Put your Ubidots' TOKEN
    const char * MQTT_CLIENT_NAME = "Assign_MQTT_client_here"; // MQTT client Name, please enter your own 8-12 alphanumeric character ASCII string; 
    const char * VARIABLE_LABEL_1 = "distance"; // Assing the variable label
    const char * VARIABLE_LABEL_2 = "humidity"; // Assing the variable label
    const char * VARIABLE_LABEL_3 = "temperature"; // Assing the variable label
    const char * DEVICE_LABEL = "esp32"; // Assig the device label
    const char * MQTT_BROKER = "things.ubidots.com";
    const int DHTPIN = 33; // Pin where is connected the DHT11
    const int DHTTYPE = DHT11; // Type of DHT
    const int trigPin = 16; // Triger pin of the HC-SR04
    const int echoPin = 17; // Echo pin of the HC-SR04  

/* Sensor's declarations */
long duration;
float distance;
/* Space to store the request */
char payload[300];
char topic[150];
/* Space to store values to send */
char str_sensor[10];
char str_TempSensor[10];
char str_HumSensor[10];

 * Auxiliar Functions
WiFiClient ubidots;
PubSubClient client(ubidots);

void callback(char * topic, byte * payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);
    Serial.write(payload, length);

void reconnect() {
    // Loop until we're reconnected
    while (!client.connected()) {
        Serial.println("Attempting MQTT connection...");

        // Attemp to connect
        if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) {
        } else {
            Serial.print("Failed, rc=");
            Serial.println(" try again in 2 seconds");
            // Wait 2 seconds before retrying

 * Sensor Functions
float readDistance() {
    digitalWrite(trigPin, HIGH);
    digitalWrite(trigPin, LOW);
    duration = (pulseIn(echoPin, HIGH));
    distance = float(duration / 29 / 2);
    return distance;

 * Main Functions
void setup() {

    /* Initializing the DHT11 */

    /* Assign the PINS as INPUT/OUTPUT */
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);

    Serial.print("Wait for WiFi...");

    while (WiFi.status() != WL_CONNECTED) {

    Serial.println("WiFi Connected");
    Serial.println("IP address: ");
    client.setServer(MQTT_BROKER, 1883);

void loop() {
    if (!client.connected()) {

    /* Reading temperature and humidity */
    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();

    /* call the funtion readDistance() */
    distance = readDistance();

    /* 4 is mininum width, 2 is precision; float value is copied onto str_sensor*/
    dtostrf(distance, 4, 2, str_sensor);
    dtostrf(humidity, 4, 2, str_HumSensor);
    dtostrf(temperature, 4, 2, str_TempSensor);

    /* Building the Ubidots request */
    sprintf(topic, "%s%s", "/v1.6/devices/", DEVICE_LABEL);
    sprintf(payload, "%s", ""); // Cleans the payload
    sprintf(payload, "{\"%s\": %s,", VARIABLE_LABEL_1, str_sensor); // Adds the variable label
    sprintf(payload, "%s\"%s\": %s,", payload, VARIABLE_LABEL_2, str_HumSensor); // Adds the variable label
    sprintf(payload, "%s\"%s\": %s}", payload, VARIABLE_LABEL_3, str_TempSensor); // Adds the variable label

    //sprintf(payload, "%s {\"value\": %s}}", payload, str_sensor); 

    /* Print the sensor reading to the Serial Monitor */
    Serial.println("Publishing values to Ubidots Cloud");
    Serial.print("Distance = ");
    Serial.print("Humidity = ");
    Serial.print("Temperature = ");

    /* Publish the request to Ubidots */
    client.publish(topic, payload);

Next, assign the parameters: Wi-Fi name and password, plus your unique Ubidots TOKEN. If you don't know how to locate your Ubidots TOKEN, please reference the article below.

Once you've pasted your code and assigned the appropriate Wi-Fi, verify in the Arduino IDE. To verify, in the top left corner of our Arduino IDE, you will see the following icons. Choose the Check Mark icon to verify any code.

Once verified, you will receive a "Done compiling" message in the Arduino IDE.

Next, upload the code into your ESP32. Choose the right-arrow icon beside the check mark icon to upload.

Once uploaded, you'll receive a "Done uploading" message in the Arduino IDE.

With this, your sensor is now sending the data to the Ubidots Could!

Data Management in Ubidots

If your device is correctly connected, you will see a new device created within your device section in your Ubidots application. The name of the device will be "esp32". Also, inside the device, you will see the variables distance, humidity, and temperature:

If you desire to change your device and variable names to more friendly ones, please reference this article:

Next, to calculate the volume of free-flowing substances in the tank, we need to create a derived variable to calculate a volume value.

The Derived Variable lets us build operations using the default variables. So, in this case, we are going to apply the volume formula with the characteristic of a cylindrical tank where:

  • Pi = The ratio of a circle's circumference to its diameter (constant)
  • r = The radius of the tank
  • h = The height of the tank

Click on "Add variable" and select "Derived":

As you can see at the new window, you have to attach the formula in the following field:

Once you've attached the formula with the characteristics of your tank, select the variable "distance."

With your formula entered, your volume will begin reading in your Ubidots application.


Now your sensor is ready to start working! Below, you can see the function of the level sensor at different volumes:

To learn more about Ubidots widgets and events, check out these video tutorials.

Happy hacking!

iot ,ubidots cloud ,sensors ,volume ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}