Learn how to interface the Raspberry Pi with the DS18B20 temperature sensor and how to get temperature readings using a Python program.
Table of Contents
Throughout this tutorial, we’ll cover the following main topics:
- Introducing the DS18B20 Temperature Sensor
- Wiring the DS18B20 Temperature Sensor to the Raspberry Pi
- Enabling One-Wire on the Raspberry Pi
- Testing the Temperature Sensor
- Getting Sensor Readings from the DS18B20 – Python Script
Prerequisites
Before continuing with this tutorial, check the following prerequisites.
- Get familiar with the Raspberry Pi board—if you’re not familiar with the Raspberry Pi, you can read our Raspberry Pi Getting Started Guide here.
- You must know how to run and create Python files on your Raspberry Pi. We like to program our Raspberry Pi via SSH using an extension in VS Code. We have a detailed tutorial about that subject: Programming Raspberry Pi Remotely using VS Code (Remote-SSH).
- Know how to use the Raspberry Pi GPIOs so that you know how to wire the circuit properly. Read the following tutorial: Raspberry Pi Pinout Guide: How to use the Raspberry Pi GPIOs?
Introducing DS18B20 Temperature Sensor
The DS18B20 temperature sensor is a one-wire digital temperature sensor. This means that it just requires one data line (and GND) to communicate with your ESP32.
It can be powered by an external power supply or it can derive power from the data line (called “parasite mode”), which eliminates the need for an external power supply.
Each DS18B20 temperature sensor has a unique 64-bit serial code. This allows you to wire multiple sensors to the same data wire. So, you can get temperature from multiple sensors using just one GPIO.
The DS18B20 temperature sensor is also available in waterproof version.
Here’s a summary of the most relevant specs of the DS18B20 temperature sensor:
- Communicates over one-wire bus communication
- Power supply range: 3.0V to 5.5V
- Operating temperature range: -55ºC to +125ºC
- Accuracy +/-0.5 ºC (between the range -10ºC to 85ºC)
For more information consult the DS18B20 datasheet.
Parts Required
To follow this tutorial you need the following parts:
- Raspberry Pi Board – read Best Raspberry Pi Starter Kits
- DS18B20 temperature sensor – waterproof version
- 4.7k Ohm resistor
- Jumper wires
- Breadboard
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Wiring a DS18B20 Temperature Sensor to the Raspberry Pi
The DS18B20 temperature sensor comes with three pins: GND, data, and VCC. The DS18B20 temperature sensor can be powered through the VDD pin (normal mode), or it can derive its power from the data line (parasite mode). You can choose either mode. We prefer using the normal mode.
If you’re using the waterproof version, you can identify each pin by its color:
- black: GND
- red: VDD
- yellow: data line
The DS18B20 temperature sensor communicates using one-wire communication protocol. The Raspberry Pi supports one-wire on any GPIO pin, but the default is GPIO 4. So, we’ll wire the data pin of the sensor to GPIO 4. If you need to use another GPIO, see one of the following sections to learn how to enable the one-wire bus on a different pin.
DS18B20 | Raspberry Pi Pico |
GND | GND |
Data (DQ) | Default one-wire pin ins GPIO 4 you also need to connect a 4.7KOhm resistor between the data line and VCC |
VDD | 3V3(OUT) |
Enable One-Wire Communication on the Raspberry Pi
To enable the one-wire interface, open a Terminal window on your Raspberry Pi (for example, via SSH), type the following command and press Enter.
sudo raspi-config
The following menu will open. Select Interface Options:
Select 1-wire.
And enable it.
Finally, select Finish, and then reboot the Raspberry Pi.
Enabling one-wire on a different GPIO (not default)
The default one-wire GPIO for the Raspberry Pi is GPIO 4. If you want to enable the one-wire bus on a different pin, you need to run the following commands.
Open and edit the config.txt file using:
sudo nano /boot/config.txt
Add the following line at the end of the file, in which x is the GPIO you want to use for one-wire:
dtoverlay=w1-gpio,gpiopin=x
For example, if you want to enable one-wire on GPIO22, it would be as follows:
dtoverlay=w1-gpio,gpiopin=22
Press CTRL-X, then press Y and Enter to save the changes.
Reboot your Raspberry Pi with:
sudo reboot
Testing the DS18B20 Temperature Sensor
With the sensor wired to your Raspberry Pi, let’s just test that it can find the sensor and report the readings before writing the Python code.
Run the following commands on a terminal window:
This command loads the w1-gpio kernel module, which is responsible for enabling the GPIO pin for one-wire communication:
sudo modprobe w1-gpio
Then, the following line loads the w1-therm kernel module, which adds support for DS18B20-specific features, such as reading temperature data from the sensor.
sudo modprobe w1-therm
Then, change the current working directory to /sys/bus/w1/devices/. In this directory, it exposes information about connected one-wire devices, including the DS18B20 sensor (if it can find the sensor).
cd /sys/bus/w1/devices/
Finally, list the contents of the devices folder that should show one or more directories, each representing a one-wire device.
ls
In the case of the DS18B20 temperature sensor, you’ll see a folder like 28-xxxxxxxxxxxx, where xxxxxxxxxxxx is the unique address of your DS18B20 sensor.
Navigate to the directory representing the DS18B20 sensor. For example, in my case it’s as follows (use the directory of your sensor):
cd 28-03173311a0ff
After navigating to the directory representing the DS18B20 sensor, you can use the cat command to read the contents of the w1_slave file. This file contains the raw temperature data in a specific format.
cat w1_slave
The contents of the w1_slave file will look something as shown in the next screenshot (first line contains the status of the reading: YES means a valid reading, and the second line shows the temperature (you need to divide by 1000 to get it in degrees Celsius).
If everything went smoothly until now, you are ready to write the Python program to get the readings.
Raspberry Pi with DS18B20 – Getting Temperature Readings (Python Script)
The following script prints temperature readings in the shell from the DS18B20 temperature sensor. The readings are printed both in Celsius and Fahrenheit degrees.
Create a new Python file called temp-ds18b20.py and copy the following code.
# Complete Project Details: https://RandomNerdTutorials.com/raspberry-pi-ds18b20-python/
# Based on the Adafruit example: https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Raspberry_Pi_DS18B20_Temperature_Sensing/code.py
import os
import glob
import time
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
while True:
print(read_temp())
time.sleep(1)
How the Code Works
In this code, we’ll basically reproduce the previous steps on the Python script to get the readings, and we’ll display them on the Python shell.
Start by importing the required libraries:
import os
import glob
import time
The os library allows you to interact with the operating system, and in this code, it’s used to execute system commands (os.system) to load the required kernel modules for 1one-wire communication with the DS18B20 sensor (similar to what we did on the Terminal before).
The glob library helps find files or directories that match a specific pattern, and it’s used here to locate the directory representing the DS18B20 sensor based on its unique address prefix.
The time library is used to introduce delays in the code to give enough time for the sensor to get valid readings.
Next, load the following kernel modules (w1-gpio and w1-therm) to interface with the DS18B20 sensor via one-wire communication protocol. These commands use the os.system function to execute shell commands within Python
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
The following lines set up paths and filenames for reading the temperature data:
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
- base_dir represents the directory where the one-wire devices are located under the /sys filesystem.
- device_folder is obtained using the glob.glob function, which searches for directories matching the pattern ’28*’. The DS18B20 sensors typically have a unique address starting with 28. This ensures that the code finds the correct folder representing the DS18B20 sensor connected to the Raspberry Pi.
- device_file represents the path to the w1_slave file that contains the raw temperature data.
The function read_temp_raw() gets the temperature readings from the w1_slave file (that’s the place where those are stored). This function opens the w1_slave file, reads its contents line by line, and then returns a list containing the lines.
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
Finally, the read_temp() function reads the temperature data.
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
First, it checks if it can find a “YES” in the first line as we’ve seen previously. If the data is not valid, it waits for 0.2 seconds and retries until a valid reading is obtained.
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
The function then extracts the temperature value from the second line after t= and converts it to Celsius (temp_c) and Fahrenheit (temp_f). It returns both temperature values. As we’ve seen previously, we need to divide by 1000 to get the temperature in Celsius degrees. Then, we just need to convert that value to Fahrenheit.
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
Finally, we have a loop (while True) that calls the read_temp() function to get the temperature in Celsius and Fahrenheit, then prints the values with two decimal places. The loop runs indefinitely, with a one-second delay between each temperature reading.
while True:
temperature_celsius, temperature_fahrenheit = read_temp()
print(f'Temperature: {temperature_celsius:.2f} °C')
print(f'Temperature: {temperature_fahrenheit:.2f} °F')
print('')
time.sleep(1)
Demonstration
Save your Python file. Then run it on your Raspberry Pi. Run the following command on the directory of your project file (use the name of your file):
python temp_ds18b20.py
After running the script, new temperature readings will be published in the Python shell every second. Touch the sensor to see the temperature increasing. It will display the readings both in Celsius and Fahrenheit degrees.
Wrapping Up
In this tutorial, you learned how to get temperature readings from the DS18B20 and print the results on the Python shell.
We hope you found this tutorial useful. We have tutorials for other popular sensors:
- Raspberry Pi: BME280 Temperature, Humidity and Pressure Sensor (Python)
- Raspberry Pi: DHT11/DHT22 Temperature and Humidity (Python)
- Raspberry Pi: Detect Motion using a PIR Sensor with Python
You can check all our Raspberry Pi projects on the following link:
Thanks for reading.
I have modified the code to read multiple sensors. The trouble is the function randomly returns a value of 85c. Any suggestions?
#!/usr/bin/python3
import os
import glob
import time
base_dir = ‘/sys/bus/w1/devices/’
os.system(‘modprobe w1-gpio’)
os.system(‘modprobe w1-therm’)
device_folder = glob.glob(base_dir + ’28‘)
NumDev=(len(glob.glob(base_dir + ’28‘)))
#values=range(NumDev)
def read_temp_raw(device):
f = open(device, ‘r’)
lines = f.readlines()
f.close()
return lines
def read_temp(device):
global temp_c
lines = read_temp_raw(device)
while lines[0].strip()[-3:] != ‘YES’:
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find(‘t=’)
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
#list comprehension
device_file = [x + ‘/w1_slave’ for x in device_folder]\
print(‘Found ‘,NumDev,’Sensors’)
for a in device_file:
print(read_temp(a))
#print(read_temp(device))
Did you ever figure this one out? I have the one sensor setup working fine, but would like to have 2 sensors (two aquariums).
I haven’t had a issue since I replaced the 4.7k ohm pull with a 2.2k I am powering my 1-wire buss with 3.3v and not parasitic.
HI? Great job !
Are you try to use the parasite mode to supply ?
Tks
Hi.
Yes. I tried, but I get better results with “normal” mode.
You can try both ways and see which one works best for your scenario.
Regards,
Sara
Hi,
ended up here following the comments of one of my students. Great work, I especially like the description of the hardware setup.
I think the code has a possible pitfall: when the RPi has seen two sensors of the same family, this code might return the the data of a sensor that has been removed (e.g. replaced due to damage). This is not a scenario where two sensor are on the bus, but a maintenance scenario when only one sensor is deployed.
Furthermore, for people who are just interested in getting things done, pypi.org/project/w1thermsensor/ might be a better starting point.
Thanks for sharing this info.
Regards,
Sara