RambleOn

Like a jazz riff, but with words.

Learning Arduino: The Geek Parent Edition

So I’m not a parent (I do have a bunch of photogenic furrykids) but I am a geek. And I have the opportunity to do work on one of the most interesting sites for parents that you’ll find: Trixie Tracker. If you love data and have young kids, or a newborn and wonder if you’ll ever get sleep again - you’ll want to check it out.

So what’s a geek and a geek (for) parents to do with a brand new arduino experimentation kit to do after my “look at the blinky light” hello world project?

Make a baby monitor of course.

I’m still not on the level of one of my colleagues that put a hydrogen sulfide monitor and a motion detecter hooked up to an Arduino in the men’s bathroom at work and had it tweet when things were, um, occupied - that project was pretty amazing. But hey, one project at a time.

So, a little more simply, what if I am a geek uncle one day and wanted to call my brother-in-law but didn’t want to wake the kid up? (Let’s skip the part that my brother-in-law is single and has no kids, and I’d just probably txt him and I’m not even sure I remember how to use the phone - but let’s not ruin my electronic project here with reality)

So, what I want to know is my mythical little nephew/niece asleep? And what’s the probability that nephew/niece should be asleep? And what’s the probability going to be like for the next hour? And then light up some LED’s. Because LED’s are cool - especially color changing ones.

Well, thanks to Trixie Tracker’s awesome sleep probability data - we can do this.

The API Call

TT doesn’t have any official API’s (yet) - our project for the last year was converting it from PHP (functional, framework less PHP) to Ruby on Rails, so we haven’t dug into building APIs yet, but I did put one useful endpoint together for this project - a sleep probability API that will return current sleep status, the probability over the last month for this 10-minute period, and the probability for next hour (or the next 6 10-minute periods)

If I do a GET on http://go.trixietracker.com/api/sleep_probability?apikey=my_api_key&child=child_id - I’ll get something that looks like:

"{\"next_hour\":[0.29,0.29,0.32,0.42,0.45,0.45],\"probability\":0.29,\"current\":\"asleep\",\"success\":true}"

in return - or looking at it as a ruby hash:

{ “current” => “asleep”, “success” => true, “next_hour” => [ [0] 0.29, 1 0.29, 2 0.32, 3 0.42, 4 0.45, 5 0.45 ], “probability” => 0.29 }

All of the probability numbers here are the probability that the child I’m looking at is asleep. As you can tell, there’s a ~70% chance that this child will be awake now or in the next hour - I should be able to call soon!

If you are a trixietracker subscriber - you can get your apikey and your child_id by going to a site that you have access to - and looking at the developer settings page. That’s not linked right now, but you can just click on your site settings page, e.g. for the “tryit” site: http://go.trixietracker.com/tryit/admin/settings and change “settings” to “developer”, i.e. http://go.trixietracker.com/tryit/admin/developer

So how do we turn this into something to look at?

The Board

Here’s my setup - three (common anode) tri-color (RGB) LED’s

So, here’s the plan: I’ll light a LED blue or yellow for the current sleep status (which can be “asleep”, “awake”, or “transition” - which means the child was put down for a nap, but hasn’t fallen asleep yet, I’ll just treat that as awake). I’ll light another for the current probability moving along a gradient from blue (RGB: 0,0,255) to yellow (RGB: 255, 255, 0), and for the third, I’ll cycle through gradients for the next hour.

My arduino uno has 13 output pins. But only some of them can vary the output voltage (known as PWM) to give me the ranges from blue to yellow. Thankfully there’s six of those, enough for the RGB pins for two of the led’s. So I’ll just do ON/OFF for the third one to give me awake/asleep.

The Sketch

here’s my pins:

//RGB LED pins
int ledSleep[] = {7,8,12}; //the three pins of the digital LED  


//These pins must be PWM        
int ledProbabilityFade[] = {3, 5, 6}; //the three pins of the first analog LED

//These pins must be PWM        
int ledProbability[] = {9,10,11}; //the three pins of the second analog LED

and here’s my core loop (full sketch), I’m reading 8 bytes at a time off the serial port when they are available - using byte one as an asleep/awake boolean, byte two as the current probability (relative to 100) - and bytes 3-8 as the next six probabilities (relative to 100).

void loop() {  


  if (Serial.available() >= 8) {
    // read two incoming byte:
    sleepByte = Serial.read();
    probabilityByte = Serial.read();
    for(int i= 0; i < 6; i++) {
      probabilityFadeBytes[i] = Serial.read();
    }
    Serial.flush();  


    // debug what we have
    Serial.print("Sleep Byte: ");
    Serial.println(sleepByte, DEC);
    Serial.print("Probability Byte: ");
    Serial.println(probabilityByte, DEC);  


    if(sleepByte == 0) {
      setDigitalColor(ledSleep,ASLEEP);
    }
    else if(sleepByte == 1) {
      setDigitalColor(ledSleep,AWAKE);
    }
    else {
      setDigitalColor(ledSleep,BLACK);
    }  


    blue =  255 * ((float(probabilityByte) / 100));
    red = 255 * ((float(100-probabilityByte) / 100));
    green = 255 * ((float(100-probabilityByte) / 100));  


    setColor(ledProbability, red, green,blue);                 


    Serial.println("Probability RGB: ");
    Serial.println(red, DEC);
    Serial.println(green, DEC);
    Serial.println(blue, DEC);
  }  




  setColor(ledProbabilityFade, 0,0,0);
  for(int i= 0; i < 6; i++) {
    blue =  255 * ((float(probabilityFadeBytes[i]) / 100));
    red = 255 * ((float(100-probabilityFadeBytes[i]) / 100));
    green = 255 * ((float(100-probabilityFadeBytes[i]) / 100));
    setColor(ledProbabilityFade, red,green,blue);
    delay(1000);
  }
  setColor(ledProbabilityFade, 0,0,0);
  delay(1000);
}  

I have precision errors with casting the division to a float and the back to an int, but I don’t really care, I’m not going to be able to discern a difference between blue = 128 and blue = 127.

I’m shooting for an output that goes from RGB 0,0,255 at 100% sleep probably to RGB 255,255,0 at 0% with a nice “grey” of 128,128,128 at 50% - basically the led equivalent of this:

The Live Shot

So with the above data, here’s what I get:

Now it’s pretty much impossible to get an idea of the colors here (other than “bluish” and “whitish”). But we had to have a live action shot you know?

The Data Transfer

So, how does this all work? How do I get the json data over to it? Well, I’m using a ruby script to parse the json, and send the serial data - the core looks like this (full script):

@url = "https://go.trixietracker.com:443/api/sleep_probability?apikey=#{@config_settings['apikey']}&child=#{@config_settings['child']}"
sleep_json = fetch_url_content(@url)
ap sleep_json
sleep_data = JSON.parse(sleep_json)
ap sleep_data  


sp = SerialPort.new "/dev/tty.usbmodem5d11", 9600
if(sleep_data["current"] == 'asleep')
  sp.putc(0)
else
  sp.putc(1)
end
sp.putc((sleep_data['probability']*100).to_i)
for i in 0..5 do
  sp.putc((sleep_data['next_hour'][i]*100).to_i)
end  


sp.close  

The Gotchas

I had to spend about 30 minutes when I slowly (really, way too slowly) realized that the documentation on my other LED’s was wrong. The blue pin is on the outside, not the green like the docs said. I figure they sent me the “screw with the n00b” set.

Red is definitely brighter in one of the LED’s (due to the red having a lower forward voltage - I’m learning, slowly). I need to add some resistance to the red pin on that one.

Doing a 7 second loop on the third LED with a one second discrete state change is a bit jarring. It’d be far more interesting to drop that delay down to about 30ms and do some vector math between the “probabilities” - giving a nice fade effect. Although for probabilities that are still so similar anyway, you wouldn’t tell much difference. It’s only going to get exciting around the times that there’s a strong probability of going from sleep to wake or vice versa within the hour.

My ruby script definitely needs some demo command line options - particularly for testing and debugging.

I really don’t understand the serial driver setup. Probably because I never have really tried to understand serial consoles in Unix. I have to open the serial port monitor in the Arduino IDE to get it going, and then I can connect with Ruby. I really, really, really should learn what’s going on there.

All in all, a fun project to start with as my “hello world” project. Next up, some kind of project for the furrykids