The last couple of months, I have been amazed about the Raspberry Pi. I won’t go into great detail on this wonderful device, other than the obvious.

  • It is cheap
  • It comes with Ethernet, HDMI
  • It runs Debian Linux
  • It has GPIO, general purpose input output, pins on the board

So, the device itself is just screaming for some interesting projects, interfacing with stuff that normally are not integrated with your IT stack. I’ve tried it out in a few different ways already, and I’ve bought a handful of devices. One of them has a fixed position, connected to my TV, running XBMC.

Well, let’s go back a few years in time. Quite many years, will say. Back to the days when I had just started growing a beard, and was just that naïve that only youngsters freshly out of high-school can be. I headed off to university and one of the first day of the introduction week we went to the student pub. There I saw one of the coolest things since the invention of sliced bread, a pedestrian crossing light.

Normally, such thing would not leave that much of an impression with me, but this one was special. Our own student pub was one of three student pubs in the same basement corridor. But there was only one WC. In principle, this was not a problem early in the evening, but as the night went on, the line to the WC was an annoyance. In our pub, the one with the crossing light, we were less stressed about it than people in the other pubs, since our crossing light was connected to the lock of the WC door. Whenever the lock was locked, our crossing light was red; hence when the door was unlocked it was green.

When we relocated the pub, we ended up in a location where the WC situation was much better. I had personally made sure that we brought the crossing light with us, but I could never come up with as good of a use for it. This was a long time ago, but the bright idea (pun intended) stuck with me over the years.

When I implemented Nagios/OP5 at my new workplace, I started playing with the thought that I wanted some way of raising the attention of the monitoring with my guys. The classical “big screen on the wall” was of course one of the first things that crossed our minds. This was easy, and people notice it – goal achieved. But I wanted something else, something more… catchy.

Just by a coincident, I got in contact with a guy who is responsible for replacing old bulb-based traffic lights with new LED-based traffic lights. He gave me a handful of 3-light (red, yellow, green) pedestrian crossing lights, and now I was able to get going with my latest project.

A Nagios/OP5 installation that shows service states on a traffic light.

Note that you are on your own when connecting the things together. If you are not completely sure of what you are doing, then don’t. I’ve been doing things like this for a while, so I trust myself. But I do not take any responsibility what so ever for any mistakes you do yourself. This project involves 220V, which can be lethal. Don’t blame me if things go bo-boo. End of disclaimer.

 

This is the conceptual view:

All in all, I’ve got a Nagios/OP5 installation in a virtual machine. In this example, one of my services is configured with an event handler, pointing to a command configured in checkcommands.cfg. I decided that the communication between my monitoring system and the Raspberry Pi would go over nrpe, which is anyways the standard Nagios Agent. Adding a couple of scripts on the server to take care of events, and the client side, to control the GPIO, was fairly simple.

Let us go through the whole chain on both hosts, the Nagios/OP5 system and the Raspberry Pi. I will start in a reverse order, as the Nagios configuration is simple and does not require much of explanation. Which service to chose for your traffic light is up to you. There are a couple of interesting constructs that come with OP5, that is not readily available out of the box in a Nagios installation. One of these is the “Business process view”, that allows you to perform logical operations on service states. You can also create new services from these aggregations. I will leave this part out of this blog entry, but the principle is so easy, that if you manage with the rest in this article, your should not have a hard time figuring that part out either.

In principle, I just chose one service and added an event_handler to it. That’s it. The event_handler is configured as any other command in the _checkcommands.cfg_ file. An event handler should take care of a couple of checks, so that you are sure that you really want to do something when the event hander is triggered, as it is triggered quite often. Basically, check the state (OK, WARNING, CRITICAL) and the state type (hard, soft) and make up your mind.

As mentioned before, I chose to use _check_nrpe_ to integrate Nagios with my Raspberry Pi, since it is readily available and very simple to configure. All I need to do, is to remotely run a script on the Raspberry Pi, which nrpe allows me to do after a very simple configuration. I just had to come up with a name for my remote command, add it to the nrpe configuration on the Raspberry Pi, restart nrpe, and start using check_nrpe on the Nagios/OP5 server.

On the Nagios/OP5 server, you need to get the following into your configuration files. When using OP5 there is a very simple web-gui to do this in. Othervise just fire up your favorite editor (which should be _vi_).

Here is the service in the Nagios/OP5 services.cfg for my dummy service to monitor and display on the traffic light. The magic is in the sauce, I mean event_handler:

1
2
3
4
5
6
7
8
# service 'remote debug'
define service{
  use default-service
  host_name pi-s001
  service_description remote debug
  check_command check_nrpe!-H $HOSTADDRESS$ -c kmg_dummy
  event_handler event_ampel
}

This event handler is configured in the Nagios/OP5 configuration file checkcommands.cfg. Note the arguments I am sending to the script.

  • $SERVICESTATE$ – Nagios macro for the current state of the service
  • $SERVICESTATETYPE$ – Nagios macro for the current type (soft or hard) of the service
  • $HOSTNAME$ – Nagios macro for the service’s host
  • $SERVICEDESC$ – Nagios macro for the name of the service
  • $SERVICEATTEMPTS$ – Nagios macro for the number of attempts
1
2
3
4
5
6
</div>
# command 'event_ampel'
define command{
  command_name event_ampel
  command_line $USER1$/kmg/event_ampel $SERVICESTATE$ $SERVICESTATETYPE$ $HOSTNAME$ $SERVICEDESC$ $SERVICEATTEMPT$
}
The $SERVICEATTEMPTS$ macro together with the $SERVICESTATETYPE$ and the $SERVICESTATE$ gives you the possibility to actually try and fix a problem before Nagios/OP5 even has notified a sysadmin. In a default installation/config, Nagios will test a service so many times before it is a hard CRITICAL, which is notified to the outside world. If you write your event handler in such way, that it tests these parameters, i.e service state = CRITICAL, type = soft, service attempts = 3, then you can perform something like restarting a server, before waking up the sysadmin. My event handler is a bit simpler than that. I am just to trigger a relay, controlling a light bulb, so I skipped some of that. This is the event handler script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/ksh

state=$1
statetype=$2
serviceHost=$3
service=$4
serviceattempt=$5

raspberryPi=10.64.150.5

logfile=/opt/monitor/var/eventhandler.log

# Sep 25 14:53:14
date=`date +"%b %d %H:%M:%S"`

case "$state" in
  OK)
    command=kmg_ampel_green
    ;;
  WARNING)
    command=kmg_ampel_yellow
    ;;
  CRITICAL)
    command=kmg_ampel_red
    ;;
esac
/bin/echo -en "$date; restart_windows_service.sh; $serviceHost:$service; Got a $statetype $state at try $serviceattempt, sending $command to host $raspberryPi " >> $logfile

/opt/plugins/check_nrpe -H $raspberryPi -c $command >> $logfile
echo "Set Ampel ok"

If you by any chance had the Raspberry Pi setup and running already, you could test the event handler and the integration in two ways from the Nagios/OP5 host:

1
2
3
4
5
6
#--- check that nrpe works (i.e allowed_hosts on the pi is set properly)
op5$ /opt/plugins/check_nrpe -H 10.64.150.5
#--- check that the commands config on the pi works
op5$ /opt/plugins/check_nrpe -H 10.64.150.5 kmg_ampel_green
#--- check that the whole stack works
op5$ ./event_ampel kmg_ampel_red

So far, the Nagios configuration. We also need the relay control and the Raspberry Pi configuration. This is the hardware you need to complete this project:

  • One Raspberry Pi
  • 5V DC source (Micro USB charger)
  • 12V DC source (to drive the relays)
  • 3 x 5kOhm resistors
  • 3 x BC237C transistors
  • 3 x Relays, 12VDC activation/250AC switching
  • A few cables.
I used a 12V/DC power source to drive the relays, since I could not quickly find any 5V/DC relays. If you do find such relays, just connect the Raspberry Pi pin 2 (5V) to the driver, and you will save yourself a couple of bucks.
Install the Debian Squeeze on a SD card, enable SSH, and expand the root fs at the first boot. Then log into your box and install ksh and nagios-nrpe-server.
1
2
sudo apt-get install ksh
sudo apt-get install nagios-nrpe-server

That is basically it. You will survive without ksh, but since I am an old fart, I tend to stick to what I know from before. Ksh was there in the dawn of UNIX. In the good old days, it was the bread and butter of decent scripting. Nowadays you’ll manage with bash, and wont miss ksh a lot. More about that in a different blog post. If you don’t care for ksh, just change the references to it in my examples to bash.

Now we will configure the nrpe daemon correctly.

1
2
3
4
5
6
7
8
9
10
11
12
pi@raspberrypi /etc/nagios $ grep allowed_hosts nrpe.cfg
allowed_hosts=127.0.0.1,192.168.2.34,194.40.128.84
pi@raspberrypi /etc/nagios $ cat nrpe.d/kmg_commands.cfg
command[kmg_ampel_red]=/app/prd/op5/bin/ampel red
command[kmg_ampel_yellow]=/app/prd/op5/bin/ampel yellow
command[kmg_ampel_green]=/app/prd/op5/bin/ampel green
command[kmg_ampel_blink]=/app/prd/op5/bin/ampel blink
command[kmg_ampel]=/app/prd/op5/bin/ampel blink
command[kmg_dummy]=/app/prd/op5/bin/dummy
pi@raspberrypi /etc/nagios $ sudo /etc/init.d/nagios-nrpe-server restart
[ ok ] Stopping nagios-nrpe: nagios-nrpe.
[ ok ] Starting nagios-nrpe: nagios-nrpe.

With that taken care of, the integration between the Nagios/OP5 server and the Raspberry Pi is set up. The best way to test this is the commands in one of the examples above (check_nrpe -H 10.64.150.5). If that doesn’t work, kill the nrpe process on the Raspberry Pi with “kill” and start it again. That usually solves most problems.

Interfacing with the GPIO ports is extremely easy in the Debian/Raspbian squeeze. You just echo some commands to files in the /sys filesystem. Firstly you’ve got to enable some GPIO ports and set the direction. I’ve done this in a startup script, /etc/init.d/ampel, to which I also symbolically linked /etc/rc2.d/S99ampel so that it will automatically do this at reboot. Debian is a weird beast, though. Note that I put the startup script in rc2.d, which is the default runlevel for Debian, whereas I would have put this in rc3.d on an Ubuntu box.

Here is my /etc/init.d/ampel script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/ksh
# /etc/init.d/ampel
#

### BEGIN INIT INFO
# Provides: ampel
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Ampel
# Description: Ampel
### END INIT INFO
################################################################################

TS=$(date "+%Y%m%d %H:%M:%S")
echo "$TS; $0 $1" >> /var/log/ampel.log

case $1 in
  start)
    echo "$TS; setup gpio" >> /var/log/ampel.log

    echo "17" > /sys/class/gpio/export
    echo "18" > /sys/class/gpio/export
    echo "21" > /sys/class/gpio/export

    echo "out" > /sys/class/gpio/gpio17/direction
    echo "out" > /sys/class/gpio/gpio18/direction
    echo "out" > /sys/class/gpio/gpio21/direction

#--- to rid the sudo part - change the permissions

    chmod 666 /sys/class/gpio/gpio17/value
    chmod 666 /sys/class/gpio/gpio18/value
    chmod 666 /sys/class/gpio/gpio21/value
    ;;
esac
This makes sure that the GPIO pins are correctly set, which you can control in the file system by checking the /sys/class/gpio directory. Note that I am changing the file permissions for the “value” files. If you don’t do this, you must write to these files as root, which is easily done by using “sudo”. But since the Raspberry Pi isn’t a state of the art box when it comes to security anyways, I just decided that if you by any chance is logged in to the system, you should be able to set these values, never mind which user you are.
If you see “your” gpio pins there, you should be fine.
1
2
3
4
5
6
7
8
9
10
pi@raspberrypi ~ $ ls -la /sys/class/gpio/
total 0
drwxr-xr-x 2 root root 0 Aug 16 16:58 .
drwxr-xr-x 26 root root 0 Aug 16 16:58 ..
--w------- 1 root root 4096 Aug 16 16:58 export
lrwxrwxrwx 1 root root 0 Aug 16 16:58 gpio17 -> ../../devices/virtual/gpio/gpio17
lrwxrwxrwx 1 root root 0 Aug 16 16:58 gpio18 -> ../../devices/virtual/gpio/gpio18
lrwxrwxrwx 1 root root 0 Aug 16 16:58 gpio21 -> ../../devices/virtual/gpio/gpio21
lrwxrwxrwx 1 root root 0 Aug 16 16:58 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
--w------- 1 root root 4096 Aug 16 16:58 unexport
The nrpe configuration in /etc/nagios/nrpe.d/kmg_commands.cfg points out the /app/prd/op5/bin/ampel script, which is merely a wrapper, if there were anything clever to be done before actually switching the relays. In this example, I am not logging anything, and there is very little magic around it. It is usually wise to have such a wrapper between nrpe and whatever you want to perform on the system; for me it comes naturally to do it this way.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/ksh

ampel_bin=/app/prd/ampel/bin
#ampel="sudo $ampel_bin/setAmpel_a1"
ampel="$ampel_bin/setAmpel_a1"

blink(){
  $ampel all
  sleep 0.2s
  $ampel none
  sleep 0.2s
  $ampel all
  sleep 0.2s
  $ampel none
  sleep 0.2s
}

red(){
  blink
  echo "  - Set ampel to: red"
  $ampel red
}
yellow(){
  blink
  echo "  - Set ampel to: yellow"
  $ampel yellow
}
green(){
  blink
  echo "  - Set ampel to: green"
  $ampel green
}

echo "Ampel"
case $1 in
  red)
    red
    ;;
  yellow)
    yellow
    ;;
  green)
    green
    ;;
  blink)
    blink
    ;;
esac

exit 0
In the end, this wrapper will execute the “$ampel” script, which is set to “/app/prd/ampel/bin/setAmpel_a1″ with one parameter; red, yellow, green, or blink. This is the setAmpel_a1 script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/ksh

#-----------------------------
# Base configuration
#-----------------------------
this_dir=$(cd `dirname $0`; pwd)
base_dir=$(cd `dirname $0`/..;pwd)

. $base_dir/conf/gpio.conf

off=0
on=1

red(){
  echo "$on" > /sys/class/gpio/gpio${a1red}/value
}

yellow(){
  echo "$on" > /sys/class/gpio/gpio${a1yellow}/value

}

green(){
  echo "$on" > /sys/class/gpio/gpio${a1green}/value
}

none(){
  echo "$off" > /sys/class/gpio/gpio${a1red}/value
  echo "$off" > /sys/class/gpio/gpio${a1yellow}/value
  echo "$off" > /sys/class/gpio/gpio${a1green}/value
}

all(){
  echo "$on" > /sys/class/gpio/gpio${a1red}/value
  echo "$on" > /sys/class/gpio/gpio${a1yellow}/value
  echo "$on" > /sys/class/gpio/gpio${a1green}/value
}

#================================
# MAIN
#================================
case $1 in
  red)
    none
    red
    ;;
  yellow)
    none
    yellow
    ;;
  green)
    none
    green
    ;;
  none)
    none
    ;;
  all)
    all
    ;;
esac
That’s all folks!