Arduino, RainbowCube, RainbowDuino

Availability Monitoring with a RainbowCube

The RainbowCube is an Rainbowduino compatible 4x4x4 grid of LEDs. In this post I’ll cover how to use it to keep track of your internet connection, and response times of sites you care about.

Overview

This project has two parts: a computer (perhaps a raspberry pi?) to perform the actual web requests, and the RainbowCube to display the results. You can see full code on GitHub.

Web Requester

For this, I wrote a short python script. Normally, I would have done this with a simple bash script, but alas, there don’t appear to be any good resources on connecting to a serial device from the command line. The only (easiest) way I found to do this was with a Python lib called PySerial. Install it, import it to your script, and connect to the device, like so:

import serial
ser = serial.Serial('/dev/cu.usbserial-A60205DR',9600)

My RainbowCube connected at that address (/dev/cu.usbserial-A60205DR), but the last string of random letters may be different for you. 9600 is something called the BAUD rate, which just determines how quickly your computer writes to the serial device (in this case the RainbowCube). Most Arduino like devices default to 9600, so it’s a safe bet yours is similar.

Next, you’ll want to wait a couple seconds, since it takes a little bit to start the connection:

import time
time.sleep(2)

Then, build an array of the sites you want to monitor:

urlarray = ["http://192.168.22.1","http://www.google.com","https://github.com/","http://www.apple.com/"]

In my version, there are 12 sites I monitor, but above, I just give four examples. The first is the router to which I connect, so I can tell if there’s something wrong with that connection.

Next, I instantiate an array that contains the times (in seconds) that I want to pause before checking the connection with a site again:

pausearray = [10, 15, 15, 15]

This allows me to check things that are more important to me more often. For instance, I check my connection to my router more frequently, since it will occasionally crash.

After that, I have to prep something that may seem a bit strange at first:

locationarray = list(string.ascii_lowercase)

I create an array of all the lowercase alphabet characters. This is because, as convenient as pySerial is, I couldn’t get it to correctly send arbitrary bytes. It did, however, send ascii characters just fine. So, to identify my list of sites, I assign each url a letter.

Then we create a queue to help us make individual, asynchronous calls to the web, so that a single slow website doesn’t slow down the rest of the program:

q = Queue.Queue()

Next, we define a function that will give us the current time in milliseconds, so that we can calculate response time:

current_milli_time = lambda: int(round(time.time() * 1000))

Now we’re ready to write the meat of our program. I’ve written a function called ‘get_url’ to request a page, calculate the response time, grade the response time, write the results to the queue, pause for a few seconds, and call itself recursively.

def get_url(q, location, url, pause_seconds):
 t0 = current_milli_time()
 try:
 status = urllib.urlopen(url).getcode()
 except:
 status = 999

 deltat = current_milli_time() - t0

 statusstr = location
 if status > 299:
 statusstr += "d"
 elif deltat < 300:
 statusstr += "a"
 elif deltat >= 300 and deltat < 900:
 statusstr += "b"
 elif deltat >= 900:
 statusstr += "c"

 q.put(statusstr)
 time.sleep(pause_seconds)
 get_url(q, location, url, pause_seconds)

Only two things left to do. Call this function on a thread for every url in my array:

for i in range(0,len(urlarray)):
 print locationarray[i] + ": " + urlarray[i]
 t = threading.Thread(target=get_url, args = (q, locationarray[i], urlarray[i], pausearray[i]))
 t.daemon = True
 t.start()

and then wait for the results to show up on the queue for delivery to the RainbowCube:

while True:
 result = q.get()
 ser.write(result)

The RainbowCube

The RainbowCube itself needs to do a few things:

  • Listen for bytes of data
  • Interpret the data
  • Light up the LEDs appropriately to reflect that data

We’ll represent each site as one row of four LEDs. This means we can reference each site by X and Y coordinates: (0, 0) represents the lower left, (0, 1) means the LED one to the right of the lower left, and so on, until we get to (3,3) which represents the upper right corner.

Next we’ll take the grade (a through d) and translate it into an LED representation: one green for ‘a,’ two green for ‘b,’ three yellow for ‘c,’ and four red for ‘d.’

To effect this, we’ll start off in the customary Arduino ‘loop’ method:

void loop()
{
  while (Serial.available() > 0) {
    parseLocation(Serial.read());
    while (Serial.available() == 0){
      delay(1);
    }
    char val = Serial.read();

    setStatus(y, x, val);
  }
}

First, as long as the serial device is available we: a) read in and parse the location byte (which corresponds to the specific website being graded), b) wait until the status byte (the grade for the website) is available, then c) set the status for that site/location.

There are a couple of methods that are just glorified switch statements for parsing the location and setting the statuses; I encourage you to check out the github repo if you’re curious. Suffice to say, you need to do a lot of this

  case 'd':
    x = 3;
    y = 0;
    break;

to go from a letter to coordinates. To actually set the colors on the RainbowCube, you simply do:

Rb.setPixelZXY(j,i,3,0x00FF00);

for instance, to set the (i, j) LED to green. Again, check out the repo for the full repetitive tediousness.

And that’s it! This will give you the beautiful, useful cube of LEDs shown on my work desk at the top of this post. Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s