My Raspberry Pi and the weather

After a successful (and surprisingly easy) setup of my Raspberry Pi 1 model B+ (also called an RPi), I decided to start working on a little weather app. While I like the look of the stock weather app on the iPhone, it is always missing, some bit of information I want. Like how much snow is expected in a couple days, and what the chance of snow is. As a result, I find myself going to Weather Underground to get the rest of the info I want. So, I decided to put my RPi 1 to work and create a system that will automatically download the weather and send me an email in the morning with a complete report.

 

This sample is a good starting point, as it gathers all the required info, including an animated gif file. From there it’s just presentation and polish. I’ll be giving a bare bones presentation.

This is what it looks like:



Weather Underground has a Programmers API that you can use to get the current weather, forecasted weather, and the satellite/radar images. The API is a RESTful web service. You need to signup, and you can choose the developer plan which is free. However you are limited to 500 calls per day, and 10 calls per minute. They make it easy to combine multiple requests in one call to save on repeated requests. For instance you can request the current conditions and the forecast in one call.

Once you have signed up, you can see the API in action by typing in a url similar to the following. Just replace the your-api-key text with the key they give you.

http://api.wunderground.com/api/your-api-key/conditions/forecast/q/ME/Portland.xml

The response is quite large, so I chopped out the unused sections. It basically looks like:

<response>
  <version>0.1</version>
  <termsofService>http://www.wunderground.com/weather/api/d/terms.html</termsofService>
  <features>
    <feature>radar</feature>
    <feature>satellite</feature>
    <feature>conditions</feature>
    <feature>forecast</feature>
  </features>
  <current_observation>
    <display_location>
      <full>Portland, ME</full>
      <city>Portland</city>
      <state>ME</state>
      <state_name>Maine</state_name>
      <country>US</country>
    </display_location>
    <observation_time>Last Updated on March 17, 11:40 PM EDT</observation_time>
    <weather>Scattered Clouds</weather>
    <temperature_string>40.5 F (4.7 C)</temperature_string>
    <temp_f>40.5</temp_f>
    <temp_c>4.7</temp_c>
    <icon>partlycloudy</icon>
    <icon_url>http://icons.wxug.com/i/c/k/nt_partlycloudy.gif</icon_url>
  </current_observation>
  <forecast>
    <txt_forecast>
      <date>9:53 PM EDT</date>
      <forecastdays>
        <forecastday>
          <period>0</period>
          <icon>partlycloudy</icon>
          <icon_url>http://icons.wxug.com/i/c/k/partlycloudy.gif</icon_url>
          <title>Thursday</title>
          <fcttext><![CDATA[Partly cloudy. Lows overnight in the upper 30s.]]></fcttext>
          <fcttext_metric><![CDATA[Partly cloudy. Low 3C.]]></fcttext_metric>
          <pop>20</pop>
        </forecastday>
        <forecastday>
          <period>1</period>
          <icon>nt_partlycloudy</icon>
          <icon_url>http://icons.wxug.com/i/c/k/nt_partlycloudy.gif</icon_url>
          <title>Thursday Night</title>
          <fcttext><![CDATA[A stray shower or thunderstorm is possible early. Some clouds. Low 37F. Winds WSW at 5 to 10 mph.]]></fcttext>
          <fcttext_metric><![CDATA[A stray shower or thunderstorm is possible early. Some clouds. Low 3C. Winds WSW at 10 to 15 km/h.]]></fcttext_metric>
          <pop>20</pop>
        </forecastday>
      </forecastdays>
    </txt_forecast>
  </forecast>
</response>

From there we just need to parse out the stuff we need. For the purposes of this example, I used PHP, but any CGI script is workable. We will first download the XML, then get it parsed into an object we can reference in code.

Download and Parse XML

Download and parse the XML:

$source_xml = file_get_contents("http://api.wunderground.com/api/your-api-key/conditions/forecast/q/ME/Portland.xml");
$parsed_xml = simplexml_load_string($source_xml) or die ("Error: Can not create xml object");

It’s questionable if the use of or die is a good idea or not, but for a quick test it’s fine. Once the XML has been parsed, we can now reference it like this:

$location = $parsed_xml->current_observation->display_location->full;
$weathernow = $parsed_xml->current_observation->weather;
$temp = $parsed_xml->current_observation->temperature_string;
$icon = $parsed_xml->current_observation->icon;
$lastUpdated = $parsed_xml->current_observation->observation_time;

The variable $location now contains the text Portland, ME.

Weather Icon

The $icon from above is an interesting one. It allows you to display the correct icon using Weather Undergrounds Icon Set. Replace the ICON with the contents of $icon and you get the correct weather icon. You can change what set of icons to use by changing the a in the url.

http://icons.wxug.com/i/c/a/ICON.gif

Let’s skip ahead to parsing the forecast. I used a different XML parser to experiment with it. I used the SimpleXMLElement class. They both seemed to work quite well, and both have the same syntax for accessing the document. This is how I parsed the weather forecast. You will note that the forecast has 10 days, so I used a for loop to to through each one:

$weather = new SimpleXMLElement($source_xml);

for($i=0; $i<8; ++$i)
{
    $icon =     $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->icon;
    $forecast = $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->fcttext;
    $day = $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->title;
    echo "<P>";
    echo "<img width='20' src='http://icons.wxug.com/i/c/${iconset}/${icon}.gif'> ";
    echo "${day}, ${forecast}";
    echo "</P>\n";
}

That’s it for parsing. The complete php file looks like this. Remember to change the the your-api-key to the key you get.

<?php
$source_xml = file_get_contents("http://api.wunderground.com/api/your-api-key/conditions/forecast/q/ME/Portland.xml");
$iconset = "i";

$parsed_xml = simplexml_load_string($source_xml) or die ("Error: Can not create xml object");
$location = $parsed_xml->current_observation->display_location->full;
$weathernow = $parsed_xml->current_observation->weather;
$temp = $parsed_xml->current_observation->temperature_string;
$icon = $parsed_xml->current_observation->icon;
$lastUpdated = $parsed_xml->current_observation->observation_time;
echo "<P>";
echo "<img width='20' src='http://icons.wxug.com/i/c/${iconset}/${icon}.gif'> ";
echo "Currently in ${location} it is: ${weathernow} and ${temp}. <br/>\n";
echo "</P>\n";
echo "<P>";
echo "<img width=300 height=300 src='http://api.wunderground.com/api/your-api-key/animatedradar/animatedsatellite/q/ME/Scarborough.gif?num=6&delay=50&interval=30'> ";
echo "</P>\n";


$weather = new SimpleXMLElement($source_xml);

for($i=0; $i<8; ++$i)
{
    $icon =     $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->icon;
    $forecast = $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->fcttext;
    $day = $weather->forecast->txt_forecast->forecastdays->forecastday[$i]->title;
    echo "<P>";
    echo "<img width='20' src='http://icons.wxug.com/i/c/${iconset}/${icon}.gif'> ";
    echo "${day}, ${forecast}";
    echo "</P>\n";
}
?>
<P>
    <font size='-2'>
        <?=${lastUpdated}?><br/>
        Weather information from <a href="https://www.wunderground.com/?apiref=6b8d7d4184746eff">Weather Underground</a>
    </font> 
</P>

You should be able to drop that PHP source onto your web server and it should work. Check out the API for more info that you can grab. Like weather history for one thing.

Downloading and Creating a Weather Report

I’m actually going to save creating a weather report and emailing to yourself for another blog post.