Search

ESP32 DS18B20 Temperature Sensor Tutorial & Best Practices (Single, Multiple, Web Server)

Here’s a thorough tutorial on using the DS18B20 temperature sensor with ESP32 via Arduino IDE. We’ll demonstrate the wiring process, library installation, and coding for obtaining temperature readings from both single and multiple sensors. Additionally, we’ll create a basic web server to showcase these readings.

Introducing DS18B20 Temperature Sensor

The DS18B20 temperature sensor operates on a single-wire digital interface. This means it only needs one data line (and GND) to communicate with your ESP32.

It can draw power either from an external power source or from the data line itself (referred to as “parasite mode”), eliminating the need for an external power supply.

Each DS18B20 sensor comes with a unique 64-bit serial code. This feature enables you to connect multiple sensors to the same data wire, allowing you to obtain temperature readings from several sensors using just one GPIO pin.

Additionally, the DS18B20 temperature sensor is available in a waterproof version.

Here’s a summary of the key specifications of the DS18B20 temperature sensor:

  • Utilizes one-wire bus communication
  • Power supply range: 3.0V to 5.5V
  • Operating temperature range: -55ºC to +125ºC
  • Accuracy of +/-0.5 ºC (within the range of -10ºC to 85ºC)

For further details, refer to the DS18B20 datasheet.

Schematic – ESP32

As noted earlier, the DS18B20 temperature sensor can be powered via the VDD pin (standard mode), or it can draw power from the data line (parasitic mode). You can select either mode.

If you’re utilizing an ESP32, refer to one of these two schematic diagrams.

Parasite Mode

Normal Mode

Parts Required

Component NameBuy Now
ESP32-WROOM-32 DevelopmentAmazon
DS18B20 Temperature SensorAmazon
Please Note: These are affiliate links. I may make a commission if you buy the components through these links. I would appreciate your support in this way!

Preparing Your Arduino IDE

We’ll be programming the ESP32 using Arduino IDE, so ensure you have the ESP32 add-on installed before proceeding:

Installing Libraries

To interface with the DS18B20 temperature sensor, you’ll need to install the One Wire library by Paul Stoffregen and the Dallas Temperature library. Follow these steps to install the libraries:

Open your Arduino IDE and navigate to Sketch > Include Library > Manage Libraries. This will open the Library Manager.

In the search box, type “onewire” and install the OneWire library by Paul Stoffregen.

Next, search for “Dallas” and install the DallasTemperature library by Miles Burton.

    After installing the libraries, restart your Arduino IDE.

    Code (Single DS18B20)

    Once you’ve installed the necessary libraries, you can upload the code to the ESP32. The following code retrieves temperature data from the DS18B20 sensor and displays it on the Arduino IDE Serial Monitor.

    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    // GPIO where the DS18B20 is connected to
    const int oneWireBus = 4;     
    
    // Setup a oneWire instance to communicate with any OneWire devices
    OneWire oneWire(oneWireBus);
    
    // Pass our oneWire reference to Dallas Temperature sensor 
    DallasTemperature sensors(&oneWire);
    
    void setup() {
      // Start the Serial Monitor
      Serial.begin(115200);
      // Start the DS18B20 sensor
      sensors.begin();
    }
    
    void loop() {
      sensors.requestTemperatures(); 
      float temperatureC = sensors.getTempCByIndex(0);
      float temperatureF = sensors.getTempFByIndex(0);
      Serial.print(temperatureC);
      Serial.println("ºC");
      Serial.print(temperatureF);
      Serial.println("ºF");
      delay(5000);
    }
    

    There are numerous methods to obtain temperature readings from DS18B20 sensors. However, if you’re using a single sensor, this is one of the simplest and most straightforward approaches.

    Code Explanation

    Begin by including the OneWire and DallasTemperature libraries:

    #include <OneWire.h>
    #include <DallasTemperature.h>

    Instantiate the necessary objects for the temperature sensor. The sensor is connected to GPIO 4.

    // GPIO where the DS18B20 is connected to
    const int oneWireBus = 4;
    
    // Setup a oneWire instance to communicate with any OneWire devices
    OneWire oneWire(oneWireBus);
    
    // Pass our oneWire reference to Dallas Temperature sensor 
    DallasTemperature sensors(&oneWire);

    In the setup() function, initialize the Serial Monitor with a baud rate of 115200:

    Serial.begin(115200);

    Initialize the DS18B20 temperature sensor:

    sensors.begin();

    Before retrieving the temperature, call the requestTemperatures() method:

    sensors.requestTemperatures(); 

    Then, retrieve the temperature in Celsius using the getTempCByIndex() method:

    float temperatureC = sensors.getTempCByIndex(0);

    Alternatively, use getTempFByIndex() to obtain the temperature in Fahrenheit:

    float temperatureF = sensors.getTempFByIndex(0);

    Both getTempCByIndex() and getTempFByIndex() methods require the index of the temperature sensor. Since we’re using only one sensor, its index is 0. For multiple sensors, utilize index 0 for one sensor, index 1 for another, and so forth.

    Lastly, print the results in the Serial Monitor:

    Serial.print(temperatureC);
    Serial.println("ºC");
    Serial.print(temperatureF);
    Serial.println("ºF");

    New temperature readings are requested every 5 seconds:

    delay(5000);

    Demonstration

    After uploading the code, you should get your sensor readings displayed in the Serial Monitor:

    Obtaining Temperature from Multiple DS18B20 Temperature Sensors

    The DS18B20 temperature sensor utilizes a one-wire protocol, with each sensor possessing a unique 64-bit serial code. Consequently, you can retrieve temperature data from multiple sensors using a single GPIO. Simply connect all data lines together, as illustrated in the following schematic diagram:

    Code (Multiple DS18B20s)

    Next, upload the provided code. It scans for all devices on GPIO 4 and prints the temperature for each one. (This sketch is based on an example provided by the DallasTemperature library).

    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    // Data wire is plugged TO GPIO 4
    #define ONE_WIRE_BUS 4
    
    // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    OneWire oneWire(ONE_WIRE_BUS);
    
    // Pass our oneWire reference to Dallas Temperature. 
    DallasTemperature sensors(&oneWire);
    
    // Number of temperature devices found
    int numberOfDevices;
    
    // We'll use this variable to store a found device address
    DeviceAddress tempDeviceAddress; 
    
    void setup(){
      // start serial port
      Serial.begin(115200);
      
      // Start up the library
      sensors.begin();
      
      // Grab a count of devices on the wire
      numberOfDevices = sensors.getDeviceCount();
      
      // locate devices on the bus
      Serial.print("Locating devices...");
      Serial.print("Found ");
      Serial.print(numberOfDevices, DEC);
      Serial.println(" devices.");
    
      // Loop through each device, print out address
      for(int i=0;i<numberOfDevices; i++){
        // Search the wire for address
        if(sensors.getAddress(tempDeviceAddress, i)){
          Serial.print("Found device ");
          Serial.print(i, DEC);
          Serial.print(" with address: ");
          printAddress(tempDeviceAddress);
          Serial.println();
        } else {
          Serial.print("Found ghost device at ");
          Serial.print(i, DEC);
          Serial.print(" but could not detect address. Check power and cabling");
        }
      }
    }
    
    void loop(){ 
      sensors.requestTemperatures(); // Send the command to get temperatures
      
      // Loop through each device, print out temperature data
      for(int i=0;i<numberOfDevices; i++){
        // Search the wire for address
        if(sensors.getAddress(tempDeviceAddress, i)){
          // Output the device ID
          Serial.print("Temperature for device: ");
          Serial.println(i,DEC);
          // Print the data
          float tempC = sensors.getTempC(tempDeviceAddress);
          Serial.print("Temp C: ");
          Serial.print(tempC);
          Serial.print(" Temp F: ");
          Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
        }
      }
      delay(5000);
    }
    
    // function to print a device address
    void printAddress(DeviceAddress deviceAddress) {
      for (uint8_t i = 0; i < 8; i++){
        if (deviceAddress[i] < 16) Serial.print("0");
          Serial.print(deviceAddress[i], HEX);
      }
    }
    

    Demonstration

    In this example, we’re using three DS18B20 temperature sensors. The results are displayed on the Arduino IDE Serial Monitor.

    For a detailed guide on interfacing multiple DS18B20 temperature sensors with the ESP32, refer to the next tutorial.

    Display DS18B20 Temperature Readings in a Web Server

    To construct the web server, we’ll utilize the ESPAsyncWebServer library, which offers a straightforward method to develop an asynchronous web server. Creating an asynchronous web server presents several benefits. We suggest referring to the library documentation on its GitHub page for a quick overview.

    Installation of ESPAsyncWebServer and AsyncTCP Libraries

    To create the web server for this project, you must install the following libraries in your Arduino IDE:

    Since the ESPAsyncWebServer, AsyncTCP, and ESPAsyncTCP libraries are not available for installation via the Arduino Library Manager, you’ll need to manually copy the library files to the Libraries folder within your Arduino installation directory. Alternatively, within your Arduino IDE, navigate to Sketch > Include Library > Add .zip Library and select the libraries you’ve recently downloaded.

    Code (DS18B20 Async Web Server)

    Launch your Arduino IDE and copy the code provided below.

    // Import required libraries
    #ifdef ESP32
      #include <WiFi.h>
      #include <ESPAsyncWebServer.h>
    #else
      #include <Arduino.h>
      #include <ESP8266WiFi.h>
      #include <Hash.h>
      #include <ESPAsyncTCP.h>
      #include <ESPAsyncWebServer.h>
    #endif
    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    // Data wire is connected to GPIO 4
    #define ONE_WIRE_BUS 4
    
    // Setup a oneWire instance to communicate with any OneWire devices
    OneWire oneWire(ONE_WIRE_BUS);
    
    // Pass our oneWire reference to Dallas Temperature sensor 
    DallasTemperature sensors(&oneWire);
    
    // Variables to store temperature values
    String temperatureF = "";
    String temperatureC = "";
    
    // Timer variables
    unsigned long lastTime = 0;  
    unsigned long timerDelay = 30000;
    
    // Replace with your network credentials
    const char* ssid = "REPLACE_WITH_YOUR_SSID";
    const char* password = "REPLACE_WITH_YOUR_PASSWORD";
    
    // Create AsyncWebServer object on port 80
    AsyncWebServer server(80);
    
    String readDSTemperatureC() {
      // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
      sensors.requestTemperatures(); 
      float tempC = sensors.getTempCByIndex(0);
    
      if(tempC == -127.00) {
        Serial.println("Failed to read from DS18B20 sensor");
        return "--";
      } else {
        Serial.print("Temperature Celsius: ");
        Serial.println(tempC); 
      }
      return String(tempC);
    }
    
    String readDSTemperatureF() {
      // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
      sensors.requestTemperatures(); 
      float tempF = sensors.getTempFByIndex(0);
    
      if(int(tempF) == -196){
        Serial.println("Failed to read from DS18B20 sensor");
        return "--";
      } else {
        Serial.print("Temperature Fahrenheit: ");
        Serial.println(tempF);
      }
      return String(tempF);
    }
    
    const char index_html[] PROGMEM = R"rawliteral(
    <!DOCTYPE HTML><html>
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
      <style>
        html {
         font-family: Arial;
         display: inline-block;
         margin: 0px auto;
         text-align: center;
        }
        h2 { font-size: 3.0rem; }
        p { font-size: 3.0rem; }
        .units { font-size: 1.2rem; }
        .ds-labels{
          font-size: 1.5rem;
          vertical-align:middle;
          padding-bottom: 15px;
        }
      </style>
    </head>
    <body>
      <h2>ESP DS18B20 Server</h2>
      <p>
        <i class="fas fa-thermometer-half" style="color:#059e8a;"></i> 
        <span class="ds-labels">Temperature Celsius</span> 
        <span id="temperaturec">%TEMPERATUREC%</span>
        <sup class="units">&deg;C</sup>
      </p>
      <p>
        <i class="fas fa-thermometer-half" style="color:#059e8a;"></i> 
        <span class="ds-labels">Temperature Fahrenheit</span>
        <span id="temperaturef">%TEMPERATUREF%</span>
        <sup class="units">&deg;F</sup>
      </p>
    </body>
    <script>
    setInterval(function ( ) {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          document.getElementById("temperaturec").innerHTML = this.responseText;
        }
      };
      xhttp.open("GET", "/temperaturec", true);
      xhttp.send();
    }, 10000) ;
    setInterval(function ( ) {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          document.getElementById("temperaturef").innerHTML = this.responseText;
        }
      };
      xhttp.open("GET", "/temperaturef", true);
      xhttp.send();
    }, 10000) ;
    </script>
    </html>)rawliteral";
    
    // Replaces placeholder with DS18B20 values
    String processor(const String& var){
      //Serial.println(var);
      if(var == "TEMPERATUREC"){
        return temperatureC;
      }
      else if(var == "TEMPERATUREF"){
        return temperatureF;
      }
      return String();
    }
    
    void setup(){
      // Serial port for debugging purposes
      Serial.begin(115200);
      Serial.println();
      
      // Start up the DS18B20 library
      sensors.begin();
    
      temperatureC = readDSTemperatureC();
      temperatureF = readDSTemperatureF();
    
      // Connect to Wi-Fi
      WiFi.begin(ssid, password);
      Serial.println("Connecting to WiFi");
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println();
      
      // Print ESP Local IP Address
      Serial.println(WiFi.localIP());
    
      // Route for root / web page
      server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/html", index_html, processor);
      });
      server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/plain", temperatureC.c_str());
      });
      server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/plain", temperatureF.c_str());
      });
      // Start server
      server.begin();
    }
     
    void loop(){
      if ((millis() - lastTime) > timerDelay) {
        temperatureC = readDSTemperatureC();
        temperatureF = readDSTemperatureF();
        lastTime = millis();
      }  
    }
    

    Replace the placeholder with your network credentials in the following variables, and the code will function seamlessly.

    const char* ssid = "REPLACE_WITH_YOUR_SSID";
    const char* password = "REPLACE_WITH_YOUR_PASSWORD";

    Code Explanation

    Let’s delve into how the code operates. Read on to gain insight into its functionality, or skip ahead to the “Demonstration” section to observe the final outcome.

    Importing libraries

    Initially, import the necessary libraries for the ESP32 board:

    #include <WiFi.h>
    #include <ESPAsyncWebServer.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>

    Instantiate DS18B20 Sensor

    Define the GPIO to which the DS18B20 data pin connects, in this case, it’s linked to GPIO 4.

    #define ONE_WIRE_BUS 4

    Instantiate the required instances to initialize the sensor:

    // Setup a oneWire instance to communicate with any OneWire devices
    OneWire oneWire(ONE_WIRE_BUS);
    
    // Pass our oneWire reference to Dallas Temperature sensor 
    DallasTemperature sensors(&oneWire);

    Setting your network credentials

    Insert your network credentials into the following variables, enabling the ESP8266 to connect to your local network.

    const char* ssid = "REPLACE_WITH_YOUR_SSID";
    const char* password = "REPLACE_WITH_YOUR_PASSWORD";

    Create an AsyncWebServer object on port 80.

    AsyncWebServer server(80);

    Read Temperature Functions

    Then, we create two functions to read the temperature.

    The readDSTemperatureC() function returns the readings in Celsius degrees.

    String readDSTemperatureC() {
      // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
      sensors.requestTemperatures(); 
      float tempC = sensors.getTempCByIndex(0);
    
      if(tempC == -127.00){
        Serial.println("Failed to read from DS18B20 sensor");
        return "--";
      } else {
        Serial.print("Temperature Celsius: ");
        Serial.println(tempC); 
      }
      return String(tempC);
    }

    In case the sensor is not able to get a valid reading, it returns -127. So, we have an if statement that returns two dashes (–-) in case the sensor fails to get the readings.

    if(tempC == -127.00){
      Serial.println("Failed to read from DS18B20 sensor");
      return "--";

    The reaDSTemperatureF() function works in a similar way but returns the readings in Fahrenheit degrees.

    The readings are returned as string type. To convert a float to a string, use the String() function.

    return String(tempC);

    Building the Web Page

    The next step is building the web page. The HTML and CSS needed to build the web page are saved on the index_html variable.

    In the HTML text we have TEMPERATUREC and TEMPERATUREF between % signs. This is a placeholder for the temperature values.

    This means that this %TEMPERATUREC% text is like a variable that will be replaced by the actual temperature value from the sensor. The placeholders on the HTML text should go between % signs.

    We’ve explained in great detail how the HTML and CSS used in this web server works in a previous tutorial. So, if you want to learn more, refer to the next project:

    Processor

    Now, we need to create the processor() function, that will replace the placeholders in our HTML text with the actual temperature values.

    String processor(const String& var){
      //Serial.println(var);
      if(var == "TEMPERATUREC"){
        return readDSTemperatureC();
      }
      else if(var == "TEMPERATUREF"){
        return readDSTemperatureF();
      }
      return String();
    }

    When the web page is requested, we check if the HTML has any placeholders. If it finds the %TEMPERATUREC% placeholder, we return the temperature in Celsius by calling the readDSTemperatureC() function created previously.

    if(var == "TEMPERATUREC"){
      return readDSTemperatureC();
    }

    If the placeholder is %TEMPERATUREF%, we return the temperature in Fahrenheit.

    else if(var == "TEMPERATUREF"){
      return readDSTemperatureF();
    }

    setup()

    In the setup(), initialize the Serial Monitor for debugging purposes.

    Serial.begin(115200);

    Initialize the DS18B20 temperature sensor.

    sensors.begin();

    Connect to your local network and print the ESP32 IP address.

    WiFi.begin(ssid, password);
    Serial.println("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println();
    
    // Print ESP8266 Local IP Address
    Serial.println(WiFi.localIP());

    Finally, add the next lines of code to handle the web server.

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/html", index_html, processor);
    });
    server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/plain", readDSTemperatureC().c_str());
    });
    server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/plain", readDSTemperatureF().c_str());
    });

    When we make a request on the root URL, we send the HTML text that is stored in the index_html variable. We also need to pass the processor function, that will replace all the placeholders with the right values.

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/html", index_html, processor);
    });

    We need to add two additional handlers to update the temperature readings. When we receive a request on the /temperaturec URL, we simply need to send the updated temperature value. It is plain text, and it should be sent as a char, so, we use the c_str() method.

    server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/plain", readDSTemperatureC().c_str());
    });

    The same process is repeated for the temperature in Fahrenheit.

    server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send_P(200, "text/plain", readDSTemperatureF().c_str());
    });

    Lastly, we can start the server.

    server.begin();

    Because this is an asynchronous web server, we don’t need to write anything in the loop().

    void loop(){
    
    }

    That’s pretty much how the code works.

    Demonstration

    Once the code is uploaded, launch the Arduino IDE Serial Monitor at a baud rate of 115200. Press the ESP32 on-board RST button, and after a few seconds, your IP address should appear.

    Within your local network, open a web browser and enter the ESP32 IP address.

    Now, you’ll be able to view the temperature in both Celsius and Fahrenheit on your web server. The sensor readings will automatically update without requiring you to refresh the web page.

    Wrapping Up

    We trust you’ve found this tutorial valuable. We have guides for various other sensors and modules compatible with the ESP32 that you might find helpful:

    Leave a Comment