[Home]Plotting DS18S20 Temperature Readings Using SVG

HomePage | RecentChanges | Preferences | My Website home page

Showing revision 22

pre Raspberry Pi and DS18S20 temperature measurement

In 2008 I tried som PIC16F assembler to read the DS18S20 temperature chip. http://www.dougrice.plus.com/dev/sl004ds1820.asm

I had brought one of these kits. https://quasarelectronics.co.uk/Item/3145-ds18s20-computer-serial-temperature-data-logger

Raspberry Pi and DS18S20 temperature measurement

This page records some work on using DS18S20 with Raspberry Pi and plotting using AWK, SVG and JavaScript.

Using the kernal extensions ( see links ) the Raspberry Pi can use the "one wire" interface to read the Dallas 18S20 temperature chips.

I use a shell script to poll the chips and append the readings to a file of JavaScript function calls and other text files.

An awk script is used to extract the text and populate the gbF() function calls. If written to a file, the file can be included into an SVG file.

Using JavaScript in an SVG file, I plot the data as a simple graph. The SVG file does a location.reload() to update.

This is run in the Midori 0.4.3 web browser that renders the SVG file.

example: http://www.dougrice.plus.com/raspberryPi_ds1820/loopDS18S20reportSVG.svg

files: http://www.dougrice.plus.com/raspberryPi_ds1820/

Update 2025-03-14: Use a cron job to poll temperature every 15 minutes

enable One wire using /bin/raspi-config

To run every 15 minutes add this to a cron job

 crontab -e 

 #Add this 
 #
 # m h  dom mon dow   command
 # poll DS18S20.sh using one wire
 0,15,30,45 * * * *  /usr/bin/bash /home/pi/log18S20.sh

Edit log18S20.sh bash script that is run every 15 minutes.

 cd ~
 nano log18S20.sh

 #! /bin/bash
 # log18S20.sh
 #
 echo "==="                       >> /home/pi/log18S20.txt
 date  -u +'%Y-%m-%d %H:%M'       >> /home/pi/log18S20.txt
 # only log the temperature t=
 cat /sys/bus/w1/devices/10-*/w1* | awk '/t=/ { print $10 }' >> /home/pi/log18S20.txt

Login and cat /home/pi/log18S20_rpiw.txt

I set the hostname of the Raspberry Pi Zero W to rpiw

Use SCP to fetch the file of temperatures

 scp pi@rpiw://home/pi/log18S20.txt log18S20_rpiw.txt

E.G log18S20_rpiw.txt contains:-

 ===
 2025-03-14 21:45
 ===
 2025-03-14 22:00
 t=20187
 ===
 2025-03-14 22:15
 t=20125
 ===
 2025-03-14 22:30
 t=20062

An example using a Raspberry Pi Zero and DS18S20 in one room and another Raspberry Pi and another DS18S20 in another room.

These Raspberry Pi are on my local lan and only accessable from a computer on the same lan.

Every 15 minutes each Pi take a measurement and append to a file which can be included in a web page.

 gbFa( "2025-03-19 07:00 t=12375" )
 gbFa( "2025-03-19 07:15 t=12500" )
 gbFa( "2025-03-19 07:30 t=12625" )

This web page includes the data files from each pi and plots the data:-

  src="http://rpiw/gb/gbFa.js" , copy in gbFar.js

  src="http://patrickpi:8086/gb/gbFa.js" , copy in gbFap.js

http://www.dougrice.plus.com/dev/graphs/graphPi.htm - This Webpage includes the data wrapped JavaScript Functions JavaScript files, and uses JavaScript and the <CANVAS>

This depends on the Raspberry Pi time and date being the same.

do_dates.bat can be used to check the clocks of the web servers I am interested in. Win 11 seems to have curl

 rem
 rem 
 rem
 echo "do.bat " >temp.txt 
 type do_dates.bat
 date /T >> temp.txt
 time /T >> temp.txt
 curl -s --head http://patrickpi 	 >> temp.txt
 curl -s --head http://rpiw	         >> temp.txt
 curl -s --head http://192.168.1.254	 >> temp.txt
 curl -s --head http://dougrice.co.uk    >> temp.txt
 curl -s --head http://www.bbc.co.uk	 >> temp.txt
 curl -s --head http://ccgi.dougrice.plus.com >> temp.txt
 curl -s --head http://www.dougrice.plus.com  >> temp.txt

 curl -s --head http://192.168.1.63	 >> temp.txt

 type temp.txt | find "Date"
 dir temp.txt 
 time /T  

Raspberry Pi and DS18S20

One wire - DS18S20 reader

Used GPIO4 pin 7 - middle pin. 3v3 to power gnd to gnd

		/ 3v3  	
DS18S20	- top (|- buss --GPIO4--[4k7]--/
	  	\ gnd

Web pages to help:-

http://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/hardware

http://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/ds18b20

Shell Script - loop.sh

The script below starts the kernel module for "OneWire" and loops polling all the devices onthe Bus.

I have 4 DS18S20, which I read and set userfield1,userfield2,userfield3,userfield4 parameters in gbF() guestbook Function. This is appended to gbookFtemp.js on the desk top. The date is set to when I read the devices.

#! /bin/bash
#	
#  Shell Script to poll temperature chips 
#  usage:	 bash loop.sh
#
# http://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/hardware
#
echo "---------------------"
ls /sys/bus
echo "---------------------"
sudo modprobe w1-gpio
sudo modprobe w1-therm

echo "---------------------"
ls /sys/bus
echo "---------------------"

while [[ 1 ]]
do
  echo "========" 		    > ~/Desktop/tmp.txt
  date 				   >> ~/Desktop/tmp.txt
  cat /sys/bus/w1/devices/10-*/name >> ~/Desktop/tmp.txt
  cat /sys/bus/w1/devices/10-*/w1* >> ~/Desktop/tmp.txt
  echo " "			   >> ~/Desktop/tmp.txt
  #
  # use AWK to extract the temperatures. appends gbF() to gbookFtemp.js
  #
  cat ~/Desktop/tmp.txt
  awk -f loop.awk ~/Desktop/tmp.txt 

  cat ~/Desktop/tmp.txt >> ~/Desktop/loop_log.txt
  sleep 3 
  
done  

Awk Script loop.awk

This awk script extracts the temperature and puts the results into the javascript include file.

#
#
# loop.awk
#
# usage: 	awk -f loop.awk loop_log.txt
#
#
# pull out the temperature from loop_log.txt written by loop.sh 
# Appends to "gbookFtemp.js"
#
#
#//gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){


BEGIN {
  FS="="

  # zero the temperatures
  ln[1]=0
  ln[2]=0
  ln[3]=0
  ln[4]=0
  # print "" > "gbookFtemp.js"
  notFirst = 0
}

/====/{
  print $0
  getline
  print $0
  
  lnp=1
  cnt +=1
  if ( notFirst ){
    print "gbF( 'awk','t@pi','" lastDate " ','127.0.0.1'," ln[1] "," ln[2] "," ln[3] "," ln[4] ",'comments');" >> "gbookFtemp.js"
  }
  # prepare for next readings
  notFirst = 1
  ln[1]=0
  ln[2]=0
  ln[3]=0
  ln[4]=0
  lastDate = $0
}

/t=/{
  # found a line with a temperature
  ln[lnp] = ($NF/1000) 
  lnp ++
}

END {
  cnt +=1
  print "gbF( 'awk','t@pi','" lastDate " ','127.0.0.1'," ln[1] "," ln[2] "," ln[3] "," ln[4] ",'comments');" >> "gbookFtemp.js"
}

some "gbookFtemp.js"

The temperatures are saved wrapped in a function call.
gbF( 'awk','t@pi','Sun Feb  9 10:30:47 UTC 2014 ','127.0.0.1',17.375,18,17.5,17.312,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:30:53 UTC 2014 ','127.0.0.1',17.312,18,17.5,17.312,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:00 UTC 2014 ','127.0.0.1',17.375,19.187,17.562,17.375,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:06 UTC 2014 ','127.0.0.1',17.375,19.187,17.562,17.437,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:13 UTC 2014 ','127.0.0.1',17.437,23.25,17.562,17.5,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:20 UTC 2014 ','127.0.0.1',17.437,24.375,17.625,17.562,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:27 UTC 2014 ','127.0.0.1',17.5,25.375,17.687,17.562,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:33 UTC 2014 ','127.0.0.1',17.5,26.062,17.687,17.562,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:40 UTC 2014 ','127.0.0.1',17.5,26.687,17.687,17.625,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:46 UTC 2014 ','127.0.0.1',17.562,27.562,17.75,17.625,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:53 UTC 2014 ','127.0.0.1',17.562,28.437,17.75,17.687,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:31:59 UTC 2014 ','127.0.0.1',17.625,28.937,17.75,17.687,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:32:06 UTC 2014 ','127.0.0.1',17.625,-1.25,17.812,17.687,'comments');
gbF( 'awk','t@pi','Sun Feb  9 10:32:13 UTC 2014 ','127.0.0.1',17.625,29.5,17.812,17.687,'comments');

SVG - loopDS18S20reportSVG.svg

The SVG below includes the readings in gbookFtemp.js and plots them.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" width="600" height="600" >
<script type="text/ecmascript"><![CDATA[
//
// Include javascript guestbook and process it. Plots Temperature measurements from DS18S20.
// 

var count=1
var opStr = ""

var linePointsStr2 = ""
var linePointsStr3 = ""
var linePointsStr4 = ""
var linePointsStr5 = ""
var xIndex = 50
var tempStr =""

//
// This function is called once per guestbook entry stored in gbookFtemp.js
// There is a lot of junk in there, which needs to be ignored.
//

function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
//  var yvalue = 200 + Math.random()*32
  scale = 10.0
  var yvalue = userfield1*1.0
  if ( yvalue != -1.25) {    linePointsStr2 += xIndex + "," + ( 400 - yvalue*scale ) + " "  }  
  var yvalue = userfield2*1.0
  if ( yvalue != -1.25) {    linePointsStr3 += xIndex + "," + ( 400 - yvalue*scale ) + " "  }  
  var yvalue = userfield3*1.0
  if ( yvalue != -1.25) {    linePointsStr4 += xIndex + "," + ( 400 - yvalue*scale ) + " "  }
  var yvalue =  userfield4*1.0
  if ( yvalue != -1.25) {    linePointsStr5 += xIndex + "," + ( 400 - yvalue*scale ) + " "  }
  xIndex += 1
  tempStr = "last temperatures: " +userfield1 +","+userfield2+","+userfield3+","+userfield4
  
}

function plotMeasured() {
  //
  // Guestbox processed
  //
  obj2=document.getElementById("dhr2");
  obj2.setAttributeNS(null,"points", linePointsStr2  );

  obj3=document.getElementById("dhr3");
  obj3.setAttributeNS(null,"points", linePointsStr3  );

  obj4=document.getElementById("dhr4");
  obj4.setAttributeNS(null,"points", linePointsStr4  );

  obj5=document.getElementById("dhr5");
  obj5.setAttributeNS(null,"points", linePointsStr5  );
}

]]></script>

// window

<defs>
  <!-- Set up clip path to constrain graphs to plot window -->
  <clipPath id = "clip1">
    <path d = "M 48 53 L 548 53  L 548 420 L 48 420 L 48 53 "/>
  </clipPath>
  <radialGradient id = "g1" cx = "50%" cy = "50%" r = "50%" fx = "25%" fy = "25%">
    <stop stop-color = "#ffff66" offset = "0%"/>
    <stop stop-color = "#FFFFCC" offset = "50%"/>
    <stop stop-color = "white" offset = "100%"/>
  </radialGradient>
  <linearGradient id = "g2" x1 = "10%" y1 = "10%" x2 = "90%" y2 = "90%">
    <stop stop-color = "white" offset = "0%"/>
    <stop stop-color = "#7fff66" offset = "25%"/>
    <stop stop-color = "white" offset = "100%"/>
  </linearGradient>
</defs>

// outer square
<rect x="0" y="0" width="600" height="590" fill = "url(#g2)" /> 

//
// plot canvas
//
<rect x="48" y="53" width="500" height="500" stroke="blue" fill = "url(#g1)"  />

//
// define 4 polylines. javascript will change points later.
//

<polyline id="dhr2" fill="none" stroke="blue"   stroke-width="2" points="" clip-path = "url(#clip1)" />
<polyline id="dhr3" fill="none" stroke="lime"   stroke-width="2" points="" clip-path = "url(#clip1)" />
<polyline id="dhr4" fill="none" stroke="red"    stroke-width="2" points="" clip-path = "url(#clip1)" />
<polyline id="dhr5" fill="none" stroke="orange" stroke-width="2" points="" clip-path = "url(#clip1)" />

//
// minor axis lines
//
<line x1="52" y1="100" x2="545" y2="100" style="stroke:rgb(99,99,99);stroke-width:1" />
<line x1="52" y1="200" x2="545" y2="200" style="stroke:rgb(99,99,99);stroke-width:1" />
<line x1="52" y1="300" x2="545" y2="300" style="stroke:rgb(99,99,99);stroke-width:1" />
<line x1="52" y1="400" x2="545" y2="400" style="stroke:rgb(10,10,10);stroke-width:2" />
<line x1="52" y1="500" x2="545" y2="500" style="stroke:rgb(99,99,99);stroke-width:1" />


<text  x="260" y="20"  text-anchor="middle" font-family="Arial,Helvetica" font-size="14px" font-weight="bold" >Temperature Plot using SVG, run: bash loop.sh</text>
<text  x="260" y="40"  text-anchor="middle" font-family="Arial,Helvetica" font-size="14px" id="svg_21"        >data from gbookFtemp.js - DS18S20</text>
<text  x="260" y="580" text-anchor="middle" font-family="Arial,Helvetica" font-size="14px" font-weight="bold" >measurement</text>

<text transform="rotate(270,20,300)" x="20" y="300" font-family="Arial,Helvetica" text-anchor="middle" font-size="14px" pointer-events="none"  font-weight="bold" >Temperature Centigrade</text>

<text  x="30" y="500"  text-anchor="middle" font-family="Arial,Helvetica" font-size="8px" >-10 C </text>
<text  x="30" y="400"  text-anchor="middle" font-family="Arial,Helvetica" font-size="8px" >0 C </text>
<text  x="30" y="300"  text-anchor="middle" font-family="Arial,Helvetica" font-size="8px" >10 C </text>
<text  x="30" y="200"  text-anchor="middle" font-family="Arial,Helvetica" font-size="8px" >20 C </text>
<text  x="30" y="100"  text-anchor="middle" font-family="Arial,Helvetica" font-size="8px" >30 C </text>

<script type="text/ecmascript" xlink:href="gbookFtemp.js" />
//
// include data from guestbook and process.
//


//
// update polyline points 
//
<script type="text/ecmascript"><![CDATA[

 obj6=document.getElementById("svg_21");
 obj6.textContent = tempStr
 
 plotMeasured() 

 window.setInterval("location.reload();",6000);

]]></script>

</svg>


HomePage | RecentChanges | Preferences | My Website home page
This page is read-only | View other revisions | View current revision
Edited March 19, 2025 8:08 am by dougrice.plus.com
Search: