Linux Scripts for RainWise 1-Wire Rain Gauge

After the first successful test of my RainWise rain gauge it’s time to automatically generate graphs showing the amount of rainfall versus time.

First I log into my NSLU2 via SSH:

$ ssh 192.168.1.xx

$ uptime
 16:07:28 up 14 days,  3:07,  1 user,  load average: 0.10, 0.06, 0.01

I can’t help checking the uptime when I log in. I’m still amazed by how little maintenance this small NSLU2 computer requires. This is usually the case with Linux servers, but on top of that is has low power consumption and small form factor – I almost forget that it’s there.

Generation of graphs happens automatically so before making any changes to the scripts, I prefer disabling the automatic scripts. This is done via Debian crontab, and I just put a ‘hash’ or number sign (#) in front of the command lines to comment them out:

$ crontab -e

# m h  dom mon dow   command
# */5 * * * * /home/thomas/rrdtool/update_database.sh &> /dev/null
# */5 * * * * /home/thomas/rrdtool/upload_graphs.sh

Once you have done a crontab edit with the -e option, you can view crontab commands as they are at the moment with the -l option for crontab list. You can format crontab listings as explained in the first line with the ‘hash’. I’m using the nano editor when editing crontab.

I want to generate graphs based on the rain data and for that I need a data set in the RRDtool database. The old database is deleted and the rain parameter is added to the database generation script:

$ cd /home/thomas/rrdtool/
$ rm database.rrd
$ nano create_database.sh 

#!/bin/bash
rrdtool create database.rrd --start N --step 300 \
DS:airtemp:GAUGE:600:U:U \
DS:soiltemp:GAUGE:600:U:U \
DS:soilmoist:GAUGE:600:U:U \
DS:rain:GAUGE:600:U:U \
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

In order to generate the database.rrd file the script is executed:

$ ./create_database.sh

The main script of the measurement logging system is the update_database.sh script (see below).

There’s no formatting of the counter data from the circuit inside the rain gauge. The rainread variable is used directly in calculations. I have created a file called rain_count.txt, which contains the counter value as it was 5 minutes ago. This is the time between each execution of the script, so the old value is in a file, and the new value is read from the 1-Wire counter. When these two values are subtracted you get the amount of rain in the last 5 minutes, but it’s in ticks, or number of buckets. Each tick represents 0.25 mm of rain, and multiplied with the number of ticks, you get the total amount of rain in [mm]. Note that when you’re doing math in a Linux script, you can make up names for your variables, like rainbuckets, but when you want to use the content of a variable you have to use the dollar sign, like $rainbuckets, or else it will be interpreted as the text ‘rainbucket’. It doesn’t make sense to multiply a number with a text (apples and bananas).

After the old value in the text file has been used in the calculations, the old value is replaced by the new value, to be used for the next calculation coming up in 5 minutes.

A few lines have been added to produce the rain graphs.

$ nano update_database.sh 

#!/bin/bash
cd /home/thomas/rrdtool

# Read data from sensors
airtempread=`cat /home/thomas/owfs/10.4F7494010800/temperature`
soiltempread=`cat /home/thomas/owfs/10.06A394010800/temperature`
soilmoistread=`cat /home/thomas/owfs/30.6A1E62120000/current`
rainread=`cat /home/thomas/owfs/1D.50E00D000000/counters.B`

# Format readings
airtemp=`echo $airtempread | cut -c -4`
soiltemp=`echo $soiltempread | cut -c -4`
soilmoist1=`echo $soilmoistread | cut -c -7`

# Calculate soil moisture
drylimit=0.1394
wetlimit=1.338
range=`echo "$wetlimit-$drylimit" | bc`
a=`echo "(-1)*$soilmoist1" | bc`
b=`echo "$a-$drylimit" | bc`
c=`echo "scale=3; $b/$range" | bc`
d=`echo "100*$c" | bc`
soilmoist=`echo $d | cut -c -5`

# Calculate rain
a=`cat /home/thomas/rrdtool/rain_count.txt`
rainbuckets=`echo "$rainread-$a" | bc`
rain=`echo "0.25*$rainbuckets" | bc`
echo $rainread > /home/thomas/rrdtool/rain_count.txt

# Update database
rrdtool update database.rrd N:$airtemp:$soiltemp:$soilmoist:$rain

# Create graphs
#0000FF = blue trace color
#CC6600 = brown trace color

rrdtool graph temp_h.png -y 2:1 --vertical-label "[deg C]" \
--start -1h DEF:airtemp=database.rrd:airtemp:AVERAGE \
DEF:soiltemp=database.rrd:soiltemp:AVERAGE \
LINE1:airtemp#0000FF:"Air temperature [deg C]" \
LINE1:soiltemp#CC6600:"Soil temperature [deg C]"

rrdtool graph temp_d.png -y 2:1 --vertical-label "[deg C]" \
--start -1d DEF:airtemp=database.rrd:airtemp:AVERAGE \
DEF:soiltemp=database.rrd:soiltemp:AVERAGE \
LINE1:airtemp#0000FF:"Air temperature [deg C]" \
LINE1:soiltemp#CC6600:"Soil temperature [deg C]"

rrdtool graph temp_w.png -y 2:1 --vertical-label "[dec C]" \
--start -1w DEF:airtemp=database.rrd:airtemp:AVERAGE \
DEF:soiltemp=database.rrd:soiltemp:AVERAGE \
LINE1:airtemp#0000FF:"Air temperature [deg C]" \
LINE1:soiltemp#CC6600:"Soil temperature [deg C]"

rrdtool graph temp_m.png -y 2:1 --vertical-label "[dec C]" \
--start -1m DEF:airtemp=database.rrd:airtemp:AVERAGE \
DEF:soiltemp=database.rrd:soiltemp:AVERAGE \
LINE1:airtemp#0000FF:"Air temperature [deg C]" \
LINE1:soiltemp#CC6600:"Soil temperature [deg C]"

rrdtool graph temp_y.png -y 2:1 --vertical-label "[dec C]" \
--start -1y DEF:airtemp=database.rrd:airtemp:AVERAGE \
DEF:soiltemp=database.rrd:soiltemp:AVERAGE \
LINE1:airtemp#0000FF:"Air temperature [deg C]" \
LINE1:soiltemp#CC6600:"Soil temperature [deg C]"

rrdtool graph soil_moisture_h.png --vertical-label "[%]" \
--start -1h DEF:soilmoist=database.rrd:soilmoist:AVERAGE \
LINE1:soilmoist#CC6600:"Soil moisture"

rrdtool graph soil_moisture_d.png --vertical-label "[%]" \
--start -1d DEF:soilmoist=database.rrd:soilmoist:AVERAGE \
LINE1:soilmoist#CC6600:"Soil moisture"

rrdtool graph soil_moisture_w.png --vertical-label "[%]" \
--start -1w DEF:soilmoist=database.rrd:soilmoist:AVERAGE \
LINE1:soilmoist#CC6600:"Soil moisture"

rrdtool graph soil_moisture_m.png --vertical-label "[%]" \
--start -1m DEF:soilmoist=database.rrd:soilmoist:AVERAGE \
LINE1:soilmoist#CC6600:"Soil moisture"

rrdtool graph soil_moisture_y.png --vertical-label "[%]" \
--start -1y DEF:soilmoist=database.rrd:soilmoist:AVERAGE \
LINE1:soilmoist#CC6600:"Soil moisture"

rrdtool graph rain_h.png --vertical-label "[mm/5 min]" \
--start -1h DEF:rain=database.rrd:rain:AVERAGE \
LINE1:rain#0000FF:"Rain"

rrdtool graph rain_d.png --vertical-label "[mm/5 min]" \
--start -1d DEF:rain=database.rrd:rain:AVERAGE \
LINE1:rain#0000FF:"Rain"

rrdtool graph rain_w.png --vertical-label "[mm/5 min]" \
--start -1w DEF:rain=database.rrd:rain:AVERAGE \
LINE1:rain#0000FF:"Rain"

rrdtool graph rain_m.png --vertical-label "[mm/5 min]" \
--start -1m DEF:rain=database.rrd:rain:AVERAGE \
LINE1:rain#0000FF:"Rain"

rrdtool graph rain_y.png --vertical-label "[mm/5 min]" \
--start -1y DEF:rain=database.rrd:rain:AVERAGE \
LINE1:rain#0000FF:"Rain"

Finally, the graph upload script has been updated to include the new graphs:

$ nano upload_graphs.sh 

#!/bin/bash
sleep 30
lftp -u USER,PASSWORD SERVER <<EOF
cd /temp/
lcd /home/thomas/rrdtool/
put temp_h.png
put temp_d.png
put temp_w.png
put temp_m.png
put temp_y.png
put soil_moisture_h.png
put soil_moisture_d.png
put soil_moisture_w.png
put soil_moisture_m.png
put soil_moisture_y.png
put rain_h.png
put rain_d.png
put rain_w.png
put rain_m.png
put rain_y.png
quit 0
EOF

When the changes have been made the crontab job is activated again:

$ crontab -e

# m h  dom mon dow   command
*/5 * * * * /home/thomas/rrdtool/update_database.sh &> /dev/null
*/5 * * * * /home/thomas/rrdtool/upload_graphs.sh

If you want to inspect your RRDtool database manually you can use rrdtool with the fetch option, which is useful if you want to check if data is stored properly in the database. I used this when I was debugging my script:

$ rrdtool fetch database.rrd AVERAGE

The output looks something like this:

            airtemp        soiltemp       soilmoist        rain
...
1324218600: 1.0633744190e+00 3.6800000000e+00 4.6966255810e+01
3.9866799250e+00
...
1324289100: nan nan nan nan
...

This is the resulting graph showing the amount of rainfall versus time:

This shows a small test I did while I was outside gardening, so I’m looking forward to see some real weather data.

I’m still a bit confused about what unit I should put on the Y axis. The normal rainfall graphs I’ve seen is actually bar charts, where each bar represents 1 hour or perhaps 6 hours of rainfall, with only [mm] as units on the Y axis. I wouldn’t say that my graph is wrong, just that my bars are extremely thin, but they do indeed only cover 5 minutes each, and are actually reduced to a 1 pixel wide vertical line. Maybe the ‘/5 min’ can be removed. The problem is that I don’t know enough about RRDtool to make bar charts, but if you have knowledge about this, please leave a comment below – or any other thoughts that you want to share.

Anyway, the rainfall graph is fun to watch, and even if the values are not absolute, it will give you an idea about what’s going on in the garden. It will be interesting to compare with the soil moisture graph and see how the soil responds to rain.

The next natural step would be to connect a sprinkler to the NSLU2 and let it control the soil moisture to provide the best growing conditions for plants, and not just do measurements. This is something I’ve been rambling about for years, so let’s see when, or if, that happens ;-) I do have an aquaponics setup that needs electronic pimping too…

1-Wire Rain Gauge Pictures

This is the newest addition to my 1-Wire system: A rain gauge from RainWise, with Hobby-Boards.com electronics inside.

Picture of rain gauge:

Rain gauge, RainWise

I bought this several years ago when I began my gardening frenzy, but never had a chance to install it before now. Well, of course I had, but I think my basic 1-Wire system had to mature a bit first, which it has and it’s running very well now, so it’s time to add more to the system.

The rain gauge has a filter at the bottom to keep leaves out of the internal mechanics:

Rain gauge, RainWise, filter

I like the fact that the whole thing is black, which I hope will cause any snow to melt in the heat absorbed from the sun, so that snow will be counted as precipitation too. After all, it is falling down from the sky too, which is what I want to measure. It will probably eat hail too.

The rain gauge consists of a long 1-Wire cable, a white plastic cup with two compartments, adjustment screws and a PCB:

Rain gauge, RainWise, parts

The amount of rain is measured by registering how many times one of the compartments of the white cup is filled. Each time a compartment is filled, the cup tips over and creates a pulse with a reed switch.

Rain gauge, RainWise, cup, reed magnetic switch

The reed switch is connected to a PCB with a counter and a backup battery. The PCB also takes care of the 1-Wire communication:

Rain gauge, RainWise, PCB, battery

Rain gauge, RainWise, PCB secondary side

I want to connect this rain gauge to my existing Debian NSLU2 1-Wire system to be able to add more data to my RRDtool graphs.

If you want to see a really complex 1-Wire system you should definitely check out the house monitoring project made by Silvano Gai at http://ip6.com/projects/.