Aquaponics pH to 1-Wire Converter – Part 1

Aquaponics systems need a good water quality, and one of the parameters is pH value, which needs to be within a certain range in order for the fish and plants to thrive. This is of course also true for fish-only aquariums, but since I have an aquaponics system set up already, this is what I’ll focus on. There are a few pictures of the system in this blog post: Debian on NSLU2 With USB Hard Disk and Homeplug Network (I’m using a Debian NSLU2 but it should be possible to use an Unslung NSLU2 too).

The small NSLU2 computer has a USB connector and with a DS9490R 1-Wire to USB adapter it’s easy to collect data from a 1-Wire unit onto a hard disk. Then I just need a pH-to-1-Wire adapter, which is what I want to build and describe in the upcoming blog posts. A 1-Wire bus has a much longer reach than a USB bus and that is very convenient for many purposes.

I’m going to build a circuit with the following specifications that will interface to a common pH probe immersed in the aquaponics water:

Input

  • BNC connector
  • High impedance
  • 0.059 V / pH unit
  • 12 VDC power supply

Output

  • RJ12 connector
  • 1-Wire

The block diagram for the circuit looks like this:

Most of the circuit is originally described at 66pacific.com.

BNC Connector

The pH probe that is supposed to be connected to the voltage amplifier only sends out 0.059 V per pH unit and using a coax cable will keep out noise. Coax cable naturally terminates in a BNC connector.

Voltage Amplifier

The small signal from the pH probe is amplified so that it matches a commonly available A/D converter.

Ground Reference

The voltage signal coming from the pH probe is both positive (pH < 7) and negative (pH > 7). Since the power supply for the circuit is from an ordinary 12 VDC mains adapter and the signal is going to an A/D converter, the ground reference for the voltage amplifier is raised to ensure positive voltages only for the converter, assuming that a normal one is only able to handle positive voltages.

A/D Converter

Converts the amplified analog voltage to a digital value and makes it available on the 1-Wire bus.

RJ12 Connector

A common type of connector for the 1-Wire bus. Only 2 pins are used although 6 are available. The pinout is shown on this page: RJ12 Pinout

Voltage Regulator

This block improves the quality of the supply voltage, which makes it possible to use many different generic mains adapters.

DC Connector

A generic low voltage coaxial power connector commonly used on mains adapters.

The next step is to draw the schematic with all the circuit components. Comments and suggestions are welcome in the comments section below.

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…

How to Calculate the Calibration of Watermark Moisture Sensors for Soil

My 1-Wire Watermark soil moisture sensor board from Hobby-Boards generates a negative number ranging from -1.338 when fully wet to -0.1394 when totally dry. These are the limits and normal everyday readings fall in between these limits.

I already had a basic script installed on my NSLU2 in order to find the limits to be used for calibration, so I just need to update the calculation section with the limits and the necessary math to get a readout in percent instead [%]:

# 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`

The original script called update_database.sh is shown in this post: Watermark Soil Moisture Sensor Probe Calibration

With this new modification the soil moisture graph will now show the data in percent:

It shows a remarkably steady low moisture content, but again, it hasn’t rained for days, perhaps even weeks, so for now I trust that this graphs is telling the truth. Time will tell if the system is stuck at this level, or if the rain will be able to change the curve.

Watermark Soil Moisture Sensor Probe Calibration

OWFS and the 1-Wire bus are able to handle several 1-Wire units at a time and I want to display air and soil temperature together in the same graph, and also add a Watermark soil moisture sensor to the system. The soil moisture sensor is controlled by a PCB from Hobby-Boards.com, but the temperature sensors are connected directly to the 1-Wire bus in a daisy chain.

When the units are connected they show up in the owfs directory. 10.x... are temperature sensors, 30.6... is the ground moisture sensor circuit board, and 81.5... is the USB-to-1-Wire adapter:

$ ssh 192.168.1.xx
$ cd owfs
$ ls -la

total 4
drwxr-xr-x 1 root   root      8 Oct 19 13:58 .
drwxr-xr-x 7 thomas thomas 4096 Sep 28 13:36 ..
drwxrwxrwx 1 root   root      8 Oct 19 15:39 10.06A394010800
drwxrwxrwx 1 root   root      8 Oct 19 15:39 10.4F7494010800
drwxrwxrwx 1 root   root      8 Oct 19 15:39 30.6A1E62120000
drwxrwxrwx 1 root   root      8 Oct 19 15:39 81.592527000000
drwxr-xr-x 1 root   root      8 Oct 19 13:58 alarm
drwxr-xr-x 1 root   root      8 Oct 19 13:58 bus.0
drwxr-xr-x 1 root   root      8 Oct 19 13:58 settings
drwxrwxrwx 1 root   root      8 Oct 19 15:39 simultaneous
drwxr-xr-x 1 root   root      8 Oct 19 13:58 statistics
drwxr-xr-x 1 root   root     32 Oct 19 13:58 structure
drwxr-xr-x 1 root   root      8 Oct 19 13:58 system
drwxr-xr-x 1 root   root      8 Oct 19 13:58 uncached

My previous system only had a single temperature sensor connected to it, so I delete the old RRDtool database:

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

and add the new temperature sensor and the soil moisture sensor (soiltemp and soilmoist) to a new database using the create_database.sh script:

#!/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 \
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

(Check out my other post about RRDtool for more details on how to get the logging system up and running: How to Use RRDtool on Debian NSLU2 to Capture Temperature Data).

The update_database.sh script also needs an update to include the soil temperature data and the soil moisture data:

#!/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`

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

# Calculate soil moisture
a=`echo "(-1)*$soilmoist1" | bc`
soilmoist=`echo $a | cut -c -5`

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

# 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"

Watermark soil moisture sensor circuits need to be calibrated before the system will produce any meaningful results. Therefore the calculation in the above script is limited to converting from a negative to a positive readout, by multiplying with -1. In order to make the calibration you need the minimum and maximum value and afterwards convert to a percentage, i.e. minimum corresponds to a totally dry sensor, and maximum corresponds to a totally wet sensor.

With the raw soil moisture data now available the upload_graphs.sh script needs to be updated to upload the new graphs too:

#!/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
quit 0
EOF

Using the above scripts will produce graphs that contain both the air temperature and the soil temperature in the same graph.

Data from the soil moisture circuit are displayed in another graph:

Note that there’s no unit on the Y-axis because it’s still the raw data coming from the soil moisture sensor circuit. The reason for the fast drop shown in the graph is that during calibration I’m controlling the actual moisture. This is not your usual kitchen table project – it turned into a kitchen floor project ;-) :

When I had the Watermark soil moisture probe installed in my previous garden I noticed a strong dependence on soil temperature, which I wanted to compensate for in this new installation. This is a graph produced by my old set up:

You do get a general idea about the soil moisture content, but the temperature influence is clear, as each number on the X-axis represents day of month and the temperature drops each night.

I used an oven and a freezer during calibration to find the real minimum and maximum values, that the system is able to produce.

I had hoped that I could do some math in my scripts and remove this temperature dependence but after seeing the graph for the raw minimum and maximum data produced during calibration I realized that it’s not possible to that after all.

To the left on the X-axis I have a completely dry sensor (using the hot air fan in my oven), and to the right the sensor is completely soaked in a bowl of water:

The graph do show the temperature dependence, but the problem is that the error due to temperature is dependent on the actual soil moisture content, which is also the parameter I want to measure. So to make the correct adjustment, in order to calculate the actual moisture, I would need to know the actual moisture, which is impossible, since the actual moisture is what I wanted to measure in the first place. I guess I had hoped that the two lines would have been parallel, so that the temperature error would have been the same no matter what the actual moisture was. We’re moving into the field of physics, but the question still is: What is the maximum value to be used for calibration?

If the average value of 1.0 is used you’ll get measurements showing more than 100 % when the temperature exceeds 20 deg. C and the sensor is soaked. Choosing 0.7 will only make it worse. If 1.3 is chosen as maximum value the measurements will always be too low, but I’ll use this value in a new script to get the readout converted to a percentage. I’ll show the math and new graphs in my next blog post.

(Update 2011-11-08: Check out my new script: Watermark soil moisture sensors calibration calculator)

Automatic File Transfer From NSLU2 to Server

My NSLU2 is generating new temperature graphs every 5 minutes from a network of 1-Wire sensors, but since it doesn’t have a connector for a screen I can’t look at the graphs unless I transfer the image files to my PC. Because my PC is sometimes turned off (scary stuff, I know ;-) ) I have to program the NSLU2 to transfer the files to an ‘always on’ server, and then from there download the graphs to my PC for analysis.

In order to program the NSLU2 I log in from my PC via my local network:

(Replace xx with the actual IP address of the NSLU2)

$ ssh thomas@192.168.1.xx

I put the instructions for the NSLU2 in a script called upload_graphs.sh:

$ cd /home/thomas/rrdtool/

$ nano upload_graphs.sh

nano is a standard terminal text editor, and these are the commands that goes into the script:

#!/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
quit 0
EOF

I immediately pause the script for 30 seconds to let the graph update script finish first before uploading the graph files.

lftp is an FTP client, and cd means changing directory on the FTP server, whereas lcd is a local change of directory.

On a standard NSLU2 Debian installation lftp has to be installed before running the script:

($ means I’m working as a standard user, and # means superuser)

$ su
# apt-get install lftp
# exit

The permission settings must be changed to ‘executable’ to allow the new script to execute:

$ chmod +x upload_graphs.sh

Test the script with a single run to see if it’s working correctly:

$ ./upload_graphs.sh

before adding it to the crontab:

$ crontab -e

This line in the crontab list will execute the upload script every 5 minutes:

*/5 * * * * /home/thomas/rrdtool/upload_graphs.sh

Check if crontab has been updated correctly:

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

Both the graph generation script and the upload script have now been installed as regular jobs to be run every 5 minutes.

Note: I realize that having your user name, password and server name in an lftp script is not very secure, so if you have a better way of doing this, please leave a comment below.