home |
electronics |
toolbox |
science club |
tuxtalk |
photos |
e-cards |
online-shop
Raspberry PI, reading temperatures with a DS18S20 sensor
My daughter owns a Raspberry PI and this is a little project I did with her during spring break.
She enjoyed exploring this little computer and it's a perfect tool for young children to get
started. You get a much better understanding what a computer actually is in terms of hardware
since you can hold the bare board in your hands. We went first over the board of the Raspberry PI to discuss what the different chips on the board do and then we started with this little
temperature measurement project.
DS18S20 and DS18B20
The DS18S20 or DS18B20 are digital temperature sensors that are already calibrated. It means
that this 3 pin sensor itself has already a kind of computer inside that converts the output of the actual sensor (the one on the chip inside the DS18S20) into digital data (numbers). The sensor data is then read via a 1-wire
bus, a bi-directional digital communication bus that requires only one wire. The computer sends a command to the DS18S20 and tells it to start a measurement cycle. The DS18S20 replies then
back with the data. The good thing about the Raspberry PI is that it has some linux kernel modules which know this 1-wire protocol already. To read one or more sensors you just read a file under "/sys/bus/w1/devices/" and the Raspberry PI will then read at that very moment the sensor.
pi@raspberrypi:~ $ ls /sys/bus/w1/devices
10-0008014fd32f 10-000801cb40f0 w1_bus_master1
pi@raspberrypi:~ $ more /sys/bus/w1/devices/10-000801cb40f0/w1_slave
29 00 4b 46 ff ff 08 10 eb : crc=eb YES
29 00 4b 46 ff ff 08 10 eb t=20250
pi@raspberrypi:~ $ more /sys/bus/w1/devices/10-0008014fd32f/w1_slave
3d 00 4b 46 ff ff 08 10 aa : crc=aa YES
3d 00 4b 46 ff ff 08 10 aa t=30250
The hex numbers you see in that file is the actual data received from the sensor and linux converts this into more human readable temperature values. The value behind "t=" is °C*1000 (milli degree celsius).
Connecting the sensors
You can use either DS18S20 or DS18B20 sensors. They differ a bit in accuracy but for most
use cases this is really irrelevant. Any of them is more accurate than any analog thermometer
you can find in the households. The kernel modules of the Raspberry PI handling the digital
communication with the sensors can handle both. The sensors look like little transistors in
a plastic case. Polarity is important. One of the outer pins is ground and the other one
is +3.3V DC. The center pin is the data pin.
a ds18s20 sensor
To connect this little sensor to the Raspberry PI you will just need one other component: A 4.7 KOhm resistor. Each sensor has a unique identifier burned into the chip during production and this is how they will be identified under /sys/bus/w1/devices. The same sensor will always have the same number (e.g 10-0008014fd32f) but you don't know up front which number a given sensor has. It's not printed onto the case of the sensor. You can connect multiple sensors to the same Raspberry PI since 1-wire is a bus. That is: it can handle several sensors on the same cable. You just connect the sensors in parallel. It's still only one 4K7 pull-up resistor for all sensors on the bus. Here is how to connect the sensor(s) to the Raspberry PI.
How to connect a ds18s20 sensor to a Raspberry PI. You can build this on a little bread board. No soldering required.
In older Raspberry PIs you can simply load manually the required kernel modules w1_gpio and w1_therm with the command modprobe. Newer Raspbian OS versions (2016 and later) have introduced a GUI to load those modules and loading just the kernel modules with modprobe does not seem to result in proper sensor readings. The kernel modules load but no sensor files are found under /sys/bus/w1/devices.
pi@raspberrypi:~ $ more /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
The GUI to load the kernel modules can be found here:
Go to the Raspberry PI config menu
The Raspberry PI config men dialog window
Enable 1-wire and after that
shut down the Raspberry PI, connect the sensor and power it up again.
As an alternative to the GUI you can possibly edit the file /boot/config.txt and add the line
"dtoverlay=w1-gpio,gpiopin=4" at the end of the file but we did not try that. We used the GUI.
After those changes and booting up the Raspberry PI again you should see a directory under /sys/bus/w1/devices/ (type in a terminal: ls /sys/bus/w1/devices/).
In that directory should be a file called w1_slave and it contains the temperature reading. In other words the command
more /sys/bus/w1/devices/*/w1_slave
Will read all your DS18S20 (or DS18B20) sensors one after the other. You will notice that it's a bit slow to read those virtual w1_slave files because the 1-wire protocol bus speed is rather low to avoid problems with electromagnetic interference even without special cables or shielding.
A script to print the temperature sensor values in human readable format
Next we wrote a shell script. This is an opportunity get hands on experience with the linux bash shell and to see that
one can actually write programs with it. We called the script tempread.sh
#!/bin/bash
#
if [ -n "$1" -a "$1" = "-h" ]; then
echo "USAGE: $0 [-h]"
echo "read all 1wire temperature sensors form /sys/bus/w1/devices/"
exit 0
fi
sensdir=/sys/bus/w1/devices
for s in $sensdir/*-*/w1_slave; do
if [ ! -r $s ]; then
echo "ERROR: can not read sensor $s"
else
# we are looking for a line with t=
# 41 00 4b 46 ff ff 07 10 38 t=32312
awk '/t=/{sub(/^.+t=/, "");c=$0/1000;print c " C"}' $s
fi
done
Copy paste this into the text editor and save it as tempread.sh. Go back to the shell and type "chmod 755 tempread.sh" to make it executable. After that you can run
pi@raspberrypi:~ $ ./tempread.sh
... and it will print the temperature readings of all your sensors in °C.
Temperature reading with any web browser
To play with the hardware, to write the script and to get it all to work was something that my daughter enjoyed but to be able to read the temperature on any device connected to the home WIFI network was really "cool".
I mentioned already that reading the sensors are a bit slow (about 1/2 sec to read the data of one sensor). It's slow but OK if you are just connecting this
to your home wifi network. The firewall in your router will block by default access for anybody outside your home network. Thus the amount of connections per seconds that you have to handle is not an issue. The following little web server is a simple perl script and you can just copy/paste it. No software installation required. If you want to make all this available on the open internet such that anybody in the world can read the temperature then I recommend a different strategy: install a real web server on the raspberry PI and do not read the sensors directly. Instead run the script to read the sensors periodically (e.g every 5min) and write the output (and some html code) to a file. The web server can the just serve that file as fast as possible and it does not need to wait for the slow 1-wire bus.
#!/usr/bin/perl -w
# vim: set sw=4 ts=4 si et:
# Simple single threaded web server that displays the output of ./tempread.sh
#
# Usage: perlweb.pl [portnumber] [ip-to-bind-to]
# Example: ./perlweb.pl
# The above example will answer http requests at port 8000
# on any interface that this machine has.
# Try:
# curl -v http://localhost:8000
#
use strict;
use Socket;
#
my $listenport = $ARGV[0] || 8000;
socket (Server, PF_INET, SOCK_STREAM, 6) || die ("Error socket: $!"); # protocol 6 is tcp
setsockopt(Server, SOL_SOCKET,SO_REUSEADDR,1) || die ("Error setsockopt: $!");
my $sockaddr = sockaddr_in($listenport, $ARGV[1] ? inet_aton($ARGV[1]) : INADDR_ANY) || die ("Error sockaddr_in: $!");
bind(Server,$sockaddr) || die ("Error bind: $!");
listen(Server,SOMAXCONN) || die ("Error listen: $!");
my $caddr;
my $buffer;
my $tmpincelsius="unknown";
while ($caddr = accept(Client, Server)) {
recv(Client,$buffer,1000,0);
if ($buffer && $buffer=~/^GET /){
print Client "HTTP/1.1 200 OK\r\n";
print Client "Content-Type: text/html\r\n";
print Client "Server: perlweb/1.0\r\n";
print Client "Connection: close\r\n";
print Client "\r\n";
print "client:\n$buffer\n";
# now read the sensor, this is a bit slow because it it in real time
print Client "<h1>Temperature in my room</h1>\n";
open(SF,"./tempread.sh |")||die "ERROR: can not read from pipe\n";
while(<SF>){
print Client $_ . "<br>";
}
close SF;
}
close Client;
}
#
__END__
Copy the above script into a text editor and save it under the name perlweb.pl in the same directory where you have the tempread.sh script. Make the script executable by running in the command "chmod 755 perlweb.pl" and then start it with ./perlweb.pl This little web server will try to run ./tempread.sh and display the output. In other words you have to be in the directory where perlweb.pl and tempread.sh are when you start it as ./perlweb.pl.
pi@raspberrypi:~ $ ./perlweb.pl &
Next we need to find the IP address of the Raspberry PI. For this run the command ifconfig:
pi@raspberrypi:~ $ ifconfig
eth0 Link encap:Ethernet HWaddr b8:27:eb:42:f4:cf
inet addr:10.0.0.12 Bcast:10.0.0.255 Mask:255.255.255.0
inet6 addr: fe80::e2c7:cb8:86d5:f27c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15607 errors:0 dropped:9 overruns:0 frame:0
TX packets:7233 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1736206 (1.6 MiB) TX bytes:1023444 (999.4 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:360 errors:0 dropped:0 overruns:0 frame:0
TX packets:360 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:47276 (46.1 KiB) TX bytes:47276 (46.1 KiB)
wlan0 Link encap:Ethernet HWaddr b8:27:eb:17:a1:9a
inet6 addr: fe80::c56b:6c07:e267:4e04/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:7173 errors:0 dropped:7173 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1666950 (1.5 MiB) TX bytes:0 (0.0 B)
If you have it connected via a cable to the network then you will will find its IP under eth0 as shown above (10.0.0.12)
otherwise if you use wifi then it will be under wlan0 in the ifconfig printout.
Now take another computer or iPad, whatever,... and use the URL http://10.0.0.12:8000 where you replace 10.0.0.12 with
the IP from your Raspberry PI.
Reading the temperature via the web browser of another device.
Cool stuff!
© 2004-2024 Guido Socher