I live and work in a windowsless shack in the middle of a desert in the Middle East. Opening the door in the middle of a sandstorm is not advisable.
So I built a little LCD display that tells me the current weather conditions outside since I have no windows to look out of.
All those U.S. DoD budget cuts didn't leave us with enough taxpayer money to pay for windows. :-)
In other words, prison cells have better natural lighting.
And since I'm a lazy, lazy man I'd prefer to just be able to look at something to get the data I need and not have to go banging around on a web browser or installing a full-blown $$$ weather station.
Arduinos are perfect devices for lazy, cheap people such as myself.
Every two minutes it pulls down an RSS feed, parses it for current Heat Index, Wind DIrection, Wind Speed, Surface Visibility, and Current Conditions.
It then abbreviates and displays that data on an Adafruit 16x2 RGBLCD shield, however just about any LCD can be used with some minor code changes.
Eventually this will be connecting via an Xbee-style WiFly module, but for now it works fine on the Arduino Ethernet or Ethernet Shield.
I chose RSSWEATHER.COM because it has ICAO airport weather data. That means just about any airport on the planet, including small local airfields to get really local weather data...it's tracking stations that not even Weather Underground or Google's hidden weather API track.
In the "GET http://69.5.27.250/icao/KQWM/rss.php HTTP/1.0" string around line 88 in the code below, just substitute your own 4-digit airport code in place of KQWM.
Forgive the messy, unoptimized code - I'm not a programmer and have never written code before, but I've read a lot of it.
I also have zero formal training or education in electronics or anything past high school, really. I've just been working with computers and strange technical stuff since I was 7 years old.
That this works at all is actually pretty amazing in itself, well to me at least.
Eventually hoping to utilize some of the shield's buttons to change up the display to show more data.
Here's the code:
- Code: Select all | TOGGLE FULL SIZE
#include <SPI.h>
#include <Ethernet.h>
#include <TextFinder.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
//Setting up colors for the backlight..some unused for now
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7
//setup Serial LCD data pin
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xE3, 0x0F };
//byte ip[] = { 192,168,1,177 }; // remarked here just in case a DHCP server plays funny with Arduino's DHCP code - I'm looking at you, every Microsoft DHCP Server!
char serverName[] = "69.5.27.250"; //char serverName[] = "www.rssweather.com";
// Initialize the Ethernet client library
EthernetClient client;
//Setup TextFinder
TextFinder finder( client );
//setup character strings, or "straings" if you're from south like me
char cond[40];
char winddir[25];
char pubdate[40];
void setup() {
// start serial comms for debugging
Serial.begin(9600);
lcd.begin(16,2); //This is originally setup for a 16x2 RGB reverse backlight display from adafruit.com, with minor mods it will work for any simple LCD line display
lcd.setBacklight(WHITE); //the backlight at night is big and WHITE....deep in the heart of Kuwait!
lcd.clear();
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
lcd.print("no IP from DHCP!");
lcd.print("Check network!");
// no point in carrying on, so do nothing forevermore:
while(true);
}
// give the Ethernet shield a second to initialize:
delay(1000);
}
void loop()
{
if (client.connect(serverName, 80)) {
client.println("GET http://69.5.27.250/icao/KQWM/rss.php HTTP/1.0"); // rssweather.com RSS feed for Camp Udairi, Kuwait
client.println();
lcd.print("Updating data...");
delay(1000); //1 second ot display the LCD message above
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
lcd.print("connect failed");
lcd.print(serverName);
}
if (client.connected()) {
int gusts = 0; //this zeroes out gusts until check is done below - if gusts = 0 then no gust data is printed to LCD
lcd.clear(); //clears LCD
//Here is where we use the TextFinder library to pull data from the RSSWEATHER page we pulled down at the start of the loop
finder.find("pubDate"); //Date last METAR/WX report was published on the server
finder.getString(">","<",pubdate,(40));
finder.find("alt="); //Now find the Current Conditions
finder.getString("\"","\"",cond,(40));
finder.find("\"windspeed\""); //Now find the Windspeed
int windspd = ((finder.getValue() / 1.6)); //windspeed is given in KMs so I'm converting it to MPH
finder.find("\"winddir\""); //Wind Direction
finder.getString("\">"," ",winddir,(40));
if ((finder.findUntil("\"gusts\"", "\n\r")) == (true)){ //scan the incoming client data for the "gusts" field and return true if found
gusts = (finder.getValue());}
finder.find("\"heatindex\""); //find Heat Index
int temperature = ((finder.getValue() * 9 / 5) + 32); //Heat Index is given in Celsius so I'm converting it to Fahrenheit
finder.find("\"visibility\""); //find surface visibility - useful for desert conditions when sand and dust are blowing...do I really want to get on that chopper?
int visibility = ((finder.getValue() / 1.6)); //Visibility at surface is given in KMs so I'm converting it to miles
//print this to serial in CSV format - useful for those using an Xbee to transmit to a an Arduino-controlled remote display device
Serial.print(temperature);//Heat Index, converted to F
Serial.print(",");
Serial.print(cond); //Current Conditions
Serial.print(",");
Serial.print(winddir);
Serial.print(",");
Serial.print(windspd);
Serial.print(",");
Serial.print(gusts);
Serial.print(",");
Serial.print(visibility);
Serial.println("M");
Serial.println(pubdate); //date of last published report on the web server
//Now time to print it all to the serial, starting with the first line on a 16x2 LCD display
lcd.setCursor(0,0);
lcd.print(temperature);//Heat Index converted to F
lcd.print("F ");
lcd.print(winddir); //Wind direction
lcd.print(windspd); //Wind speed
//this next bit checks if there is gust data and if so appends it to the windspeed data with /GUSTS so that "N12" becomes "N12/24"
if (gusts != 0){
lcd.print("/");
lcd.print(gusts);
}
lcd.print(" ");
lcd.print("V");
lcd.print(visibility); //Visibility at surface so one knows if to "Run! Get to the chopper!" or not
lcd.print("M"); //this indicates "Miles"
//Now for the second line on the LCD display
lcd.setCursor(0,1);
//Since we're actually capturing a JPEG's ALT description string, we want to re-write the longer strings so that they fit in 16 characters or look better...needs optimization
if (strcmp(cond, "blowing widespread dust") == 0)
lcd.print("Blowing Dust");
else
if (strcmp(cond, "heavy duststorm") == 0)
lcd.print("Heavy Dust Storm");
else
if (strcmp(cond, "duststorm") == 0)
lcd.print("Dust Storm"); //Making it look pretty, oh so pretty...
else
lcd.print(cond);
//now let's change the backlight color to reflect weather conditions...man, I really need to optimize this
if (strcmp(cond, "blowing widespread dust") == 0)
lcd.setBacklight(YELLOW);
else
if (strcmp(cond, "widespread dust") == 0)
lcd.setBacklight(YELLOW);
else
if (strcmp(cond, "heavy duststorm") == 0)
lcd.setBacklight(YELLOW);
else
if (strcmp(cond, "duststorm") == 0)
lcd.setBacklight(YELLOW); //Because after spending many years in the desert, it really is yellow during a sand/dust storm
else
if (temperature >= 90)
lcd.setBacklight(RED); //If the Heat Index is 90 or above, switch to RED backlight
else
if (temperature >=80)
lcd.setBacklight(GREEN); //If the Heat Index is in the 80s, switch backlight to green
else
if (temperature >=70)
lcd.setBacklight(BLUE); //if the Heat Index is 70 or below, switch backlight to BLUE - in the desert this is COLD!
//Here at the end is where we stop the client, flush the data, wait two minutes, flush the serial data, and then it starts all over again
client.stop();
client.flush();
delay(120000); //wait about 2 minutes before next update
Serial.flush();
}
}