Digital temperature sensor DS18B20 are very popular among hobbyist because they are quite cheap, provide satisfactory precision for number of applications and can be easily interfaced with microcontrollers or Raspberry Pi. In this article we are going to explain how to periodically measure temperature with DS18B20 sensors that are attached to Raspberry Pi. This is quite common situation in number of different applications (like house monitoring, drying process monitoring, etc.). The measured values are stored to MySql database for later examination.
DS18B20 has an operating temperature range of -55°C to +125°C and is accurate to ±0.5°C over the range of -10°C to +85°C. The most popular are those in TO-92 package as shown in image below. The sensors has three pins: VDD, GND and DQ (data input/output line). The power supply range is between 3.0 V and 5.5 V so can be easily interfaced to the 5V and 3.3V microcontrollers. In addition, it can be powered from DQ line (parasite power) so only two wires are needed. For communication with the sensor over DQ line 1-wire protocol is used. Each DS18B20 sensors has a unique 64-bit serial code. Therefore, you can connect number of them on same line.
When connecting multiple sensors to device like microcontroller or Raspberry Pi, the sensors should be connected in a bus like fashion. Basically, this means that one cable with three wires is deployed and the sensors are attached to it at desired locations. Each sensor should be connected to the bus with wires as short as possible. In 1-wire communication, the bus is in idle state at high level. Therefore, you have to connect pull-up resistor (about 5k) between VDD and DQ line.
In our setup we have connected three DS18B20 sensors to Raspberry Pi. The bus consists of three wires which are connected to the 3.3V, GPIO4 and GND pin on Raspberry Pi GPIO header and to appropriate pins of each sensor. Pull-up resistor of 4.7k is connected between 3.3V and GPIO4.
We wrote simple python script which gets sensor readings from DS18B20 sensors every 10 minutes and store the readings to MySql database. Let's first prepare the database. Install MySql and python module for accessing database by running the following command in shell:
sudo apt-get install mysql-server python-mysqldb
After completing the installation, log into MySql:
sudo mysql -u root -p
Inside MySql create database:
CREATE DATABASE TempLog;
and table which will have sensor ID, date stamp, time stamp and measured value columns:
USE TempLog; CREATE TABLE DS18B20( measurement_id INT NOT NULL AUTO_INCREMENT, sensor_id INT NOT NULL, date DATE NOT NULL, time TIME NOT NULL, value varchar(50), PRIMARY KEY ( measurement_id ));
Make one user which can write the sensor readings to this database:
GRANT INSERT,SELECT ON TempLog.* TO 'sensor_writer'@'localhost' IDENTIFIED BY 'password'; FLUSH PRIVILEGES;
Our Raspberry Pi with Raspbian OS acts like a master on a bus and gets the readings from sensors. Luckily, the 1-wire communication on GPIO4 is already implemented as kernel module in Raspbian which should be loaded before trying to read the sensors. Load modules with the following shell commands:
sudo modprobe w1-gpio sudo modprobe w1-therm
If the sensors are properly connected to RPi GPIO header, the following command should return number of slaves on the bus:
and this command:
returns unique ID of each sensor that is connected to the bus. In our case previous command gives the following output:
28-0000029f82cc 28-000005e791b9 28-000005e3816f
As can be seen, each sensor is represented with the unique ID (28-xxxxxxxxxxxx). If sensor ID does not start with "28" then you probably have some other temperature sensor from DS18x20 family.
Sensor reading can be performed by reading w1_slave link in
/sys/bus/w1/devices/28-xxxxxxxxxxxx directory. For example by running the following command:
we get something like this:
aa 01 4b 46 7f ff 06 10 84 : crc=84 YES aa 01 4b 46 7f ff 06 10 84 t=26625
In the first line we can see if the reading was successfull ("YES") and in the second line after "t=" is the temperature reading in mili degreees Celsius (26625). Howver, we want to automate this reading and store the read values to the database.
Our python script loops through all available sensors on the bus. If the reading is successfull, the reading is stored in MySql database with date and time stamp. If error occurs during sensor reading (CRC is not valid) or script cannot access database, the error is logged to the file (
/home/pi/DS18B20_error.log). Here is the whole script:
import time import os import fnmatch import MySQLdb as mdb import logging logging.basicConfig(filename='/home/pi/DS18B20_error.log', level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s %(message)s') logger=logging.getLogger(__name__) os.system('modprobe w1-gpio') os.system('modprobe w1-therm') #function for storing readings into MySql def insertDB(IDs, temperature): try: con = mdb.connect('localhost', 'sensor_writer', 'password', 'TempLog'); cursor = con.cursor() for i in range(0,len(temperature)): sql = "INSERT INTO DS18B20(sensor_id, date, time, value) \ VALUES ('%s', '%s', '%s', '%s' )" % \ (IDs[i], time.strftime("%Y-%m-%d"), time.strftime("%H:%M"), temperature[i]) cursor.execute(sql) sql =  con.commit() con.close() except mdb.Error, e: logger.error(e) #get readings from sensors every 10 minutes and store them to MySql while True: temperature =  IDs =  for filename in os.listdir("/sys/bus/w1/devices"): if fnmatch.fnmatch(filename, '28-*'): with open("/sys/bus/w1/devices/" + filename + "/w1_slave") as fileobj: lines = fileobj.readlines() if lines.find("YES"): pok = lines.find('=') temperature.append(float(lines[pok+1:pok+6])/1000) IDs.append(filename) else: logger.error("Error reading sensor with ID: %s" % (filename)) if (len(temperature)>0): insertDB(IDs, temperature) time.sleep(600)
Stored readings can be checked by running the following commands in MySql:
USE TempLog; SELECT * FROM DS18B20;