Home Page Up ACARS decoder ADS-B dump1090 AIS receiver Cross-compiling Kernel compile Monitoring NTP Wall Clock


Monitoring The Raspberry Pi with MRTG

As most of my Raspberry Pi cards are used headless - i.e. without a keyboard or monitor - I wanted to monitor what was happening remotely.  In addition to monitoring the NTP Server operation, I've added general SNMP support (Simple Network Management Protocol) which has allow monitoring of the network I/O, disk space, CPU temperature and, with a little additional hardware, ambient temperature monitoring.

Adding SNMP support for general remote monitoring


Based on: and

sudo apt-get update
sudo apt-get install snmpd snmp    # for the SNMP server and client software
[Enter "Y" at Do you want to continue:?]

You need to edit the configuration if you want to monitor your Raspberry Pi from across the network rather than just locally.  The configuration below allows anyone to read the SNMP data - you may want a more secure configuration.  The changes below may not be ideal, but they are what I found to be necessary to get it working:

sudo nano /etc/snmp/snmpd.conf

Change the agentAddress from:

agentAddress udp:


agentAddress 161

Below the line:

#rocommunity public localhost


rocommunity public        (without the initial #)

Restart the SNMP daemon:

sudo /etc/init.d/snmpd restart

For monitoring with MRTG, you can get the results shown here if you have a remote system running MRTG, with an include script something like this zip archive.  You could also install MRTG on the Raspberry Pi itself.  I do wonder what other variables you could monitor, as plotting NTP rate of change versus board or chip temperature would be an interesting exercise.

Interesting that for the two nominally identical Raspberry Pi cards, the one running gpsd and the PPS software for "precise" timekeeping uses about 3% CPU, versus about 1% for the Raspberry Pi without and syncing just off the LAN.  I find that slightly surprising. 

Memory and CPU usage

Monitoring memory can be useful if you think there is a process which is leaking memory, and monitoring CPU will show how near to being saturated your Raspberry Pi is - whether it may be able to handle more work, for example.

RasPi-3 memory usage

RasPi-3 CPU usage

Access to this data is a standard part of Linux for the Raspberry Pi, once SNMP has been installed (see below).  I happen to run the monitoring remotely and use MRTG scripts like those below = this for Raspbian Wheezy!

#	Raspberry Pi 3 - CPU load

# The second entry in the CPU line should always return "0"
# I use Maximum Number of Process Contexts: .
Target[raspi3-CPU]: .
MaxBytes[raspi3-CPU]: 100
YLegend[raspi3-CPU]: CPU %
ShortLegend[raspi3-CPU]: %
LegendI[raspi3-CPU]: CPU
Legend1[raspi3-CPU]: CPU usage
Options[raspi3-CPU]: integer, gauge, nopercent, growright, unknaszero, noo
Title[raspi3-CPU]: Raspberry Pi 3 CPU load
PageTop[raspi3-CPU]: <H2>Raspberry Pi 3 - CPU load</H2>

#	Raspberry Pi 3 - Memory

Target[raspi3-mem]: .
MaxBytes[raspi3-mem]: 100524288
Options[raspi3-mem]: integer, gauge, nopercent, growright, unknaszero, noo
YLegend[raspi3-mem]: Mem - 1K pages
Factor[raspi3-mem]: 1024
ShortLegend[raspi3-mem]: B
LegendI[raspi3-mem]: Physical &nbsp;
LegendO[raspi3-mem]: Virtual  &nbsp;
Legend1[raspi3-mem]: Physical 
Legend2[raspi3-mem]: Virtual Memory
Title[raspi3-mem]: Raspberry Pi 3 Memory Usage
PageTop[raspi3-mem]: <H2>Raspberry Pi 3 - Memory Usage</H2>


For Raspbian Jessie, some of the OIDs have changed.  For example: CPU is now percent free rather than percent busy, so subtract the value returned from 100.:
#	Raspberry Pi 13 - CPU load

# Try to calculate 100 - (OID)
Target[raspi13-CPU]: 100 - .
MaxBytes[raspi13-CPU]: 100
YLegend[raspi13-CPU]: CPU %
ShortLegend[raspi13-CPU]: %
LegendI[raspi13-CPU]: CPU
Legend1[raspi13-CPU]: CPU usage
Options[raspi13-CPU]: integer, gauge, nopercent, growright, unknaszero, noo
Title[raspi13-CPU]: Raspberry Pi 13 CPU load
PageTop[raspi13-CPU]: <H2>Raspberry Pi 13 - CPU load</H2>



Monitoring NTP remotely

You can produce real-time graphs like those below using MRTG and a simple script which can be run even on a Windows PC to get the statistics from NTP remotely.  There is more information here.  



Click on the graph for the week, month & year plots.

To monitor NTP in more detail, you can edit the ntp.conf file to turn on the generation of statistics data.  Note that this data maybe a megabyte or more per day, so think about keeping only a few days worth, and only enabling statistics collection when needed as the number of writes to the SD card flash memory is limited.

sudo nano /etc/ntp.conf

Insert (or uncomment) these lines:

# Enable statistics gathering

statsdir /var/log/ntpstats/
statistics loopstats
filegen loopstats file loopstats type day enable

or if you are exceptionally interested in the peerstats as well (which can be large files!):

# Enable statistics gathering

statsdir /var/log/ntpstats/
statistics loopstats peerstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable

Now restart the NTP daemon:

sudo /etc/init.d/ntp restart

Adding SAMBA for file access from your PC

To view the results from a Windows PC (so that you can run my NTP Plotter program or use the Meinberg NTP Monitor) you need to install and configure a package called SAMBA, which allows a UNIX file system to be seen by a Windows network client.  The following steps are based in information from:

sudo apt-get update
sudo apt-get install samba samba-common-bin
[Enter "Y" at Do you want to continue:?]
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.old

Edit /etc/samba/smb.conf

sudo nano /etc/samba/smb.conf

add at the end of the file a definition of a share named "ntp":

  comment = NTP log files
  path = /var/log/ntpstats
  read only = yes
  guest ok = yes

You may also want to add a share for the NTP leapseconds file:

  comment = NTP leapsecond.file
  path = /home/pi/ntp
  writeable = yes
  guest ok = yes

If you want write access, replace "read only" with "writeable" as in the second example above.  I found that I needed to grant access to the /home/pi/ntp/ directory, which I did with a chmod 777 ntp - doubtless there are tighter protections I could have used.  Now restart the Samba server:

sudo /etc/init.d/samba restart

You now access the files from Windows just like any other network share, for example (after NTP has been running for a while):

C:\>dir \\RasPi-1\ntp
Volume in drive \\RasPi-1\ntp is ntp
Volume Serial Number is 04CA-A6BD

Directory of \\RasPi-1\ntp

24/11/2012 12:03 <DIR> .
24/11/2012 12:03 <DIR> ..
24/11/2012 14:25 112,661 peerstats.20121124
24/11/2012 14:25 33,443 loopstats
24/11/2012 14:25 112,661 peerstats
24/11/2012 14:25 33,443 loopstats.20121124
4 File(s) 292,208 bytes
2 Dir(s) 1,826,832,384 bytes free

To define the IP address to Windows I simply edited the \Windows\System32\drivers\etc\hosts file with Notepad, but you may want a more elegant integration than that.  I could then use the Meinberg Time Server Monitor by adding  \\RasPi-1\ntp  to the known nodes list within the program.

Later, I found that you can edit the DHCP configuration file, uncomment the first send host-name command, edit in your own wanted name, and comment out the default name:

$ sudo nano /etc/dhcp/dhclient.conf


#send host-name "";
send host-name = gethostname();


send host-name "raspi-1";
#send host-name = gethostname();

Robin Schwab notes: The service is now (Jessie) called smbd, not samba.  Then for restarting a service there is a better way than:

$ sudo /etc/init.d/samba restart

If you use:

$ sudo service smbd restart

it will work in Wheezy and Jessie.

Adding SNMP support for CPU temperature monitoring


Click on the graph for the week, month & year plots.
CPU temperature C

Notes based on: 

  How do I monitor and/or control the temperature of the SoC?
  Report GPIO pins by SNMP
  snmpd.conf - configuration file for the Net-SNMP SNMP agent

To monitor the CPU temperature remotely, SNMP is the obvious medium for me.  By chance I happened upon the command to get the CPU temperature of the CPU on the Raspberry Pi in either milli-degrees:

$ cat /sys/class/thermal/thermal_zone0/temp

or in human readable format:

$ /opt/vc/bin/vcgencmd measure_temp

To get this information into SNMP we can create an SNMP "pass" extension, whereby SNMP will call a specific program or shell script to get a particular object ID (OID) value.  The script needs to write to standard output three lines, the OID, the data type (integer/string etc.), and the actual data.  To control the execution of the program or script, the snmpd program will include a parameter when the script is called, to indicate whether the request is a "get" command (-g), a "get-next" command (-n), or a "set" command (-s).  It is important that the program or script not respond to a "get-next" command if it is returning only one variable and, of course, the set command would do nothing when measuring a temperature.  Use the nano editor to create a script named snmp-cpu-temp (or whatever) in your default directory:

$ nano snmp-cpu-temp

The script should contain:

if [ "$1" = "-g" ]
echo .
echo gauge
cat /sys/class/thermal/thermal_zone0/temp
exit 0

I selected the OID as the next unused in a sequence.  You now need to mark the script executable and run it as follows:

$ chmod +x snmp-cpu-temp
$ ./snmp-cpu-temp -g

and you should get a response something like (for a CPU temperature of 46°C):


Having got that part working, you need to copy the script to a location where the SNMP software can find it.  I used /usr/local/bin but I don't know Linux well enough to know whether that's the most appropriate directory.

$ sudo cp snmp-cpu-temp /usr/local/bin

Now we need to edit the SNMP daemon configuration to tell it how to handle this OID.  In the snmpd.conf file, you will find a couple of examples of the "pass" command.  Edit the file:

$ sudo nano /etc/snmp/snmpd.conf

and just below the sample ""Pass-through" MIB extension command"  lines, insert a new active "pass" command:

pass . /bin/sh /usr/local/bin/snmp-cpu-temp

Restart snmpd:

$ sudo /etc/init.d/snmpd restart

and you can then test that it's all working with the command:

$ /usr/bin/snmpget -v 2c localhost -c public .

I got different responses on the two Raspberry Pi cards where I tested, but both contained the line:

iso. = Gauge32: 46540

One system had a whole lot of what appeared to be messages about unfound data, but all three systems work correctly and can be accessed remotely for monitoring the CPU temperature.  Here are the graphs from MRTG - click a graph for a summary or see this page for the more composite data:



RasPi-12 - gets the sun around lunchtime!

Click on a graph for the week, month & year plots.

The monitoring scripts (which I actually run on a Windows PC covering several Raspberry Pi card PCs) are in this Zip archive.  Note that I changed from using the MRTG "in" counter on RasPi-1 -2 and -3, to using the "out" counter on RasPi-4 and -5 as I prefer the single-line blue graph to the green block.

I note that there are some values which record "85", which I recall is the maximum from this sensor.  Ideally, the script would treat those values as an error, and perhaps try again until a more reasonable value is found, or report the value as zero.  I'd welcome your input.

#	Raspberry Pi 4 - CPU temperature

Target[raspi4-CPU-temp]: .
MaxBytes[raspi4-CPU-temp]: 100000
MaxBytes2[raspi4-CPU-temp]: 100000
Title[raspi4-CPU-temp]: CPU temperature on Raspberry Pi 4
Options[raspi4-CPU-temp]: gauge, nopercent, growright, unknaszero, noi
YLegend[raspi4-CPU-temp]: Temperature C
ShortLegend[raspi4-CPU-temp]: C
kMG[raspi4-CPU-temp]: ,
Factor[raspi4-CPU-temp]: 0.001
Legend2[raspi4-CPU-temp]: CPU temperature in C
LegendO[raspi4-CPU-temp]: CPU temperature
PageTop[raspi4-CPU-temp]: <H1>Raspberry Pi 4 - CPU Temperature</H1>



Monitoring Ambient Temperature


Click on a graph for the week, month & year plots.

I extended the SNMP pass function to allow monitoring of ambient temperature using the DS18B20 "single-wire" device.  This is well written up for use with the Raspberry Pi here.  Multiple devices an all be connected, using just a ground, 3.3V and signal wire connection, with the signal wire going to GPIO 4 (pin 7).  Some extra software drivers are required, and the commands listed on that page, with comments and changes, are listed here (in case that page goes offline in the future):

The 1-Wire drivers are not loaded by default when the Raspberry Pi boots. You can load them with the following commands from a command prompt:

$ sudo modprobe wire
$ sudo modprobe w1-gpio
$ sudo modprobe w1-therm

[DJT] but it's easier to add them into /etc/modules (as I found that the command in PERL code below did not load the drivers for me).

$ sudo nano /etc/modules
Add the lines:
to the end of the file, taking care not to delete any lines already there.  A reboot will be required.

Connect the sensor hardware to the Raspberry Pi and check it is detected by seeing if a device is listed on the 1-Wire bus.

$ cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count

This will print the number of sensors detected, 1 - for my hardware at the moment. You can get the sensor ID (a hexadecimal string stored in ROM on the sensor chip) by reading the w1_master_slaves file:

$ cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves

[DJT: My device started with a 28, not a 10.  In fact, it seemed to vary between a 28 and a 10, so I did modify the PERL code accordingly.]  A quick check for correct operation of the sensor is to "read" the sensor file, you'll need the hex ID of the sensor from earlier commands:

$ cat /sys/bus/w1/devices/10-00080234149b/w1_slave
37 00 4b 46 ff ff 07 10 1e : crc=1e YES
37 00 4b 46 ff ff 07 10 1e t=27312

The number after 't=' is the temperature in thousandths of a degrees Celsius.

Note for later versions of Raspbian

Nigel Heasman notes: 

I'm setting up more 1 wire sensors on a raspberry pi B (one of the early ones), running Raspbian wheezy 2015-02-16 and using your notes, and have found that I need to add " dtoverlay=w1-gpio " to the bottom of /boot/config.txt, before the devices were recognised.

I'm not sure if this is something to do with the later versions of Wheezy, as I don't remember having to do it a couple of years ago when I set up my first lot!  I found this info in

I am only mentioning it in case you get queries about:-

$ cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count

reporting that there is no such file or directory.
Many thanks for the copious notes and information on your web pages - a mine of information

Code for multiple devices

At first I wrote a PERL script and bash Shell script to read a single device, but as the PERL contained too little error checking its output was unreliable, and will not be shown here.   I removed the commands to check for and load the modules as they did not work for me.  Finally, I needed a script to be called by the SNMP pass option.  Here is the script, named  snmp-ds1-temp.  It was in the same /home/pi/thermometer/DS18B20 directory.  I used the next higher number for the SNMP object ID.  Probably ought to have made a more formal search!  As with the CPU temperature monitoring, make the script executable, test it, copy it to a directory on the path, edit and restart SNMP, and test that the new OID you have created works as expected.  My current information is being plotted here as "DS1 ambient temperature".

When I added a second DS18B20 to my Raspberry Pi, I found that the two IDs were:


and so I took the easy way out and created two separate PERL scripts, and two separate Shell scripts to be called by SNMP.  I also made some improvements to the PERL scripts to allow for retries in the event of a first try failure based on the scripts here.  As the outside temperature can be negative (in Celsius) here, and as MRTG can't plot negative values, I made return the Fahrenheit rather than the Celsius temperature.  These improvements are in the  scripts below.

Note that I did try with MRTG plotting both indoors and outdoors temperatures on a single MRTG target, but it failed with the simple scripts.  I suspect the failure may have been because SNMP was causing two PERL scripts to be run at the same time, and likely this conflicts with the 1-wire bus arrangement.  I did not test putting two SNMP temperature retrievals in one MRTG target with the error-checking scripts below.  In any case, I ended up with two different MRTG targets with the indoors in °C and the outdoors in °F as implemented in

If you only have one device, you can replace the line:

$sensor_temp = `cat /sys/bus/w1/devices/*5211b35/w1_slave 2>&1`;

with a simpler wildcard such as:

$sensor_temp = `cat /sys/bus/w1/devices/28-*/w1_slave 2>&1`; 

$sensor_temp = "";
$attempts = 0;
$temperature = 0;

while ($sensor_temp !~ /YES/g && $attempts < 5)
        $sensor_temp = `cat /sys/bus/w1/devices/*5211b35/w1_slave 2>&1`;
        if ($sensor_temp =~ /No such file or directory/)
        elsif ($sensor_temp !~ /NO/g)
                $sensor_temp =~ /t=(\d+)/i;
                $temperature = ($1);
print "$temperature\n";

$sensor_temp = "";
$attempts = 0;
$temperature = 0;

while ($sensor_temp !~ /YES/g && $attempts < 5)
        $sensor_temp = `cat /sys/bus/w1/devices/*53520a2/w1_slave 2>&1`;
        if ($sensor_temp =~ /No such file or directory/)
        elsif ($sensor_temp !~ /NO/g)
                $sensor_temp =~ /t=(\d+)/i;
                $temperature = int ((9*$1/5) + 32000);
print "$temperature\n";

Update: it seems that the Perl code above may not work correctly if the temperature is below 0°C.  If so, try replacing the lines:

$sensor_temp =~ /t=(\d+)/i;
$temperature = int ((9*$1/5) + 32000);


$sensor_temp =~ s/.*t=//i;
$temperature = int ((9*$'/5) + 32000);

I would appreciate any feedback on this.
snmp-ds1-temp snmp-ds2-temp
if [ "$1" = "-g" ]
echo .
echo gauge
perl /home/pi/thermometer/DS18B20/
exit 0
if [ "$1" = "-g" ]
echo .
echo gauge
perl /home/pi/thermometer/DS18B20/
exit 0

In /etc/snmp/snmpd.conf

pass  .   /bin/sh  /usr/local/bin/snmp-ds1-temp
pass  .  /bin/sh  /usr/local/bin/snmp-ds2-temp

I know this isn't particularly clever, but as a first cut it worked for me.  To check that it's all working, use snmpget as for the CPU temperature:

$ /usr/bin/snmpget -v 2c localhost -c public .
iso. = Gauge32: 22312
$ /usr/bin/snmpget -v 2c localhost -c public .
iso. = Gauge32: 63386

So that's 22.312 C for the indoor temperature, and 63.386 F for the outdoor temperature.  Bear in mind that although these devices can have a precision of 1/16 C, they only have an accuracy (or trueness) specified to 2 C.

#	Raspberry Pi 4 - Ambient temperature indoors

Target[raspi4-ds1-temp]: .
MaxBytes[raspi4-ds1-temp]: 100000
MaxBytes2[raspi4-ds1-temp]: 100000
Title[raspi4-ds1-temp]: Ambient temperature indoors
Options[raspi4-ds1-temp]: gauge, nopercent, growright, unknaszero, noi
YLegend[raspi4-ds1-temp]: Temperature C
ShortLegend[raspi4-ds1-temp]: C
kMG[raspi4-ds1-temp]: ,
Factor[raspi4-ds1-temp]: 0.001
Legend2[raspi4-ds1-temp]: Indoors temperature in C
LegendO[raspi4-ds1-temp]: Indoors temperature
PageTop[raspi4-ds1-temp]: <H1>Raspberry Pi 4 - Ambient Temperature Indoors</H1>

#	Raspberry Pi 4 - Ambient temperature outdoors

Target[raspi4-ds2-temp]: .
MaxBytes[raspi4-ds2-temp]: 100000
MaxBytes2[raspi4-ds2-temp]: 100000
Title[raspi4-ds2-temp]: Ambient temperature outdoors
Options[raspi4-ds2-temp]: gauge, nopercent, growright, unknaszero, noi
YLegend[raspi4-ds2-temp]: Temperature F
ShortLegend[raspi4-ds2-temp]: F
kMG[raspi4-ds2-temp]: ,
Factor[raspi4-ds2-temp]: 0.001
Legend2[raspi4-ds2-temp]: Outdoors temperature in F
LegendO[raspi4-ds2-temp]: Outdoors temperature
PageTop[raspi4-ds2-temp]: <H1>Raspberry Pi 4 - Ambient Temperature Outdoors</H1>



Monitoring Sea-Level Air pressure

There are a couple of very low cost devices for monitoring ambient air pressure, and it's very easy to add one of these devices to a Raspberry Pi as it already supports the I2C two-wire communication protocol used by the devices, and software support is readily available from Adafruit (to whom, many thanks).  The devices are the older BMP085 and the more recent BMP180, which are pin- and software-compatible.  You will need to connect the board-mounted device to the Raspberry Pi as described in the Adafruit notes.  You don't have to use an Adafruit board, and cheaper UK options are available from eBay.  I assume that you followed their tutorial and have got as far as running the example program.  Do note that if you are using a recent version of Raspbian the instructions for adding modules have changed.  In very brief summary:

sudo apt-get install python-smbus
sudo apt-get install i2c-tools (already there on my RPi)

Run: sudo raspi-config, Advanced options, I2C (interface & kernel)

Add to /etc/modules: (lines were already added in my RPi)

In: /etc/modprobe.d/raspi-blacklist.conf, comment out these lines:
blacklist spi-bcm2708 (needed comment # added)
blacklist i2c-bcm2708 (was already commented)

In: /boot/config.txt add:
dtparam=i2c1=on (had to be added)
dtparam=i2c_arm=on (already there)


At this point, you need the BMP180 connected to see the following:

I could see two devices with the number 42 and 77.
sudo i2cdetect -y 1

I think the 42 was because I had some other stuff connected, you only need the 77 present.  At this point, attempt to build the Adafruit example:

sudo apt-get install git build-essential python-dev python-smbus
git clone
cd Adafruit_Python_BMP
sudo python install
cd examples
sudo python

To use the sensor with SNMP and hence MRTG you need to create a program which will respond with the pressure, create a shell script which SNMP will call to get the value of the pressure, and add a line to snmpd.conf telling SNMP where to find the script.  My simple examples are:

Simple program to read the pressure: - you can put this in your home directory: /home/pi/  Note that the 2175 is the adjustment required to convert readings at my height (183 m) to sea-level pressure.  Yes, you can use a more accurate formula if you wish.  Do not rely on the value from the Adafruit example program where the height appears to be derived from assuming the sea-level pressure to be 1015 hPa, if my reading of their note is correct.

import Adafruit_BMP.BMP085 as BMP085
sensor = BMP085.BMP085(mode=BMP085.BMP085_ULTRAHIGHRES)
pressure = sensor.read_pressure() + 2175
print '{0:0.0f}'.format(pressure)

Simple shell script which can be called by SNMP pass command: snmp-air-pressure

if [ "$1" = "-g" ]
echo .
echo gauge
python /home/pi/
exit 0

Create the script in your home directory, make it executable:

$ chmod a+x snmp-air-pressure

and copy it to a directory on the path such as:

$ sudo cp snmp-air-pressure /usr/local/bin

Now edit the snmpd configuration file, to add the pass command:

$ sudo nano /etc/snmp/snmpd.conf


pass .  /bin/sh /usr/local/bin/snmp-air-pressure

A problem ...

Having done all this, I encountered a problem where I needed to ask for help.  As you can see from the previous examples, I expect to run a command like:

/usr/local/bin/snmp-air-pressure -g

and get a result, but all my attempts gave a result of 0.


... and the solution

Running the command as root (i.e. with sudo) it worked as expected, which suggested a rights issue.  After a lot of discussion on both the Usenet Raspberry Pi newsgroup, and the Adafruit forum, it emerged that there is a Linux group called "i2c" and if the current user has access to that group they can run the I2C software without requiring the sudo prefix.  So I added my user name "pi" to that group:

sudo adduser pi i2c

You can check a group's membership with the "members" command, but you may need to apt-get install that command first.  Further checks shows that when snmpd ran a "pass" command it did so with the user name "snmp", so you would think that all that was required would be:

sudo adduser snmp i2c

so that the user had access to the i2c group.  However, it turns out that when snmpd is started it does not claim all the groups to which it should have access when it starts, and that one line needs to be added to  /etc/snmp/snmpd.conf  to set the group it uses by default.  After the line:

agentAddress 161


agentgroup i2c

Once this is done, the pass script above works correctly when called by snmpd on receipt of an snmp get request.  My thanks to a number of folk on the Raspberry Pi Usenet group, in particular Nomen Nescio who spotted the agentgroup requirement.

Earlier solution - non-preferred

Looking more closely, I could see that Python was giving error 13, in this case from being unable to open the pressure sensor.  Running the script with sudo solved the problem from the command line, but just adding sudo into the script did not work.  Following Andy Burns suggestion on the Raspberry Pi USENET group, I altered the protection on the /dev/i2c-1 device so that "others" could have read-write access.

Before: ls -l /dev/i2c-1 => crw-rw---- 1 root i2c 89, 1 Feb 28 15:12 /dev/i2c-1
Command: sudo chmod o=rw /dev/i2c-1
After: ls-l /dev/i2c-1 => crw-rw-rw- 1 root i2c 89, 1 Feb 28 15:12 /dev/i2c-1

This then allowed the air pressure to be read with SNMP:

$ /usr/bin/snmpget -v 2c localhost -c public .
iso. = Gauge32: 98749

so that I could then use standard MRTG commands to read the air pressure from anywhere in the network.  However, it seems that this solution will only last until the next reboot, and I am advised (thanks Tony van der Hoff and Tauno Voipio) that it would be better to add the user (in this case snmp) to the group (i2c) which has access to the I2C bus.

MRTG commands

Here's what I am using in an include file for my MRTG configuration.

# Raspberry Pi 4 - Air pressure

Target[raspi4-air-pressure]: .
MaxBytes[raspi4-air-pressure]: 110000
MaxBytes2[raspi4-air-pressure]: 110000
Title[raspi4-air-pressure]: Sea-level Air Pressure for Raspberry Pi 4
Options[raspi4-air-pressure]: expscale, gauge, nopercent, growright, unknaszero, noo
YLegend[raspi4-air-pressure]: Pressure kPa
ShortLegend[raspi4-air-pressure]: Pa
Factor[raspi4-air-pressure]: 0.01
kMG[raspi4-air-pressure]: ,
Legend1[raspi4-air-pressure]: Air Pressure hPa
LegendI[raspi4-air-pressure]: Pressure hPa
PageTop[raspi4-air-pressure]: <H1>Sea-level Air Pressure at Edinburgh</H1>


Note that the output from standard MRTG is not very attractive for air pressure as you can't constrain the range to be a narrow band around 1013 hPa, so  I wrote a small program to read the log files from MRTG and produce a more attractive output.  This is from my Arduino-based BMP085 pressure monitor made some years back:

Air-pressure graph

Using the BME280 sensor

In mid-2015 a new sensor was released from Bosch which added humidity sensing to the pressure and temperature from the BMP085/180 series.  Using the sensor is very similar to the instructions above, but the registers are different, and because the temperature reading is required to correct the pressure and humidity readings, I had to use a slightly different approach in that I now run the Python script which produces the ambient data readings to three files once a minute (my first time with cron), and then just read out the content of the files from the SNMP pass functions.

The Python script I used is here.  You will likely want to modify it to suit your own requirements.  As-supplied it write to three files in /tmp named:  temperature_millidegrees.txt, pressure_pascals.txt and humidity_percent.txt.  The latter name is a misnomer as it write 1000 times the percent value, so that MRTG will render it more accurately in the longer term plots.  You should be able to make this file executable, copy it to /usr/local/bin and run it.

Thanks to Gennadiy who notes that the address in the file is hard-coded to 0x77.  However, BME280s may be at 0x77 or 0x76, depending on the state of the SDO pin.  Some modules he obtained from China had the SDO pin grounded, resulting in the 0x76 address.  It's easy enough to alter the Python file if this applies to you.

To test

ls -l /tmp/*.txt

Look for the date on the files changing when you run the Python script.

Setting up the cron job

You can now copy the python script to /usr/local/bin and check that you can run it from there.

sudo cp /usr/local/bin

Create a script to run the Python program, and make it executable.

nano bme280
python /usr/local/bin/
chmod +x bme280

and copy that file to /usr/local/bin as well:

sudo cp bme280 /usr/local/bin

You need to add one line to the crontab file:

sudo nano /etc/crontab

* * * * * root /usr/local/bin/bme280

Updating the SNMP configuration

I used a sequence of three OIDs for the three variables:

    . (temperature)
    . (pressure)
    . (humidity)

 so three scripts for the SNMP pass commands are:

snmp-atmos-temp snmp-atmos-press snmp-atmos-humid
if [ "$1" = "-g" ]
echo .
echo gauge
cat /tmp/temperature_millidegrees.txt
exit 0
if [ "$1" = "-g" ]
echo .
echo gauge
cat /tmp/pressure_pascals.txt
exit 0
if [ "$1" = "-g" ]
echo .
echo gauge
cat /tmp/humidity_percent.txt
exit 0

The three scripts all live in /usr/local/bin, and need to be marked as executable:

chmod +x <script-name>

The updates to /etc/snmp/snmpd.conf are:

pass . /bin/sh /usr/local/bin/snmp-atmos-temp
pass . /bin/sh /usr/local/bin/snmp-atmos-press
pass . /bin/sh /usr/local/bin/snmp-atmos-humid

followed by a restart of the SNMP daemon:

sudo /etc/init.d/snmpd restart

You should now check that the SNMP is behaving as expected, using snmpget:

/usr/bin/snmpget -v 2c localhost -c public .
/usr/bin/snmpget -v 2c localhost -c public .
/usr/bin/snmpget -v 2c localhost -c public .

Suitable MRTG commands are given below.  See the MRTG Reference for more details.

# Raspberry Pi 3 - Ambient temperature indoors

Target[raspi3-air-temp]: .
MaxBytes[raspi3-air-temp]: 100000
MaxBytes2[raspi3-air-temp]: 100000
Title[raspi3-air-temp]: Ambient temperature indoors
Options[raspi3-air-temp]: gauge, nopercent, growright, unknaszero, noi
YLegend[raspi3-air-temp]: Temperature C
ShortLegend[raspi3-air-temp]: C
kMG[raspi3-air-temp]: ,
Factor[raspi3-air-temp]: 0.001
Legend2[raspi3-air-temp]: Indoors temperature in C
LegendO[raspi3-air-temp]: Indoors temperature
PageTop[raspi3-air-temp]: <H1>Downstairs - Ambient Temperature Indoors</H1>

# Raspberry Pi 3 - Air pressure

Target[raspi3-air-pressure]: .
MaxBytes[raspi3-air-pressure]: 110000
MaxBytes2[raspi3-air-pressure]: 110000
Title[raspi3-air-pressure]: Sea-level Air Pressure for Raspberry Pi #3
Options[raspi3-air-pressure]: expscale, gauge, nopercent, growright, unknaszero, noi
YLegend[raspi3-air-pressure]: Pressure hPa
ShortLegend[raspi3-air-pressure]: Pa
Factor[raspi3-air-pressure]: 0.01
kMG[raspi3-air-pressure]: ,
Legend2[raspi3-air-pressure]: Air Pressure hPa
LegendO[raspi3-air-pressure]: Pressure hPa
PageTop[raspi3-air-pressure]: <H1>Sea-level Air Pressure at Edinburgh</H1>

# Raspberry Pi 3 - Ambient air humidity

Target[raspi3-air-humidity]: .
MaxBytes[raspi3-air-humidity]: 100000
MaxBytes2[raspi3-air-humidity]: 100000
Title[raspi3-air-humidity]: Relative humidity for Raspberry Pi #3
Options[raspi3-air-humidity]: gauge, nopercent, growright, unknaszero, noi
YLegend[raspi3-air-humidity]: Humidity %
ShortLegend[raspi3-air-humidity]: %
kMG[raspi3-air-humidity]: ,,
Factor[raspi3-air-humidity]: 0.001
Legend2[raspi3-air-humidity]: Ambient air relative humidity
LegendO[raspi3-air-humidity]: Ambient air relative humidity
PageTop[raspi3-air-humidity]: <H1>Downstairs Ambient Air Relative Humidity</H1>

I then run a small Delphi program to process the raw MRTG log files to present the pressure variable on a more sensible scale, as seeing 0...1000 hPa on one graph rather loses the variations!  At the moment I am comparing two BME280 boards in the same location, just to see how accurate they are, before moving one downstairs and the other upstairs.  You can see the comparison here.

The current output from all three variables can be seen below:

Upstairs indoor temperature - C
Sea-level air pressure - hPa
Upstairs ambient air humidity - %

Thanks to folk in this Adafruit discussion forum for their help and encouragement.  No thanks for the ridiculously large number of brackets in their example C code in the BME280 datasheet which made it so much more difficult to understand!  And no thanks to Delphi for not including an arithmetic shift right for signed integers!  All this added many hours to my debugging time....

GPS Performance

In situations where a GPS puck is used (e.g. for precise timekeeping) it may be useful to plot the number of satellites which are in theory visible, and the number of satellites used by the GPS daemon to return a position fix and time data (PPS).  I have played with a Python script for this, but the snag is that you need to wait for the gpsd to emit a message with the required information.  I therefore also tried writing my own two programs to retrieve the information directly from gpsd, and while this works on recent RPi systems (with GPSD 3.11) it fails on earlier systems which have gpsd 3.6 (and which seems to to upgrade?).  Update 2016-Apr-12: combined the two programs into one.


  1. Create the source file for the C program.
  2. Install the gpsd development library.
  3. Compile the program.
  4. Test that the program works for both "visible" and "used".
  5. Copy the working program to a system location on the path
  6. Edit the SNMP configuration to add two new "pass" commands.
  7. Restart the SNMP daemon.
  8. Check that you can see the numbers via SNMP.
  9. Create suitable MRTG configuration file.

In more detail:

  1. Source for gpsGetSatellites.c
    /* Copyright (c) 2016 David Taylor <>
    Permission to use, copy, modify, and distribute this software for 
    any purpose without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.
    The user of the software is responsible for ensuring the accuracy 
    of any data produced by the software.
    This software may not be used in safety-critical
    or life-critical systems. */
    #include <gps.h>
    #include <stdio.h>
    int main (int argc, char **argv) {
      int status, used, visible;
      struct gps_data_t gpsdata;
      #define OID_VISIBLE "."
      #define OID_USED "."
      if ((argc > 2) && (strcmp ("-g", argv[1]) == 0))
        status = gps_open (GPSD_SHARED_MEMORY, DEFAULT_GPSD_PORT, &gpsdata);
        status = gps_read (&gpsdata);
        used  = gpsdata.satellites_used;
        visible = gpsdata.satellites_visible;
        gps_close (&gpsdata);
        if (strcmp (OID_VISIBLE, argv[2]) == 0) {
          printf (OID_VISIBLE);
          printf ("\n");
          printf ("gauge\n");
          printf ("%d\n", visible);
        if (strcmp (OID_USED, argv[2]) == 0) {
          printf (OID_USED);
          printf ("\n");
          printf ("gauge\n");
          printf ("%d\n", used);
      return 0;


  2. $ sudo apt-get install libgps-dev
  3. $ gcc gpsGetSatellites.c -o gpsGetSatellites -lgps
  4. $ ./gpsGetSatellites -g .
    $ ./gpsGetSatellites -g .

  5. $ sudo cp gpsGetSatellites /usr/local/bin
  6. Edit snmpd configuration:
    $ sudo nano /etc/snmp/snmpd.conf
    pass . /usr/local/bin/gpsGetSatellites
    pass . /usr/local/bin/gpsGetSatellites
  7. Restart snmpd:
    $ sudo /etc/init.d/snmpd restart
  8. Test both SNMP OIDs:
    $ snmpget -v 2c localhost -c public .
    iso. = Gauge32: 19
    $ snmpget -v 2c localhost -c public .
    iso. = Gauge32: 10
  9. #---------------------------------------------------------------
    # Raspberry Pi 14 - GPS Satellites Visible and Used
    Target[raspi14-gps]: .
    MaxBytes[raspi14-gps]: 100
    MaxBytes2[raspi14-gps]: 100
    Title[raspi14-gps]: GPS Satellites Raspberry Pi #14
    Options[raspi14-gps]: integer, gauge, nopercent, growright, unknaszero
    YLegend[raspi14-gps]: Satellites
    ShortLegend[raspi14-gps]: Satellites
    Legend1[raspi14-gps]: Used
    Legend2[raspi14-gps]: Visible
    LegendI[raspi14-gps]: Used
    LegendO[raspi14-gps]: Visible
    PageTop[raspi14-gps]: <H1>RasPi-14 - GPS Satellites in view and used</H1>

You could use this information to see how the location of an indoor GPS antenna and the quality of the receiver affects the timekeeping accuracy of an NTP server.  For example, below are two systems, one with a poorly located somewhat older receiver, and the other with a well-located HAB supplies GPS.

Older receiver, poor location:

Note that the gpsd version was changed from 3.6 to 3.11 on 2016-Apr-12 at 13:00 UTC, and there is a noticeable difference in behaviour.  The number of "visible" satellites appears to be less.

HAB supplies receiver, better antenna location:


Python and shell script alternatives

Although the solution above is believed to be optimum based on getting the data as quickly as possible, the initial development of this monitoring code was done in Python, although I needed external help (thanks, Steve O'Hara-Smith) to get it working.  The items I ended up with were a mixture of shell code and Python.  It seems that the C program versions above won't work with the earlier 3.6 version of GPSD which was supplied with Raspbian Wheezy, and which doesn't get upgraded when you update to Jessie.  Why not!?

For available satellites (visible satellites), a shell script named: snmp-get-gps-available:

if [ "$1" = "-g" ]
gpspipe -r | egrep --line-buffered  'GPGSA' | stdbuf -o0 gawk  '-F,' '
  if ( $1 ~  /GPGSA/ ) {
    for (i = 1; i <= NF; i++) {
      if ( $i != "" ) {
        # print ( $i ) ;
        AVAILABLE++ ;
      } ;
    } ;
    print ".";
    print "gauge";
    print ( AVAILABLE ) ;
    exit 0
  } ;
exit 0

and its pass entry:

pass . /bin/sh /usr/local/bin/snmp-get-gps-available

For the used satellites, a Python program (, and shell script (

import gps
import json
from collections import Counter

# Listen on port 2947 (gpsd) of localhost
session = gps.gps("localhost", "2947") | gps.WATCH_NEWSTYLE)

while True:
        report =
        # Wait for a 'SKY' report and display the current time
        # To see all report data, uncomment the line below
        # print report
        if report['class'] == 'SKY':
            # print report
            session = None
            if 'satellites' in report:
                total_sats = len (report.satellites)
                used_sats = 0
                for sat in report.satellites:
                    if sat['used']:
                        used_sats = used_sats + 1
                print "."
                print "Gauge"
                print used_sats
                session = None
    except KeyError:
    except KeyboardInterrupt:
    except StopIteration:
                session = None
                print "GPSD has terminated"

The shell script:

if [ "$1" = "-g" ]
exit 0

and its pass entry:

pass . /bin/sh /usr/local/bin/

Using MRTG on the Raspberry Pi itself

Paul Marsh (@UHF_Satcom on Twitter) has kindly sent a script you could use to produce data directly in the format MRTG needs.  As I run MRTG on a separate Windows PC and get the data over SNMP, I've not tested this script.  This script prints MRTG compatible output as number of satellites used in fix, number of visible satellites, 0 and "gps stats".

fix=`gpspipe -r | egrep --line-buffered  'GPGGA' | stdbuf -o0 gawk '-F,' '{print $8;exit}'`
echo $fix
gpspipe -r | egrep --line-buffered  'GPGSA' | stdbuf -o0 gawk  '-F,' '
  AVAILABLE = -1 ;
  if ( $1 ~  /GPGSA/ ) {
    for (i = 1; i <= NF; i++) {
      if ( $i != "" ) {
        AVAILABLE++ ;
      } ;
    } ;
    print ( AVAILABLE ) ;
    print ( "0" ) ;
    print ( "GPS stats" ) 
    exit 0
  } ;

Relay status

John Parker asked about monitoring a relay status, and then kindly sent the following notes:

I finally got it working, after battling with it, on and off, for quite some time.

Eventually I got it working via pigpio.

Here are the steps:

1) Install pigpio

2) Set it up to start the daemon on boot

3) Create a (very) simple python script which I called and stored it in /home/pi/relay:

import pigpio
pi = pigpio.pi()
pi.set_mode(14, pigpio.INPUT)

I then followed a system similar to how you read air pressure using BMP085, creating a shell script in /usr/local/bin:

if [ "$1" = "-g" ]
echo .
echo gauge
python /home/pi/relay/
exit 0

4) Call this from the snmp file as per normal. It works well! 

My next step is to see if I can convert it into a moisture detector, so if we get leak in our server room aircon, we'll be able to detect it...


  • To the folk in the comp.protocols.time.ntp and other Usenet newsgroups who were enormously helpful and patient with someone whose Linux knowledge is sparse!
  • My thanks to Webshed for uploading the temperature sensor information.
  • To Adafruit for their tutorial on using their BMP180 board and related information.
  • To Andy Burns, Dennis Lee Bieber, Tony van der Hoff, Nomen Nescio and Tauno Voipio for their help with the permissions issue with the BMP180 sensor.
  • To John Parker (Australia) for the relay monitoring code.

Copyright © David Taylor, Edinburgh   Last modified: 2016 Aug 21 at 16:13