From Webshed
Jump to: navigation, search
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Multiple DS18x20 1-wire sensors on the Raspberry PI<br> =
+
= Multiple DS18x20 1-wire sensors on the Raspberry PI  =
 +
''Edited 16/07/2014 to show how to use new version of the code"''
  
In a previous article I&nbsp;showed how to use a 1-wire tempreature sensor with the Raspberry PI&nbsp;with minimal interface requirements. The nice thing with 1-wire sensors in that multiple devices can share the same bus. You just wire the sensors in parallel - all GND pins tired together, all DQ&nbsp;pins tied together and all VCC&nbsp;pins (if you use them) tired together.<br>  
+
"'Edited 22/12/2013 to add a link to github"''
 +
''Edited 1/1/2013 to fix buggy code, etc''
 +
 
 +
In a [[RaspberryPI DS1820|previous article]] I&nbsp;showed how to use a 1-wire temperature sensor with the Raspberry PI&nbsp;with minimal interface requirements. The nice thing with 1-wire sensors in that multiple devices can share the same bus. You just wire the sensors in parallel - all GND pins tired together, all DQ&nbsp;pins tied together and all VCC&nbsp;pins (if you use them) tired together.<br>  
  
 
The perl code developed for the previous article can only access a single sensor. To read multiple sensors we need to fist get the device IDs of all sensors on the bus, then read each sensor's data. <br>  
 
The perl code developed for the previous article can only access a single sensor. To read multiple sensors we need to fist get the device IDs of all sensors on the bus, then read each sensor's data. <br>  
  
 
On the rPI using the w1 kernel drivers, the file "'''/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves'''" contains a list of all the device IDs detected on the 1-wire bus. We can read this to get a list of IDs to iterate over, requesting data from each of them.<br>  
 
On the rPI using the w1 kernel drivers, the file "'''/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves'''" contains a list of all the device IDs detected on the 1-wire bus. We can read this to get a list of IDs to iterate over, requesting data from each of them.<br>  
<pre>#!/usr/bin/perl
 
use warnings;
 
&amp;check_modules;
 
&amp;get_device_IDs;
 
  
 +
There was a "feature" in the previous version of the code (now removed from this page), it didn't keep track of the 1-Wire ID of the sensors when it queried them for data, it just assumed the first one that answered would always be the first one that answered - a poor assumption that can lead to data from the wrong sensor being written to the wrong database slots. The new code (July 2014) addresses this isse and now keep track of the device IDs.
  
foreach $device (@deviceIDs)
+
To use the new code, you first need to run ''detect.pl'' this produces a plain text file called ''sensors.conf'', you can edit this to give the sensors nice names and to add any offset or calibration values you need. You can change the calibration / offset values any time you like, but the names are fixed once you've created the database.
{
 
    $reading = &amp;read_device($device);
 
        if ($reading&nbsp;!= "9999")
 
    {
 
        push(@temp_readings,$reading);
 
    }
 
}
 
  
#update the database
+
<pre>
`/usr/bin/rrdtool update  /home/pi/temperature/multirPItemp.rrd N:$temp_readings[0]:$temp_readings[1]`;
+
#SENSORS.CONF example
 +
# we read this file, and make a new fixed file with all the device IDs and fixed indexes. You can also put
 +
# calibration information into the sensors.conf file after detect.pl has created it.
 +
# sensors.conf format is:
 +
#
 +
# index , calibration factor    , 1-Wire Device ID
 +
# 0            ,0.0                                   , 10-000802b67ffc
 +
# 1             ,0.0                                    , 10-000802b65cc2
 +
# 2            ,0.0                                    , 10-000802b685ca
 +
# 3            ,0.0                                    , 10-000802b6689e
 +
# 4            ,0.0                                    , 10-000802b68df3
 +
# 5            ,0.0                                    , 10-000802b67687
  
print "Temp 1 = $temp_readings[0]    Temp 2 = $temp_readings[1]\n";
+
# or you can use descriptive names for the device ID, but again you'll have to edit the sensors.conf file to
 +
# add them after detect.pl has created sensors.conf for you.
 +
#
 +
# index , calibration factor , 1-Wire Device ID
 +
# inside ,0.0 ,10-000802b67ffc
 +
# the sun ,100.123 ,10-000802b65cc2
 +
# deepspace ,-273.1 ,10-000802b685ca
 +
# earth_core ,6000 ,10-000802b6689e
 +
# outside ,-1.2 ,10-000802b68df3
 +
# spare ,0.0 ,10-000802b67687
 +
</pre>
  
 +
Once you've got a nice looking sensors.conf, you need to run "makedb.pl". YOou can edit "makedb.pl" to change the RRDTool database settings, but the default values I have in there (collect data every 5min, make a few averages, collect data for a year) should be fine to get started with. My cron job for reading the senors and updating the database looks like this
 +
<pre>
 +
*/5 * * * * cd /home/pi/rPI-multiDS18x20/example && /home/pi/rPI-multiDS18x20/example/gettemp.pl
 +
*/6 * * * * cd /home/pi/rPI-multiDS18x20/example && /home/pi/rPI-multiDS18x20/example/graph.sh
 +
</pre>
  
 +
We have to change directory to the place where the scripts and database are kept first, then call the "gettemp.pl" script. I also update the graphs in the cron-job too, that's the second line.
  
sub check_modules
+
I couldn't think of a nice way to automatically generate a graph plotting script based on the content of sensors.conf, so you'll have to make your own or edit my one in the examples directory.
{
 
  $mods = `cat /proc/modules`;
 
if ($mods =~ /w1_gpio/ &amp;&amp; $mods =~ /w1_therm/)
 
{
 
print "w1 modules already loaded \n";
 
}
 
else
 
{
 
print "loading w1 modules \n";
 
    `sudo modprobe w1-gpio`;
 
    `sudo modprobe w1-therm`;
 
}
 
}
 
  
 +
If you've any questions, or problems or just found a ice way to programmatically generate a graph plotting script, drop me an email.  My address can be found under About Me at the top of the page
  
sub get_device_IDs
+
This code is now maintained at [https://github.com/g7uvw/rPI-multiDS18x20 github]
{
 
# The Hex IDs off all detected 1-wire devices on the bus are stored in the file
 
# "w1_master_slaves"   
 
  
# open file
+
Have fun.
open(FILE, "/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves") or die("Unable to open file");
 
 
# read file into an array
 
@deviceIDs = &lt;FILE&gt;;
 
 
# close file
 
close(FILE);
 
}
 
  
sub read_device
+
[[File:IMG 20140716 205226.jpg|thumb|800px|Six DS18s20 connected to a Raspberry Pi]]
{
 
    #takes one parameter - a device ID
 
    #returns the temperature if we have something like valid conditions
 
    #else we return "9999" for undefined
 
   
 
    $readcommand = "cat /sys/bus/w1/devices/".$_[0]."/w1_slave 2&gt;&amp;1";
 
    $readcommand =~ s/\R//g;
 
    $sensor_temp = `$readcommand`;
 
  
    if ($sensor_temp&nbsp;!~ /No such file or directory/)
+
[[Category:Code]] [[Category:Experiments]] [[Category:HowTo]] [[Category:RaspberryPI]] [[Category:Projects]] [[Category:Electronics]]
    {
 
        if ($sensor_temp&nbsp;!~ /NO/)
 
        {
 
      $sensor_temp =~ /t=(\d+)/i;
 
      $temperature = (($1/1000));
 
        }
 
        else
 
        {
 
            $ret = "9999";
 
        }
 
    }
 
    else
 
    {
 
        $ret = "9999"
 
    }
 
}
 
 
 
</pre>
 
This perl code writes data to a RRD database with two sensors - it should be pretty straightforward to extend this to any number of sensors.<br>
 
 
 
The RRD database is created with this script<br>
 
<pre>#!/bin/bash
 
rrdtool create multirPItemp.rrd  --step 300 \
 
DS:in_temp:GAUGE:600:-30:50 \
 
DS:out_temp:GAUGE:600:-30:50 \
 
RRA:AVERAGE:0.5:1:12 \
 
RRA:AVERAGE:0.5:1:288 \
 
RRA:AVERAGE:0.5:12:168 \
 
RRA:AVERAGE:0.5:12:720 \
 
RRA:AVERAGE:0.5:288:365
 
</pre>
 
The graphs are generated every five minutes from a cron job with with this script<br>
 
<pre>#!/bin/bash
 
RRDPATH="/home/pi/temperature/"
 
RAWCOLOUR="#FF0000"
 
TRENDCOLOUR="#0000FF"
 
#hour
 
rrdtool graph $RRDPATH/mhour.png --start -6h \
 
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
 
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
 
CDEF:intrend=intemp,1200,TREND \
 
CDEF:outtrend=outtemp,1200,TREND \
 
LINE2:intemp$RAWCOLOUR:"Inside temperature" \
 
LINE1:intrend$TRENDCOLOUR:"20 min average" \
 
LINE2:outtemp$RAWCOLOUR:"Outside temperature" \
 
LINE1:outtrend$TRENDCOLOUR:"20 min average"
 
 
 
#day
 
rrdtool graph $RRDPATH/mday.png --start -1d \
 
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
 
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
 
CDEF:intrend=intemp,1800,TREND \
 
CDEF:outtrend=outtemp,1800,TREND \
 
LINE2:intemp$RAWCOLOUR:"Inside temperature" \
 
LINE1:intrend$TRENDCOLOUR:"1h min average" \
 
LINE2:outtemp$RAWCOLOUR:"Outside temperature" \
 
LINE1:outtrend$TRENDCOLOUR:"1h min average"
 
 
 
#week
 
rrdtool graph $RRDPATH/mweek.png --start -1w \
 
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
 
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
 
LINE2:intemp$RAWCOLOUR:"Inside temperature" \
 
LINE2:outtemp$RAWCOLOUR:"Outside temperature" \
 
 
 
 
 
 
 
#month
 
rrdtool graph $RRDPATH/mmonth.png --start -1m \
 
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
 
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
 
LINE2:intemp$RAWCOLOUR:"Inside temperature" \
 
LINE2:outtemp$RAWCOLOUR:"Outside temperature" \
 
 
 
#year
 
rrdtool graph $RRDPATH/myear.png --start -1y \
 
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
 
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
 
LINE2:intemp$RAWCOLOUR:"Inside temperature" \
 
LINE2:outtemp$RAWCOLOUR:"Outside temperature" \
 
 
 
</pre>
 

Latest revision as of 21:02, 16 July 2014

Multiple DS18x20 1-wire sensors on the Raspberry PI

Edited 16/07/2014 to show how to use new version of the code"

"'Edited 22/12/2013 to add a link to github" Edited 1/1/2013 to fix buggy code, etc

In a previous article I showed how to use a 1-wire temperature sensor with the Raspberry PI with minimal interface requirements. The nice thing with 1-wire sensors in that multiple devices can share the same bus. You just wire the sensors in parallel - all GND pins tired together, all DQ pins tied together and all VCC pins (if you use them) tired together.

The perl code developed for the previous article can only access a single sensor. To read multiple sensors we need to fist get the device IDs of all sensors on the bus, then read each sensor's data.

On the rPI using the w1 kernel drivers, the file "/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves" contains a list of all the device IDs detected on the 1-wire bus. We can read this to get a list of IDs to iterate over, requesting data from each of them.

There was a "feature" in the previous version of the code (now removed from this page), it didn't keep track of the 1-Wire ID of the sensors when it queried them for data, it just assumed the first one that answered would always be the first one that answered - a poor assumption that can lead to data from the wrong sensor being written to the wrong database slots. The new code (July 2014) addresses this isse and now keep track of the device IDs.

To use the new code, you first need to run detect.pl this produces a plain text file called sensors.conf, you can edit this to give the sensors nice names and to add any offset or calibration values you need. You can change the calibration / offset values any time you like, but the names are fixed once you've created the database.

#SENSORS.CONF example
# we read this file, and make a new fixed file with all the device IDs and fixed indexes. You can also put
# calibration information into the sensors.conf file after detect.pl has created it.
# sensors.conf format is:
# 
# index , calibration factor    , 1-Wire Device ID
# 0             ,0.0                                    , 10-000802b67ffc
# 1             ,0.0                                    , 10-000802b65cc2
# 2             ,0.0                                    , 10-000802b685ca
# 3             ,0.0                                    , 10-000802b6689e
# 4             ,0.0                                    , 10-000802b68df3
# 5             ,0.0                                    , 10-000802b67687

# or you can use descriptive names for the device ID, but again you'll have to edit the sensors.conf file to
# add them after detect.pl has created sensors.conf for you.
#
# index				, calibration factor , 1-Wire Device ID
# inside			,0.0					,10-000802b67ffc
# the sun			,100.123				,10-000802b65cc2
# deepspace			,-273.1					,10-000802b685ca
# earth_core		,6000					,10-000802b6689e
# outside			,-1.2					,10-000802b68df3
# spare				,0.0					,10-000802b67687

Once you've got a nice looking sensors.conf, you need to run "makedb.pl". YOou can edit "makedb.pl" to change the RRDTool database settings, but the default values I have in there (collect data every 5min, make a few averages, collect data for a year) should be fine to get started with. My cron job for reading the senors and updating the database looks like this

*/5 * * * * cd /home/pi/rPI-multiDS18x20/example && /home/pi/rPI-multiDS18x20/example/gettemp.pl 
*/6 * * * * cd /home/pi/rPI-multiDS18x20/example && /home/pi/rPI-multiDS18x20/example/graph.sh 

We have to change directory to the place where the scripts and database are kept first, then call the "gettemp.pl" script. I also update the graphs in the cron-job too, that's the second line.

I couldn't think of a nice way to automatically generate a graph plotting script based on the content of sensors.conf, so you'll have to make your own or edit my one in the examples directory.

If you've any questions, or problems or just found a ice way to programmatically generate a graph plotting script, drop me an email. My address can be found under About Me at the top of the page

This code is now maintained at github

Have fun.

Six DS18s20 connected to a Raspberry Pi