Arduino Ambient Orb Weather Predictor Revisited

Weather Beacon

Back in February, I posted about some new enclosures I’d built for my weather beacon.

This weekend, I finally got around to tweaking the code for my beacon. I was inspired to work on it after receiving one of ThingMs spiffy new MaxM’s. They’re nice and bright and will work with any BlinkM code you may have already written.

I’m pretty happy with how my beacon works now. After my initial post, I got an email from Dave Lemons. Dave took my initial cobbled-together code and added the pulse support I’d been meaning to implement. I wanted the beacon to pulse according to the forecasted chance of precipitation. Dave’s code used delay()’s to effect the pulses. I found that when I hooked this up to my Processing script that’d pull in the weather data, I got no response from the beacon. It looks like the Processing script was delivering the data while the Arduino was “sleeping” during a delay().

So… I rewrote Dave’s code to offload the pulsing effect to a BlinkM script, saved on the MaxM. That frees up the Arduino code so that it pretty much just sits there and waits for input.

If you’d like to play around with this project, here’s my code. Be gentle… my code reads a bit like someone learning to swear phonetically in a foreign language. It might be ugly, but it gets the job done. There are 3 parts to the project:

  1. PHP code that checks the Yahoo! Weather API. You’ll need to put this code on a Web server of some sort. This code translates the weather forecast into a color(RGB hex) and a pulse code. It’ll also dump out XML – I’ve been experimenting with implementing a beacon in Flash on my Chumby. It looks like I’m using an old URL for the API, but it appears to be working OK. Put that on my TODO list.
  2. Processing code that sits on your computer that periodically checks the PHP in code 1, then delivers the color/pulse info to your Arduino.
  3. The Arduino code that parses the input from step 2 and sends the appropriate instructions to your BlinkM.

Download the code here.

The code might be a bit ugly. Give a yell if you run into a snag or make some improvements.

6 Comments

  1. Posted November 25, 2008 at 8:13 am | Permalink

    I think it would be simpler and as effective to outfit the Arduino with a barometer. You could then have it turn red as a low approaches.

    Neat project!

  2. Scott
    Posted November 25, 2008 at 8:19 am | Permalink

    Ah, but suppose the approaching storm is a bunch of email to your inbox, or a failing router… You could easily cobble together some code to report on that kind of ‘bad weather’, too…

  3. Chris
    Posted November 2, 2009 at 10:57 am | Permalink

    Hello!
    I got it running and it is absolutely amazing. I’ve been struggling for hours with the pulse idea- anyone figure it out?

  4. Posted November 19, 2009 at 10:58 am | Permalink

    Hey,

    I got it working but I want to use it for weather in Ireland and I cant use a zip code in the PHP file to do this. According to Yahoo(http://developer.yahoo.com/weather/#req) I must use the WOEID instead of zip code. Any idea how I could edit the PHP file to do this??? Any help would be greatly appreciated. Thanks.

  5. Scott
    Posted November 19, 2009 at 11:30 am | Permalink

    Here’s the Arduino code for anyone looking for it!

    BEGIN=====

    /*
    Simple code used for Arduino/Blink-M weather beacon
    My thanks go to Scott Reston (http://www.therestons.com/scott/) and
    Tod E. Kurt (www.todbot.com/blog) for the code and inspiration

    Upload to Arduino and open the serial monitor.
    This takes two commands:

    c xxxxxx where xxxxxx is the hex color you want to change to.
    to change color to red pass: c ff0000

    p x where x is the pulse variable. This will cause the blink-m
    to pulse in 3 different (p 1, p 2, p 3) intensity levels with
    1 being slow and 3 being fast. pass p 0 to turn off the pulse.

    This is just cobbled together code from various sources…please
    feel free to use and just shoot me an email with any projects you
    use it in. I plan on building a weather forcaster and beacon. I’ll
    be posting my build at:

    http://www.davelemons.com
    -Dave

    */

    #include “Wire.h”
    #include “BlinkM_funcs.h”

    #define BLINKM_ARDUINO_POWERED 1

    int blinkm_addr = 0×09;
    int ledPin = 13;
    char serInStr[30]; // array that will hold the serial input string
    byte r = toHex(0,0);
    byte g = toHex(0,0);
    byte b = toHex(0,0);

    char pulse = ’0′;
    int delaytime = 1000;

    void setup()
    {
    pinMode(ledPin, OUTPUT);
    if( BLINKM_ARDUINO_POWERED ) {
    BlinkM_beginWithPower();
    } else {
    BlinkM_begin();
    }
    BlinkM_setAddress( blinkm_addr ); // comment out to not set address

    Serial.begin(19200);
    byte rc = BlinkM_checkAddress( blinkm_addr );
    if( rc == -1 )
    Serial.println(“no response”);
    else if( rc == 1 )
    Serial.println(“addr mismatch”);

    Serial.println(“BlinkM ready”);
    //BlinkM_stopScript(blinkm_
    addr);
    BlinkM_playScript( blinkm_addr, 10,0,0 ); // play a script while we’re waiting to show no data received yet
    BlinkM_setFadeSpeed(blinkm_addr, 10);

    }

    void loop()
    {
    int num;
    //read the serial port and create a string out of what you read
    if( readSerialString() ) {
    Serial.println(serInStr);
    char cmd = serInStr[0]; // first char is command
    char* str = serInStr;
    while( *++str == ‘ ‘ ); // got past any intervening whitespace
    num = atoi(str); // the rest is arguments (maybe)
    if( cmd == ‘c’) {
    r = toHex( str[0],str[1] );
    g = toHex( str[2],str[3] );
    b = toHex( str[4],str[5] );
    BlinkM_stopScript(blinkm_addr);
    BlinkM_fadeToRGB( blinkm_addr, r,g,b);
    //pulse = ’0′;
    }
    else if( cmd ==’p’ ){
    pulse = str[0];
    if (pulse == ’1′) { //slow pulse
    int f = 2;
    int t = 60;
    int denom = 6;

    int r2 = r/denom;
    int g2 = g/denom;
    int b2 = b/denom;

    blinkm_script_line script1_lines[] = {
    { 1, {‘f’, f,0,0}},
    { 1, {‘t’, t,0,0}},
    { 10, {‘c’, r2,g2,b2}},
    { 10, {‘c’, r,g,b}}
    };
    int script1_len = 4; // number of script lines above

    Serial.print(“Writing new script (slow pulse)…”);
    BlinkM_writeScript( blinkm_addr, 0, script1_len, 0, script1_lines);
    Serial.println(“done.”);
    delay(500);
    Serial.println(“playing script.”);
    BlinkM_playScript( blinkm_addr, 0,0,0 );

    }
    else if(pulse == ’2′) { //medium pulse
    int f = 3;
    int t = 20;
    int denom = 6;

    int r2 = r/denom;
    int g2 = f/denom;
    int b2 = b/denom;

    blinkm_script_line script1_lines[] = {
    { 1, {‘f’, f,0,0}},
    { 1, {‘t’, t,0,0}},
    { 10, {‘c’, r2,g2,b2}},
    { 10, {‘c’, r,g,b}}
    };
    int script1_len = 4; // number of script lines above

    Serial.print(“Writing new script (med pulse)…”);
    BlinkM_writeScript( blinkm_addr, 0, script1_len, 0, script1_lines);
    Serial.println(“done.”);
    delay(4000);
    Serial.println(“playing script.”);
    BlinkM_playScript( blinkm_addr, 0,0,0 );;
    }
    else if (pulse == ’3′) { //fast pulse
    int f = 10;
    int t = 10;
    int denom = 10;

    int r2 = r/denom;
    int g2 = g/denom;
    int b2 = b/denom;

    blinkm_script_line script1_lines[] = {
    { 1, {‘f’, f,0,0}},
    { 1, {‘t’, t,0,0}},
    { 10, {‘c’, r2,g2,b2}},
    { 10, {‘c’, r,g,b}}
    };
    int script1_len = 4; // number of script lines above

    Serial.print(“Writing new script (fast pulse)…”);
    BlinkM_writeScript( blinkm_addr, 0, script1_len, 0, script1_lines);
    Serial.println(“done.”);
    delay(500);
    Serial.println(“playing script.”);
    BlinkM_playScript( blinkm_addr, 0,0,0 );
    }
    else { //turn it off
    pulse = ’0′;
    BlinkM_stopScript(blinkm_addr);
    }
    }
    else {
    Serial.println(“Unrecognized cmd”);
    }
    serInStr[0] = 0; // say we’ve used the string
    Serial.print(“cmd>”);

    } //if( readSerialString() )

    delay(250);
    }

    // a really cheap strtol(s,NULL,16)
    #include
    uint8_t toHex(char hi, char lo)
    {
    uint8_t b;
    hi = toupper(hi);
    if( isxdigit(hi) ) {
    if( hi > ’9′ ) hi -= 7; // software offset for A-F
    hi -= 0×30; // subtract ASCII offset
    b = hi< ’9′ ) lo -= 7; // software offset for A-F
    lo -= 0×30; // subtract ASCII offset
    b = b + lo;
    return b;
    } // else error
    } // else error
    return 0;
    }

    //read a string from the serial and store it in an array
    //you must supply the array variable
    uint8_t readSerialString()
    {
    if(!Serial.available()) {
    return 0;
    }
    delay(10); // wait a little for serial data
    int i = 0;
    while (Serial.available()) {
    serInStr[i] = Serial.read(); // FIXME: doesn’t check buffer overrun
    i++;
    }
    serInStr[i] = 0; // indicate end of read string
    return i; // return number of chars read
    }

    END=====

  6. Scott
    Posted November 19, 2009 at 11:32 am | Permalink

    Also – Alan worked out that if you change the ?p= to ?w= (/inc/functions.php) and use your WOED as a zip, you can get this to work internationally. Cheers!

Post a Comment

Your email is never shared. Required fields are marked *

*
*