It's been a while since I've made any Arduino & node.js mashups so decided to address that this week. I've always wanted to use Arduino to visualise in a very tangible way some form of data from a computer - be it data from a website, disk usage, or - as in this case - system load.
The idea is pretty simple: we want to build something (using Arduino) which visually indicates and interprets the five minute load average sent to it (using NodeJS). We'll use green, yellow and red LEDs to visualise the load and we'll use a Piezo Buzzer to play a disconcerting alarm sound when the load goes above a certain threshold.
The project gets a little more complicated when we want to monitor a remote server rather than a local machine directly attached to our Arduino board, and again when we want to make the actual monitor board wireless (e.g. portable) - the code on GitHub contains all the possible variations though we're only going to look at monitoring a local server with with a wireless monitor. Of course, the most useful combination is a wireless monitor visualising the load of a remote (e.g. production) server - a quick look at server.js and relay.js should be fairly self explanatory but if not please feel free to get in touch or leave a comment on this article.
Let's take a look at the finished product in action. The video shows the system being load tested using ApacheBench - first with a moderate load and then with a dangerous amount the system can't cope with. A few things to watch out for:
- The kernel only updates the load averages roughly every 5 seconds, but as soon as it does, the monitor gets updated
- The warning (yellow) LEDs light up when the load average goes above 0.75
- The panic (red) LEDs light up when the load average goes above 2.00, which also triggers an audible alarm. In the video this sound is incredibly quiet so you might have to turn your sound right up, but in reality it's plenty loud enough!
- The monitor often updates before the top output does - this is just because top by default doesn't update its load averages as soon as they're updated, but we do
- We're using the 5 minute load average rather than the 1 minute variable as it's less prone to fluctuations - temporarily going above a load average of 1.00 isn't a disaster over a minute, but it's a concern over five!
How does it work?
Explaining in exact detail how it all works would make this a painfully long article, so in brief:
- The direct.js process periodically queries the system load average and converts it to a rounded integer by scaling it up by a factor of 100 - this is simply so we only ever send the Arduino integers (it felt a bit simpler that way). If the value has changed since the last time we sent it, we write it to the serial port the Arduino is connected to (in my case,
- The Arduino board attached via the USB serial cable is running the serverload_send.pde sketch and simply relays anything it receives on its serial input to serial output - this is transmitted by an XBee radio
- The wireless Arduino board is running serverload_receive.pde. When it receives anything on its serial port (e.g. via its XBee radio) it converts it back to a normalised load average, performs a small bit of logic to determine what value to write to the shift register controlling the LEDs and checks to see if it's time to sound the panic alarm!
As with all the Arduinode experiments, the focus here is simplicity above all else. The arduino code could certainly do with tightening up (particularly the serial communication logic) and the node.js code could be more elegant. The number of CPU cores (used to normalise the load average) is hard coded into the serverload_receive.pde script rather than being sent from the server, and it would be nice to be able to override the alarm sound (apart from waiting for it to switch off automatically, or disconnecting it!).
One of the biggest improvements with the project would be to apply it to something a bit more real time - it's a shame that load averages are computed only roughly every five seconds as it somewhat negates many of the advantages of Node's evented architecture. The same arduino boards with a few software tweaks could easily be used to monitor virtually anything - one great use would be a real time hit counter for a website, a bit like hummingbird but with a physical output.
Of course, feel free to fork the project on GitHub and improve it, and if you end up using the code to actually monitor a production server then I'd love to hear about it!