...making Linux just a little more fun!

An NSLU2 (Slug) Reminder Server

By Silas Brown

LG #138 contained an article, "Debian on a Slug", in which Kapil Hari Paranjape described how to install Debian on an NSLU2 device, so that it can be made into a general-purpose server (a firewall, backup server, Web server, etc.) He also added a sound device so that it can be used to play music.

Another application for such a device is as an alarms and reminders system. This is more than a simple alarm clock or PDA, because the Slug is much more programmable: once you have installed a lightweight speech synthesizer, the Slug can be made not only to generate verbal reminders (which few PDAs can do), but also to check for information on the Internet and adjust its announcements, accordingly. It is a useful alternative to leaving a PC switched on for long periods just to do that job (or possibly forgetting something because the computer was switched off). If you are attempting to learn a foreign language, the Slug reminders system can help with that, also.

Speech Synthesis

The eSpeak speech synthesizer is lightweight enough to run on the Slug, and is also available as a Debian package, although if you are running Debian stable then you will likely find that installing from source will get you a significantly improved version. (Be sure to completely remove the Debian package and its libraries, before compiling from source.) eSpeak produces very clear English speech in several accents, and also supports quite a few other languages (some better than others). Installation is straightforward, except you might find that the audio output doesn't work; if this is the case, then simply write audio to a file or pipe and play using aplay in the alsa-utils package. (Note, however, that some old versions of eSpeak won't write to a pipe when asked. If it's just a short reminder, you can write to a file in /dev/shm and delete it after playing.)

Personally I use eSpeak with my language-practice program Gradint, which I have adapted to run on the Slug. Besides generating vocabulary-practice sessions using "graduated-interval recall", Gradint can also be made to produce other speech-reminder "patterns" such as:

For languages that eSpeak cannot yet produce well, if all the possible utterances are known in advance, then Gradint allows you to generate them on another system and transfer them across (or simply use recorded sounds instead).

Dealing with Unreliable Sound

It appears that some USB sound adapters will fail, from time to time, especially if they are plugged into an unpowered hub. This is probably due to their highly variable power consumption. The symptoms are that the sound stops, and the system behaves as though the sound adapter has disappeared from the USB bus. To restore sound functionality, the adapter may need to be unplugged and re-inserted, or perhaps even the hub it has been connected to may need to be unplugged and re-inserted. For this reason, never put the sound adapter on the same hub as the storage device(s). (Some kernel versions won't be able to use certain sound adapters, if they are attached to USB 2 hubs, anyway; they need to be attached to USB 1.1 hubs or directly to the NSLU2, unless you update your kernel.) It is also advisable to minimise the number of devices the sound adapter shares an unpowered hub with, or even connect it directly to the NSLU2, if you don't have many other USB devices to connect. (You could connect it to a powered hub, but I am trying to avoid the use of powered hubs in an attempt to minimise extra power consumption and reduce the amount of wiring.)

In order to avoid missing your reminders due to the sound adapter having failed, it is advisable to periodically run a script that ensures the sound device is still present, and alerts you if it is not. The alert can be by means of a console beep. (Unfortunately, there does not yet appear to be an NSLU2 equivalent of the PC-speaker kernel patches that allow the speaker to generate more than a simple beep.) The following script will do this:

#!/bin/bash
if ! amixer scontents >/dev/null; then
  # sound adapter has somehow gone down
  cd
  if test -e .soundcheck-beeping; then exit; fi
  touch .soundcheck-beeping
  while true; do
    for N in 1 2 3 4 5; do echo $'\a' > /dev/tty1; sleep 1; done
    if amixer scontents >/dev/null; then break; fi # came back
  done
  rm .soundcheck-beeping
fi

The script should be run as root, so that it can access /dev/tty1 to make the NSLU2 beep. It should be run at various times (perhaps from crontab), but take care not to run it in the middle of the night, unless you want to be awoken whenever the sound happens to fail. (It may be better to wait until just before the time the morning alarm would have happened.)

It will likely help to use amixer to set the sound level low, so as to reduce peaks in USB-bus current. If using unpowered speakers (which is a good idea because powered speakers can be more susceptible to picking up annoying noise from mobile phones, etc., and anyway they take more power), consider attaching only one speaker, if stereo sound is not necessary, since this should further reduce the current, and it also means you can salvage an unpowered speaker from an unused pair of powered speakers (one of which is usually unpowered), rather than having to obtain new ones. Then experiment with different levels, to find how low you can go whilst still being able to hear it clearly. This will vary with the sound adapter and the speakers.

Wireless headphones may need the level set lower still; cheap FM cordless headphones can easily be overloaded and lose the signal, if the input sound peaks too loudly. You may find that the lowest setting of amixer (the resolution of which is limited to that of the sound adapter) is still too high, in which case you need to ensure that the sound data itself is not too loud. This is one of the functions I had to add to Gradint.

Using the Power Button

The NSLU2 has only one built-in input device: the power button. Thankfully, this can be re-programmed, so, for example, you can use it to acknowledge an alarm without having to connect some other input device or connect across the network. On Debian at least, the NSLU2 power button sends a "Ctrl-Alt-Delete" event to init, so you can edit /etc/inittab and change the ctrlaltdel line to run whatever script you want. Since it's rather long-winded to script an automatic edit of /etc/inittab followed by a signal to init, every time one of your scripts wants to change the function of the power button, it makes sense to point inittab to a shell script somewhere, which you can then modify at will. Personally, I use something like the following:

#!/bin/bash
cd ~user   # note: we are root
if test -e .powerbutton.pid; then
  kill $(cat .powerbutton.pid)
elif test -e .powerbutton2.pid; then
  kill $(cat .powerbutton2.pid)
else
  if test -e .about-to-shutdown; then
    reminders.sh "en Shutting down."
    rm -f .powerbutton.pid .about-to-shutdown
    /sbin/halt
  fi
  echo $'\a' > /dev/tty1
  touch .about-to-shutdown
  reminders.sh "en Press again to shut down." &
  (sleep 10 ; rm .about-to-shutdown) &   # the & is important
fi

This looks for a file called .powerbutton.pid, which should, if it exists, contain the process ID of some process that needs to be terminated when the power button is pressed (for example, the alarm process). If .powerbutton.pid does not exist (and there is a check for .powerbutton2.pid also, in case you need to run some lower-priority reminder sequence at the same time as the immediate one), then the power button will halt the machine, but, before it does so, it will prompt the user to press again (within 10 seconds), in order to protect against accidents: if you pressed the button half a second after the process happened to terminate by itself, then you probably don't want to shut down the machine. The console beep is there so that, if the sound or speech somehow fails, there is at least some indication of response. The line in the script marked "the & is important" is marked thus because the script needs to return control to init, so that init can catch the repeat press of the power button within the 10-second period; otherwise, init may queue that event until after the script finishes, when the 10 seconds are up, which will mean it will not be possible to use the power button to halt the machine.

Other Remarks

If you want to reduce the amount of light given off by the Slug (for example because you want to run it in a bedroom which needs to be dark), you can turn off all the LEDs except the Ethernet LED and the power button LED, by using the leds command. For example, you can put this in root's crontab:

@reboot sleep 5; for N in ready status disk-1 disk-2; do leds $N off; done

The sleep 5 is to avert a race condition with the system init scripts, which will otherwise switch the LEDs back on. You may still have too much light coming from the LEDs on USB devices (most flash storage devices have bright LEDs that may flicker during use), so you may have to position these carefully, and/or point their LEDs downward onto a dark surface.

The NSLU2 seems to keep good clock time (better than many PCs), but you might want to install ntp to keep the clock synchronised. To save RAM, you can prevent ntp from running as a daemon by adding an exit command near the start of /etc/init.d/ntp.conf, and instead run it from root's crontab using something like

37 2 * * * /usr/sbin/ntpd -n -q -g >/dev/null

since updating once a day should easily be accurate enough. (Note that it should run after 2am, if you want it to pick up daylight-saving changes.)

If you do not have a PDA to connect as an NSLU2 terminal, you may also like to try using a screenreader with eSpeak in place of a display. An NSLU2 with a screenreader and a USB keyboard could be enough to make a simple workstation for a blind user, although it does require some setting up.

Talkback: Discuss this article with The Answer Gang


[BIO]

Silas Brown is a legally blind computer scientist based in Cambridge UK. He has been using heavily-customised versions of Debian Linux since 1999.


Copyright © 2007, Silas Brown. Released under the Open Publication License unless otherwise noted in the body of the article. Linux Gazette is not produced, sponsored, or endorsed by its prior host, SSC, Inc.

Published in Issue 141 of Linux Gazette, August 2007

Tux