Setting up the sensor
The DS18B20 is a 1-wire digital sensor and is very easy to setup. It has 3 pins, 3.3v in, data & ground and you will also need a 4.7K-10K resistor 'pull-up' the data line.
Looking at the sensor with the flat side facing you:
- Pin 1 -> Raspberry Pi GND
- Pin 2 -> Raspberry Pi GPIO 4
- Pin 3 -> Raspberry Pi 3V
- 4.7K resistor goes between Pin 2 & 3
Setup the software
In order to read data from the sensor I needed to install some modules using modprobe. Once I had I could read the data from the sensor (including the current temperature) just like reading a file.
Install modules:
sudo modprobe w1-gpio
sudo modprobe w1-therm
sudo modprobe w1-therm
The sensor appeared as a directory in /sys/bus/w1/devices directory. The name of the directory is 28-########## with the hashes being the Id of the sensor:
cd /sys/bus/w1/devices
ls
cd 28-*********** (whatever the Id of your sensor)
ls
cd 28-*********** (whatever the Id of your sensor)
I could then read the temperature data from the w1_slave file:
cat w1_slave
The data from the sensor looks like this:
f6 01 4b 46 7f ff 0a 10 eb : crc=eb YES
f6 01 4b 46 7f ff 0a 10 eb t=24437
f6 01 4b 46 7f ff 0a 10 eb t=24437
The first line tells us whether the data read was successful with YES.
The second line displays the temperature as t=#####.
The temperature is returned in 1000's of a degress so 24437 is 24.437 centigrade.
Python program
I created a python module which would periodically sample the temperature from the sensor and allow a calling program to read the temperature from module as and when required, similar to the module I wrote for reading GPS data.
There is a more complete example of how to use the module in the code below but simply you use it like this:
#create temp sensor controller, passing Id of sensor and a time to wait between reads
tempcontrol = TempSensorController("28-000003aaea41", 1)
#start up temp sensor controller
tempcontrol.start()
#read temperature
print tempcontrol.temperature.C
print tempcontrol.temperature.F
#stop the controller
tempcontrol.stopController()
tempcontrol = TempSensorController("28-000003aaea41", 1)
#start up temp sensor controller
tempcontrol.start()
#read temperature
print tempcontrol.temperature.C
print tempcontrol.temperature.F
#stop the controller
tempcontrol.stopController()
Temperature Sensor Controller code
import threading
import time
DEVICESDIR = "/sys/bus/w1/devices/"
#class for holding temperature values
class Temperature():
def __init__(self, rawData):
self.rawData = rawData
@property
def C(self):
return float(self.rawData) / 1000
@property
def F(self):
return self.C * 9.0 / 5.0 + 32.0
#class for controlling the temperature sensor
class TempSensorController(threading.Thread):
def __init__(self, sensorId, timeToSleep):
threading.Thread.__init__(self)
#persist the file location
self.tempSensorFile = DEVICESDIR + sensorId + "/w1_slave"
#persist properties
self.sensorId = sensorId
self.timeToSleep = timeToSleep
#update the temperature
self.updateTemp()
#set to not running
self.running = False
def run(self):
#loop until its set to stopped
self.running = True
while(self.running):
#update temperature
self.updateTemp()
#sleep
time.sleep(self.timeToSleep)
self.running = False
def stopController(self):
self.running = False
def readFile(self):
sensorFile = open(self.tempSensorFile, "r")
lines = sensorFile.readlines()
sensorFile.close()
return lines
def updateTemp(self):
data = self.readFile()
#the output from the tempsensor looks like this
#f6 01 4b 46 7f ff 0a 10 eb : crc=eb YES
#f6 01 4b 46 7f ff 0a 10 eb t=31375
#has a YES been returned?
if data[0].strip()[-3:] == "YES":
#can I find a temperature (t=)
equals_pos = data[1].find("t=")
if equals_pos != -1:
tempData = data[1][equals_pos+2:]
#update temperature
self.temperature = Temperature(tempData)
#update success status
self.updateSuccess = True
else:
self.updateSuccess = False
else:
self.updateSuccess = False
if __name__ == "__main__":
#create temp sensor controller, put your controller Id here
# look in "/sys/bus/w1/devices/" after running
# sudo modprobe w1-gpio
# sudo modprobe w1-therm
tempcontrol = TempSensorController("28-000003aaea41", 1)
try:
print("Starting temp sensor controller")
#start up temp sensor controller
tempcontrol.start()
#loop forever, wait for Ctrl C
while(True):
print tempcontrol.temperature.C
print tempcontrol.temperature.F
time.sleep(5)
#Ctrl C
except KeyboardInterrupt:
print "Cancelled"
#Error
except:
print "Unexpected error:", sys.exc_info()[0]
raise
#if it finishes or Ctrl C, shut it down
finally:
print "Stopping temp sensor controller"
#stop the controller
tempcontrol.stopController()
#wait for the tread to finish if it hasn't already
tempcontrol.join()
print "Done"
import time
DEVICESDIR = "/sys/bus/w1/devices/"
#class for holding temperature values
class Temperature():
def __init__(self, rawData):
self.rawData = rawData
@property
def C(self):
return float(self.rawData) / 1000
@property
def F(self):
return self.C * 9.0 / 5.0 + 32.0
#class for controlling the temperature sensor
class TempSensorController(threading.Thread):
def __init__(self, sensorId, timeToSleep):
threading.Thread.__init__(self)
#persist the file location
self.tempSensorFile = DEVICESDIR + sensorId + "/w1_slave"
#persist properties
self.sensorId = sensorId
self.timeToSleep = timeToSleep
#update the temperature
self.updateTemp()
#set to not running
self.running = False
def run(self):
#loop until its set to stopped
self.running = True
while(self.running):
#update temperature
self.updateTemp()
#sleep
time.sleep(self.timeToSleep)
self.running = False
def stopController(self):
self.running = False
def readFile(self):
sensorFile = open(self.tempSensorFile, "r")
lines = sensorFile.readlines()
sensorFile.close()
return lines
def updateTemp(self):
data = self.readFile()
#the output from the tempsensor looks like this
#f6 01 4b 46 7f ff 0a 10 eb : crc=eb YES
#f6 01 4b 46 7f ff 0a 10 eb t=31375
#has a YES been returned?
if data[0].strip()[-3:] == "YES":
#can I find a temperature (t=)
equals_pos = data[1].find("t=")
if equals_pos != -1:
tempData = data[1][equals_pos+2:]
#update temperature
self.temperature = Temperature(tempData)
#update success status
self.updateSuccess = True
else:
self.updateSuccess = False
else:
self.updateSuccess = False
if __name__ == "__main__":
#create temp sensor controller, put your controller Id here
# look in "/sys/bus/w1/devices/" after running
# sudo modprobe w1-gpio
# sudo modprobe w1-therm
tempcontrol = TempSensorController("28-000003aaea41", 1)
try:
print("Starting temp sensor controller")
#start up temp sensor controller
tempcontrol.start()
#loop forever, wait for Ctrl C
while(True):
print tempcontrol.temperature.C
print tempcontrol.temperature.F
time.sleep(5)
#Ctrl C
except KeyboardInterrupt:
print "Cancelled"
#Error
except:
print "Unexpected error:", sys.exc_info()[0]
raise
#if it finishes or Ctrl C, shut it down
finally:
print "Stopping temp sensor controller"
#stop the controller
tempcontrol.stopController()
#wait for the tread to finish if it hasn't already
tempcontrol.join()
print "Done"
Good information.
ReplyDeleteGreat info! I followed the same pattern and also added a Java web application which the Raspberry Pi pythin script posts the temperature readings to via a REST interface. The web app stores the data in a CouchDB database and can show the temperature in diagrams and charts over time. If interested the code is free on GitHub. Keep up the good work!
ReplyDeletehttp://macgyverdev.blogspot.se/2014/01/weather-station-using-raspberry-pi.html
Nice code, thanks!
ReplyDeleteJust a little typo in the conversion to F. 23.0 should be 32.0
Thanks Denny.. You are the first person to mention this! Ive updated the post.
DeleteYes, I'm in the US where we still us degrees F, so I noticed the temp was off right away.
DeleteI'm just picking up python since I started using Pis for all kinds of things and I'm really liking the language. I particularly like the fact that you can do interrupts based on GPIO pin state changes.
Your code is the first example I've seen that uses threading. I'd be interested in your thoughts about that method vs just reading the file directly if you have a minute. We can take this off-line if you would prefer.
Thanks!
I wrote the class to use in my gps helmet cam http://www.stuffaboutcode.com/2014/01/raspberry-pi-gps-helmet-cam.html and for this it made sense to use a thread because i didnt want to delay the main program while it read the file directly, so by using threading i get around that issue. Its also a tidy way of monitoring a sensor, by running it in its own thread the calling program doesnt need to worry about how to do this or whether it needs to read the temperature, but it is a more processor intensive solution as im reading the value whether i need to or not.
DeleteSlightly rambling but hopefully that makes sense.
Grazie, ottimo lavoro.
ReplyDeleteThis was super nice, intro to threading in python as well! Thanks!
ReplyDeleteThis is very helpful, I'm really new at this. This is the first explanation I've found that actually works. Although the first example doesn't. This is probably more that I actually need. All I really need is for the reading to be placed on a GUI in tkinter.
ReplyDeleteHow would you make it replace the reading with the new reading instead of making a long list?
Im not really sure what you mean? Each time you call tempcontrol.temperature.C you get the temperature at that time, you can do with that whatever you want, write it to the screen using print, assign it to a variable or put it to a GUI.
DeleteHi Martin, Many thanks for this useful code. I am modifying your code for multiple sensors and it works first time the sensor prints the values, but the 2nd and subsequent times the remaining sensors do not update. Any ideas?
ReplyDeleteimport threading
import time
DEVICESDIR = "/sys/bus/w1/devices/"
#class for holding temperature values
class Temperature():
def __init__(self, rawData):
self.rawData = rawData
@property
def C(self):
return float(self.rawData) / 1000
@property
def F(self):
return self.C * 9.0 / 5.0 + 32.0
#class for controlling the temperature sensor
class TempSensorController(threading.Thread):
def __init__(self, sensorId, timeToSleep):
threading.Thread.__init__(self)
#persist the file location
self.tempSensorFile = DEVICESDIR + sensorId + "/w1_slave"
#persist properties
self.sensorId = sensorId
self.timeToSleep = timeToSleep
#update the temperature
self.updateTemp()
#set to not running
self.running = False
def run(self):
#loop until its set to stopped
self.running = True
while(self.running):
#update temperature
self.updateTemp()
#sleep
time.sleep(self.timeToSleep)
self.running = False
def stopController(self):
self.running = False
def readFile(self):
sensorFile = open(self.tempSensorFile, "r")
lines = sensorFile.readlines()
sensorFile.close()
return lines
def updateTemp(self):
data = self.readFile()
#the output from the tempsensor looks like this
#f6 01 4b 46 7f ff 0a 10 eb : crc=eb YES
#f6 01 4b 46 7f ff 0a 10 eb t=31375
#has a YES been returned?
if data[0].strip()[-3:] == "YES":
#can I find a temperature (t=)
equals_pos = data[1].find("t=")
if equals_pos != -1:
tempData = data[1][equals_pos+2:]
#update temperature
self.temperature = Temperature(tempData)
#update success status
self.updateSuccess = True
else:
self.updateSuccess = False
else:
self.updateSuccess = False
if __name__ == "__main__":
#create temp sensor controller, put your controller Id here
# look in "/sys/bus/w1/devices/" after running
# sudo modprobe w1-gpio
# sudo modprobe w1-therm
tempcontrol = TempSensorController("28-03168b14dbff", 1)
tempcontrol2 = TempSensorController("28-0416935ab0ff", 2)
tempcontrol3 = TempSensorController("28-051692c5bdff", 3)
try:
print("Starting temp sensor controller")
#start up temp sensor controller
tempcontrol.start()
#loop forever, wait for Ctrl C
while(True):
print "Sensor 1", tempcontrol.temperature.C, tempcontrol.temperature.F
print "Sensor 2", tempcontrol2.temperature.C, tempcontrol2.temperature.F
print "Sensor 3", tempcontrol3.temperature.C, tempcontrol3.temperature.F
time.sleep(10)
#Ctrl C
except KeyboardInterrupt:
print "Cancelled by user"
#Error
except:
print "Unexpected error:", sys.exc_info()[0]
raise
#if it finishes or Ctrl C, shut it down
finally:
print "Stopping temp sensor controller"
#stop the controller
tempcontrol.stopController()
#wait for the tread to finish if it hasn't already
tempcontrol.join()
print "Done"
You are only starting the first temperature controller.
Deletetempcontrol.start()
You need to start the other 2 as well, i.e:
tempcontrol.start()
tempcontrol2.start()
tempcontrol3.start()
Its a good idea to stop them at the end of the program as well.
Scuse me, I'm new to Python, and rusty at other programming languages, but I was attempting to modify Mark's code to use five sensors. But even as the posted code doesn't work for me(even after proper indents were added)I was wondering if the Python version (2 or 3) made any difference.
DeleteFunny how as soon as you post something stupid, you find the answer to your woes? So I compared Martin's code, which worked fine to the code I modified from Mark, and once I corrected for all the indents, etc, plus my tinkering and modifications, I got something I can use.
Delete