Temperature measurement with several DS18B20 probes, Arduino code compatible ESP8266 and ESP32, publication on Domoticz in HTTP

If you want to create a temperature measurement network using an Arduino or ESP8266, the OneWire DS18B20 probes are ideal. The OneWire is a digital data bus that requires only one wire. The OneWire bus can address up to 100 devices with a single wire. There are many tutorials on the Internet that explain how to implement DS18B20 probes with Arduino code. We will not reinvent the wheel here. You have been several to contact me to ask me an example using several DS18B20 sensors and how to publish the measurements on a home automation server. That’s what we’re going to do here. I propose instead a methodology to identify the sensors, read the measurements and send them to a home automation server using an HTTP request. In the next tutorial, we will see how to do with MicroPython code. If you have other needs, do not hesitate to ask me in the comments.

Necessary material

For this tutorial, I adapted the Arduino code that came with the Arduino OneWire and DallasTemperature libraries. I tested the code on an ESP32 and more particularly on the Wemos LoLin32 Lite and the Wemos d1 mini based ESP8266. The libraries are therefore compatible with ESP8266 and ESP32 WiFi modules last generation which is much more convenient to send measurements to a home automation server.

Attention for the ESP8266, it is necessary to install the SDK Espressif, the Chinese company that develops micro-controllers. Follow this tutorial to install the ESP8266 SDK and this one for the ESP32 SDK for the Arduino IDE.
Last update was on: 20 October 2018 20 h 08 min

Multiple connection of Dallas DS18B20 probes

The connection is very simple. The One-Wire bus is usually located on a yellow wire. Red is used for power, black for GND as usual. For the bus to work, it must be “de-wormed”. For this, a resistor (4K7 in general) is placed between the +5V and the data bus. I also tried other resistors (5K7) and a power supply +3V3 successfully. Obviously, everything will depend on the cable length. The longer the cabling, the more rigorous it will be to supply the power and the de-interference of the signal.

For this tutorial, the DS18B20 is plugged into pin 4 of the ESP8266. You can also use all the codes in this tutorial on an Arduino Uno or ESP32.

Scan DS18B20 probe addresses, Arduino code (compatible ESP8266 and ESP32)

The first thing to do is to identify the probes. Each probe has a unique 8-bit identifier. Unfortunately, it is never indicated on the packaging. It’s up to us to do it manually. Here is a small scanner that retrieves the addresses of DS18B20 probes. It scans the OneWire bus every 2 seconds for connected probes. It is possible to add “hot” sensors without having to restart the program.

/*
 * One Wire scanner
 * Testé sur la carte ESP32 Wemos LoLin32 Lite | Checked on Wemos LoLin32 Lite development board
 * Code inspiré de l'exemple livré avec la librairie Arduino DallasTemperature 
 * Code inspired by DallasTemperature Aduino library from
 * http://milesburton.com/Dallas_Temperature_Control_Library
 */
#include <OneWire.h>
// Bus OneWie connecté sur la broche 4 | OneWire bus connected on Pin 4
// Installer une résistance de 4.7K entre le +5V et le cable de données
// A 4.7K resistor is necessary between +5V and Data wire  
OneWire  ds(4);  

byte i;
byte type_s;
byte data[12];
byte addr[8];
  
void OneWireScanner(){
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    return;
  }
  
  Serial.print("ROM = ");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print("0x");
    Serial.print(addr[i], HEX);
    if ( i != 7 ) {
      Serial.print(", ");
    }
  }
  
  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  } 
}

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

void loop() {
  // put your main code here, to run repeatedly:
  OneWireScanner();
  delay(5000);
}

Open the Arduino IDE, create a new sketch and paste the code above. Modify the pin to which the DS18B20 sensor will be connected. Then open the Library Manager, Sketch -> Include Library -> Manage Libraries. Do a search on the OneWire keyword and then install the OneWire library

Upload the program and open the serial monitor. Here is the execution log with two DS18B20 probes. Uncheck the “Auto Scroll” option. You can easily copy the address of each probe to include it in your project. In practice, I advise you to successively connect the probes to identify and stick a label bearing its address, for example (28-D4-B0-26-00-00-80-BC)

ROM =  0x28,  0xD4,  0xB0,  0x26,  0x0,  0x0,  0x80,  0xBC
  Chip = DS18B20
ROM =  0x28,  0xF4,  0xBC,  0x26,  0x0,  0x0,  0x80,  0x2B
  Chip = DS18B20
No more addresses.

Individual reading of the temperature of several DS18B20 probes, compatible Arduino code ESP8266 and ESP32

Now that each temperature sensor is identified, we will use the DallasTemperature library that adds some very useful methods for managing DS18B20 sensors. Return to the library manager to install the DallasTemperature library.

Create a new sketch and paste the code below. Specify the pin to which the One-Wire data bus is attached using the ONE_WIRE_BUS constant. You can change the accuracy of the measurement with the TEMPERATURE_PRECISION constant. By default, it is returned on 10 bits. Finally, replace the addresses of your probes for insideThermometer and outsideThermometer.

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

// Data wire is plugged into port 4 on the Arduino or ESP32
#define ONE_WIRE_BUS 4
#define TEMPERATURE_PRECISION 10

// 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);

// Tableaux contenant l'adresse de chaque sonde OneWire | arrays to hold device addresses
DeviceAddress insideThermometer = { 0x28,  0xD4,  0xB0,  0x26,  0x0,  0x0,  0x80,  0xBC };
DeviceAddress outsideThermometer = { 0x28,  0xF4,  0xBC,  0x26,  0x0,  0x0,  0x80,  0x2B };

void setup() {
  Serial.begin(115200);
  
  // Start up the library
  sensors.begin();

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // Vérifie sir les capteurs sont connectés | check and report if sensors are conneted 
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 

  // set the resolution to 9 bit per device
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);

  // On vérifie que le capteur st correctement configuré | Check that ensor is correctly configured
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

  Serial.print("Device 1 Resolution: ");
  Serial.print(sensors.getResolution(outsideThermometer), DEC); 
  Serial.println();
}

void printTemperature(String label, DeviceAddress deviceAddress){
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(label);
  if (tempC == -127.00) {
    Serial.print("Error getting temperature");
  } else {
    Serial.print(" Temp C: ");
    Serial.print(tempC);
    Serial.print(" Temp F: ");
    Serial.println(DallasTemperature::toFahrenheit(tempC));
  }  
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures();
  Serial.println("DONE");

  // print the device information
  printTemperature("Inside : ", insideThermometer);
  printTemperature("Outside : ", outsideThermometer);
  
  delay(5000);
}

How does the code work?

The DallasTemperature library is expecting a OneWire object that is attached to the ESP32 (or Arduino) pin. Here is the pin n ° 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);

The DallasTemperature library allows to define an address for each probe (which we did previously). Here, we will define an inner (Inside) and outer (Outside) probe. It is a DeviceAdress variable that expects an array of hexadecimal values

DeviceAddress insideThermometer = {0x28, 0xD4, 0xB0, 0x26, 0x0, 0x0, 0x80, 0xBC};
DeviceAddress outsideThermometer = {0x28, 0xF4, 0xBC, 0x26, 0x0, 0x0, 0x80, 0x2B};

In the setup loop, the sensors.begin () method is used to start the communication with the probes. Now, we can read the temperature on a particular probe at any time, for the outside temperature, this will give for example

sensors.requestTemperatures();                         // Demande la lecture de toutes les sondes | Request all temperatures from probes
float tempC = sensors.getTempC(outsideThermometer);    // Récupère la température de la sonde extérieure | Get temperature from outside probe
Serial.print(" Temp C: ");                             // Imprime la temperature (par défaut en °C | Print outside temp. By default in Celcius
Serial.print(tempC);

The DallasTemperature bookseller offers other useful methods here. Everything is available in the source code on GitHub

// returns the number of devices found on the bus
uint8_t getDeviceCount(void);

// returns true if address is valid
bool validAddress(const uint8_t*);

// returns true if address is of the family of sensors the lib supports.
bool validFamily(const uint8_t* deviceAddress);

// finds an address at a given index on the bus
bool getAddress(uint8_t*, uint8_t);

// attempt to determine if the device at the given address is connected to the bus
bool isConnected(const uint8_t*);

// attempt to determine if the device at the given address is connected to the bus
// also allows for updating the read scratchpad
bool isConnected(const uint8_t*, uint8_t*);

// read device's scratchpad
bool readScratchPad(const uint8_t*, uint8_t*);

// write device's scratchpad
void writeScratchPad(const uint8_t*, const uint8_t*);

// read device's power requirements
bool readPowerSupply(const uint8_t*);

// get global resolution
uint8_t getResolution();

// set global resolution to 9, 10, 11, or 12 bits
void setResolution(uint8_t);

// returns the device resolution: 9, 10, 11, or 12 bits
uint8_t getResolution(const uint8_t*);

// set resolution of a device to 9, 10, 11, or 12 bits
bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false);

// sets/gets the waitForConversion flag
void setWaitForConversion(bool);
bool getWaitForConversion(void);

// sets/gets the checkForConversion flag
void setCheckForConversion(bool);
bool getCheckForConversion(void);

// sends command for all devices on the bus to perform a temperature conversion
void requestTemperatures(void);

// sends command for one device to perform a temperature conversion by address
bool requestTemperaturesByAddress(const uint8_t*);

// sends command for one device to perform a temperature conversion by index
bool requestTemperaturesByIndex(uint8_t);

// returns temperature raw value (12 bit integer of 1/128 degrees C)
int16_t getTemp(const uint8_t*);

// returns temperature in degrees C
float getTempC(const uint8_t*);

// returns temperature in degrees F
float getTempF(const uint8_t*);

// Get temperature for device index (slow)
float getTempCByIndex(uint8_t);

// Get temperature for device index (slow)
float getTempFByIndex(uint8_t);

// returns true if the bus requires parasite power
bool isParasitePowerMode(void);

// Is a conversion complete on the wire?
bool isConversionComplete(void);

int16_t millisToWaitForConversion(uint8_t);

Program test with two DS18B20 probes

Upload the program and open the serial monitor. The individual reading of each probe is immediate.

Inside: Temp C: 18.00 F Temp: 64.40
Outside: Temp C: 18.25 Temp F: 64.85
Requesting temperatures ... DONE

If you disconnect one of the probes, an error message is displayed next to the faulty probe. It is very easy to send an email to indicate that a probe is defective. To test the probes, one also has the method isConnected (probe_address) of the DallasTemperature library. The One-Wire bus runs hot. As soon as you reconnect the probe, it is automatically detected and the temperature reading is immediate. It’s really very practical. We could imagine a small web interface to manage the probes without having to recompile the program as soon as we add a new probe. By going further, you can read this series of articles on the creation of an WEB interface for DIY projects based on ESP8266

Inside :  Temp C: 18.00 Temp F: 64.40
Outside : Error getting temperature

Publishing temperatures on a Domoticz server by HTTP request

All that remains is to send the data to a home automation server. Here we will take the example of Domoticz which has a JSON interface (API). The format of the HTTP request is the following for a temperature type measurement (the documentation of the API is detailed here). For more details, read this previous article or this one to do the same thing with Jeedom.

Attention for the ESP8266, it is necessary to install the SDK Espressif, the Chinese company that develops micro-controllers. Follow this tutorial to install the ESP8266 SDK and this one for the ESP32 SDK for the Arduino IDE.

Start by going to the Domoticz server to create two virtual devices of the temperature type and get the Idx of each probe. Follow this tutorial to learn how to do it.

domoticz ds18b20 esp8266 esp32 arduino idx device sensor

The following code is compatible with Arduino, ESP8266 and ESP32. Several parameters must be modified in the code before uploading it:

  • Specify the One Wire bus pin on the constant ONE_WIRE_BUS
  • Replace probe addresses, insideThermometer and outsideThermometer
  • The WiFi network on which to connect with the constant wifi_ssid, as well as the password
  • Domoticz server IP address, host variable, connection port (default 8080)
  • The Domoticz Idx for each IDX_insideTemp and IDX_outsideTemp probe
/*
 * Read multiple One-Wire DS18B20 probes and publish value on Domoticz with HTTP request
 * Lecture multiple de sonde OneWire DS18B20 et plublication des mesures sur un serveur Domoticz requete HTTP
 * Code adapté - Code adaptated 
 * 
 */
#include <OneWire.h>
#include <DallasTemperature.h>
// Pour un Arduino ou ESP32 (le SDK Espressif doit être installé) | For Arduino or ESP32 (Espressif SDK must be installed) 
#include <WiFi.h>
#include <HTTPClient.h>
// Pour une carte ESP8266 | For ESP8266 development board
//#include <ESP8266WiFi.h>
//#include <ESP8266HTTPClient.h>
#include <PubSubClient.h>

// Data wire is plugged into port 4 on the Arduino or ESP32
#define ONE_WIRE_BUS 4
#define TEMPERATURE_PRECISION 10

// 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);

// Tableaux contenant l'adresse de chaque sonde OneWire | arrays to hold device addresses
DeviceAddress insideThermometer = { 0x28,  0xD4,  0xB0,  0x26,  0x0,  0x0,  0x80,  0xBC };
DeviceAddress outsideThermometer = { 0x28,  0xF4,  0xBC,  0x26,  0x0,  0x0,  0x80,  0x2B };

// Parametres WIFI - WiFi settings
#define wifi_ssid "xxxxxxxx"
#define wifi_password "xxxxxxxx"

// Paramètres HTTP Domoticz - HTTP Domoticz settings
const char* host = "xxx.xxx.xxx.xxx";
const int   port = 8080;
#define IDX_insideTemp    24
#define IDX_outsideTemp   25 
HTTPClient http;

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

  // Connexion au réseau WiFi, connexion aux sondes
  // Start WiFi connexion and probes
  setup_wifi();           
  sensors.begin();

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // Vérifie sir les capteurs sont connectés | check and report if sensors are conneted 
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 

  // set the resolution to 9 bit per device
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);

  // On vérifie que le capteur st correctement configuré | Check that ensor is correctly configured
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

  Serial.print("Device 1 Resolution: ");
  Serial.print(sensors.getResolution(outsideThermometer), DEC); 
  Serial.println();
}

void printTemperature(String label, DeviceAddress deviceAddress){
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(label);
  if (tempC == -127.00) {
    Serial.print("Error getting temperature");
  } else {
    // Format JSON à respecter pour l'API Domoticz - Domoticz JSON API 
    // /json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=TEMP
    // https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature
    if ( label == "Inside : " ) {
      String url = "/json.htm?type=command&param=udevice&idx=";
        url += String(IDX_insideTemp);
        url += "&nvalue=0&svalue=";    
        url += String(tempC); 
      sendToDomoticz(url);
    } else {
      String url = "/json.htm?type=command&param=udevice&idx=";
        url += String(IDX_outsideTemp);
        url += "&nvalue=0&svalue=";    
        url += String(tempC);  
      sendToDomoticz(url);
    }
  }  
}

void loop() {

  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures();
  Serial.println("DONE");

  // print the device information
  printTemperature("Inside : ", insideThermometer);
  printTemperature("Outside : ", outsideThermometer);
  
  delay(5000);
}

//Connexion au réseau WiFi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connexion OK ");
  Serial.print("=> Addresse IP : ");
  Serial.print(WiFi.localIP());
}


void sendToDomoticz(String url){
  Serial.print("Connecting to ");
  Serial.println(host);
  Serial.print("Requesting URL: ");
  Serial.println(url);
  http.begin(host,port,url);
  int httpCode = http.GET();
    if (httpCode) {
      if (httpCode == 200) {
        String payload = http.getString();
        Serial.println("Domoticz response "); 
        Serial.println(payload);
      }
    }
  Serial.println("closing connection");
  http.end();
}

Now, you can now add DS18B20 probes to your Arduino, ESP8266 or ESP32 connected object projects quite quickly. We find the DS18B20 in the form of a 3-pin housing or most often pre-wired in a waterproof stainless steel case. It can for example be used to regulate a heating with an indoor temperature sensor and an outdoor sensor. The stainless steel case is very suitable for monitoring the temperature in humid or dusty environments (fridge, freezer, swimming pool, aquarium …), environments inaccessible to the usual sensors (DHT22, DHT12 on I2C bus …). If you have no notion of programming, the DS18B20 is also supported by the ESP Easy firmware on ESP8266 and now on ESP32.

 

 

DS18B20 Temperature Sensor for Arduino Lovers
$0.99
Waterproof Digital Thermal Probe or Sensor DS18B20 Length:1M
$1.53
DS18B20 Temperature Sensor - Black + Silver
$1.60
Buy this item
DealExtreme
-10% 1pcs Waterproof Digital Thermal Probe or Sensor DS18B20 DS18B20 Sensor
$1.60 $1.78
Buy this item
AliExpress
Water Proof DS18b20 Temperature Probe - Black (90cm)
$2.26
Buy this item
DealExtreme
90cm Cable DS18B20 Chip Temperature Probe for Thermostatic Controls (3.0 - 5.5V)
$2.39
DIY DS18B20 Stainless Steel Temperature Sensor Probe - Black
$2.58
Buy this item
DealExtreme
400pcs Metal Film Resistor Assortment Kit Set 20 Kinds Value
$2.69
Geekcreit® 3 IN 1 120pcs 10cm Male To Female Female To Female...
$2.85
Geekcreit® UNO R3 ATmega328P Development Board For Arduino No Cable
$3.19
Stainless Steel Waterproof Digital Temperature Thermal Probe or Sensor DS18B20 1M
$3.27
Buy this item
TOMTOP Technology Co., Ltd
DS18B20 Temperature Sensor 18B20 TO-92 Encapsulation
$5.33
DS18B20 Waterproof Digital Temperature Temp Sensor Probe
$5.42
WeMos® D1 mini V2.2.0 WIFI Internet Development Board Based ESP8266 4MB FLASH...
$8.84
5pcs DS18b20 Waterproof Temperature Sensors Temperature Transmitter
$10.74
Buy this item
Newfrog.com
Diymore 5Pcs DALLAS 18B20 DS18B20 TO-92 3 Pins Wire Digital Thermometer Temperature...
$10.88
Buy this item
Amazon.com
Wemos® ESP-WROOM-32 Rev1 ESP32 OLED Board 4 Mt Bytes(32 Mt bit) Flash...
$10.99
ELENKER 5PCS Waterproof Temperature Probe Thermometer DS18B20 1M with Heat Resistance Thermal...
$10.99
Buy this item
Amazon.com
Wemos® SX1278 LoRa ESP32 Bluetooth WIFI Lora Internet Antenna Development Board For...
$11.39
KT003 Arduino UNO Starter Kit with Bread Plate / Sensor / LED...
$24.93

 

Subscribe to the weekly newsletter

No spam and no other use will be made of your email. You can unsubscribe anytime.

Tags:

  • Misiu

    Are You sure the wiring is fine? Please take a look at: http://www.instructables.com/id/Simple-Example-ArduinoESP8266DS18B20/
    I’ve tried Your way and DS18B20 got very hot :/

    • Hello Misui. I think yes. Now I have a doubt :O. In any case, I did not observe any heating of my sensors. I power the sensors in 3V3. You too ?

      • Misiu

        Hi there, I’very used 5V. In my case when I used Your schema I was unable to find sensor using 1wire sensor. I had to switch GND and power and then it worked fine. Have You looked at attached pinout?

        • Hello Misiu and happy new year ! Yes I looked but as you can see on the technical documentation https://cdn.sparkfun.com/datasheets/Sensors/Temp/DS18B20.pdf, we can power the ds18b20 between 3V and 5V. So it is not necessary to put a resistor to decrease the voltage. By cons you may have bought a clone or your sensor may be defective. Do you have other sensors to test?

          • Misiu

            In datasheet You attached GND is far left pin, but in Your schema GND is far right pin. (please look at my attached image from previous comment, datasheet You linked and compare it with first schema in this post)
            I switched VDD and GND and everything worked fine.

            Please correct that schema. Voltage isn’t the problem and Yes, looking at datasheet I can confirm that it should work with 3.3V.

          • Oh yes, excuse me Misui. I used ds18b20 waterproof and I was wrong when I did the wiring scheme. It’s corrected. See you soon

          • Misiu

            That looks much better 🙂 Thanks for fix and for article. It really helped me getting started with DS18B20.
            I’ve bookmarked Your site so I’ll definitively come back! 🙂

          • Thank you very much Misiu 😀

DIY Projects