National Weather Service


The U.S. NWS recently launched its own API, allowing users to request detailed weather information for any location within the contiguous United States. This information can be used to add a personal touch to websites (reporting either the weather at the site owner's location, or in combination with an IP lookup table, at the visitor's location), or be fully integrated with websites to complement other services (for example, travel websites). Unlike every other API discussed in this book, no authentication is required. The API is provided as a free service because the information gathered was provided at taxpayers' expense — no double charge.

The NWS provides access to two functions via its API: NDFDGen and NDFDGenByDay (NDFD stands for National Digital Forecast Database). NDFDGen provides weather forecasts in a granular manner over the specified period, whereas NDFDGenByDay provides only a summary of the data available. In these examples the NDFDGenByDay data is examined.

The NWS updates the data provided to the API once per hour, generally 45 minutes past the hour, so it is unnecessary and requested that you not request the data on page load. Your main options on how to handle this are (in decreasing order of preference): Cache the data that gets printed to the page and update that cache once an hour, cache the desired weather data and update that information once an hour, or cache the API's response and only update that cache once per hour.

In order to obtain weather information for a specific location, you will need the latitude and longitude. If you intend to display weather information for a static set of locations (you could, for example, display the weather at each of your company's offices), it should be simple just to calculate that information once (there are many websites that do zip code to latitude and longitude calculations for you) and store the results. If, on the other hand, you want to display a dynamic set of weather data (say, if you want to display the weather from a user's location), you will likely need to invest in an IP address to a physical location database. There are several commercial sources of this information. Remember that the United States is in the western hemisphere, so all longitude values will be negative.

SOAP Request

Requests against the NWS API are quite brief:

 <?xml version="1.0" encoding="ISO-8859-1"?> <SOAP-ENV:Envelope   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:si="http://soapinterop.org/xsd"   xmlns:tns="http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl"   xmlns:typens="http://weather.gov/forecasts/xml/DWMLgen/schema/ndfdXML.xsd">   <SOAP-ENV:Body>     <tns:NDFDgenByDay       xmlns:tns="http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl">       <latitude xsi:type="xsd:decimal">40.7409</latitude>       <longitude xsi:type="xsd:decimal">-73.9997</longitude>       <startDate xsi:type="xsd:date">2005-05-13</startDate>       <numDays xsi:type="xsd:integer">5</numDays>       <format xsi:type="typens:formatType">24 hourly</format>     </tns:NDFDgenByDay>   </SOAP-ENV:Body> </SOAP-ENV:Envelope> 

As usual, the SOAP Envelope contains a number of namespace declarations; these are dictated by the WSDL file provided by the NWS. The SOAP Body contains the essential portions of the request:

  • latitude — The latitude for the location you are requesting information for. The latitude shown here is for southern Manhattan, New York City.

  • longitude — The longitude for the location you are requesting information for. The longitude used is for southern Manhattan, New York City.

  • startDate — The first day you want weather information for.

  • numDays — The number of days you are requesting weather information for.

  • format — There are two format options, 24 hourly and 12 hourly, returning data summarized in a 24- or 12-hour format, respectively.

SOAP Response

As also tends to be the case, the response is quite verbose:

 <?xml version="1.0" encoding="ISO-8859-1"?> <SOAP-ENV:Envelope   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:si="http://soapinterop.org/xsd">   <SOAP-ENV:Body>     <ns1:NDFDgenByDayResponse       xmlns:ns1="http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl">       <dwmlByDayOut xsi:type="xsd:string">         <?xml version=;1.0; ?>         <dwml version=;1.0; xmlns:xsd="http://www.w3.org/2001/XMLSchema"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation       ="http://www.nws.noaa.gov/forecasts/xml/DWMLgen/schema/DWML.xsd">        <head>           <product concise-name="dwmlByDay" operational-mode="developmental">             <title>NOAAs National Weather Service Forecast by 24 Hour period               </title>             <field>meteorological</field>             <category>forecast</category>             <creation-date refresh-frequency=;PT1H;>2005-05-13T16:06:09Z               </creation-date>           </product>           <source>             <more-information>http://www.nws.noaa.gov/forecasts/xml/               </more-information>             <production-center>Meteorological Development Laboratory               <sub-center>Product Generation Branch</sub-center>             </production-center>             <disclaimer>http://www.nws.noaa.gov/disclaimer.html</disclaimer>             <credit>http://weather.gov/</credit>             <credit-logo>http://weather.gov/images/xml_logo.gif</credit-logo>             <feedback>http://weather.gov/survey/nws-survey.php?code=xmlsoap               </feedback>           </source>         </head>         <data>         <location>           <location-key>point1</location-key>           <point latitude="40.7409" longitude="-73.9997" />         </location>         <time-layout time-coordinate="local" summarization="24hourly">           <layout-key>k-p24h-n2-1</layout-key>           <start-valid-time>2005-05-13T06:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-14T06:00:00-04:00</end-valid-time>           <start-valid-time>2005-05-14T06:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-15T06:00:00-04:00</end-valid-time>         </time-layout>         <time-layout time-coordinate="local" summarization="12hourly">           <layout-key>k-p12h-n4-2</layout-key>           <start-valid-time>2005-05-13T06:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-13T18:00:00-04:00</end-valid-time>           <start-valid-time>2005-05-13T18:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-14T06:00:00-04:00</end-valid-time>           <start-valid-time>2005-05-14T06:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-14T18:00:00-04:00</end-valid-time>           <start-valid-time>2005-05-14T18:00:00-04:00</start-valid-time>           <end-valid-time>2005-05-15T06:00:00-04:00</end-valid-time>         </time-layout>         <parameters applicable-location="point1">           <temperature type=;maximum; units="Fahrenheit" time-layout="k-p24h-n2-1">             <name>Daily Maximum Temperature</name>             <value>63</value>             <value>69</value>           </temperature>           <temperature type=;minimum; units="Fahrenheit" time-layout="k-p24h-n2-1">             <name>Daily Minimum Temperature</name>             <value>50</value>             <value>61</value>           </temperature>           <probability-of-precipitation type=;12 hour; units="percent"             time-layout="k-p12h-n4-2">             <name>12 Hourly Probability of Precipitation</name>             <value>0</value>             <value>11</value>             <value>32</value>             <value>46</value>           </probability-of-precipitation>           <weather time-layout="k-p24h-n2-1">             <name>Weather Type, Coverage, and Intensity</name>             <weather-conditions weather-summary="Increasing Clouds">             </weather-conditions>             <weather-conditions weather-summary="Chance Rain Showers">               <value coverage="chance" intensity="none"                weather-type="thunderstorms" qualifier="none">               </value>               <value coverage="chance" intensity="light"                 weather-type="rain showers" qualifier="none">               </value>             </weather-conditions>           </weather>           <conditions-icon type="forecast-NWS" time-layout="k-p24h-n2-1">             <name>Conditions Icons</name>             <icon-link> http://www.nws.noaa.gov/weather/images/fcicons/bkn.jpg</icon-link>             <icon-link> http://www.nws.noaa.gov/weather/images/fcicons/hi_shwrs.jpg</icon-link>           </conditions-icon>         </parameters>         </data>         </dwml>       </dwmlByDayOut>     </ns1:NDFDgenByDayResponse>   </SOAP-ENV:Body> </SOAP-ENV:Envelope> 

The response is quite extensive because the service seeks to be very precise about the information it is providing. Note that there are two time-layout elements: one providing two start and end times, the other providing four. The first presents the time indices for the minimum and maximum temperatures, and the second is relevant for the probability of precipitation, which is given for 12-hour segments.

Note the weather-conditions elements under the weather element; they provide detailed information about expected weather for each time segment. This information can be brief, as shown with the first element, which merely states that there will be increasing cloud cover:

 <value coverage="chance" intensity="none" weather-type="thunderstorms" qualifier="none"></value> 

Or the information can be more detailed, as shown in the second element, which indicates that there is a chance of thunderstorms, and also that there is a chance of light showers:

 <weather-conditions weather-summary="Chance Rain Showers">   <value coverage="chance" intensity="none" weather-type="thunderstorms"     qualifier="none">   </value>   <value coverage="chance" intensity="light" weather-type="rain showers"     qualifier="none">   </value> </weather-conditions> 

Depending on the expected weather conditions, a large amount of information can be presented here.

One last item of particular note is the icon-link elements under conditions-icon. These are links to images hosted by the National Weather Service that graphically represent the expected weather conditions.

Generating the SOAP Request

Thanks to NuSOAP, generating the request is pretty simple, and follows the same structure used for other APIs:

 require('../lib/nusoap.php');    $today = date("Y-m-j"); $client = new soapclient("http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl", true);  $params = array(       'latitude'    => "40.7409",       'longitude'   => "-73.9997",       'startDate'   => $today,       'numDays'     => '2',       'format'      => '24 hourly'   );   $result = $client->call('NDFDgenByDay',$params);   $error = $client->getError();   if ($error)   {     echo "error<pre>";     print_r($error);     print_r($result);     echo "</pre>";     exit;   } 

After the NuSOAP libraries are referenced, today's date is generated in a compatible format. The client is created by referencing the NWS's WSDL document, and the appropriate parameters are set (these are the same values as were used when the request was shown earlier). If an error was encountered, print out the information and exit.

Handling the SOAP Response

Having all that interesting weather data is of little use if you don't do anything with it, and it's pretty easy to display it to the end user in an attractive manner. This section of code will grab some essential data from the SOAP response (relevant dates, min and max temperatures, and the weather icons), then print it out in a simple table:

   $xml = simplexml_load_string($result);   $dayNames = array();   $weatherDates = array();   foreach($xml->data->{'time-layout'}->{'start-valid-time'} AS $time)   {      $weatherDates[] = (string) $time;      $dayNames[] = date("l", strtotime($time));   } 

Once the response is turned into a SimpleXML object, the dates for the returned data are copied into its own array. Both the full date and name of the day in question (for example, Wednesday) are recorded; the date itself isn't used here but would be the appropriate item to store if this data is going to be stored in a database.

Note 

Notice how the time-layout and start-valid-time elements are encapsulated within the single quotes and curly braces. This is absolutely necessary to refer to an XML element within a SimpleXML object. Write that down.

Also note the use of casting when populating the $weatherDates array. Without this casting a SimpleXML object containing the appropriate date will be assigned to the $weatherDates array; with the casting, only the date it contains is assigned. This saves on overhead and helps prevent any "weirdness" later.

   $maxTemperature = array();   foreach($xml->data->parameters->temperature[0]->value AS $maxTemp)   {     $maxTemperature[] = (int) $maxTemp;   }   $minTemperature = array();   foreach($xml->data->parameters->temperature[1]->value AS $minTemp)   {     $minTemperature[] = (int) $minTemp;   }   $icons = array();   foreach($xml->data->parameters->{‘conditions-icon'}->{‘icon-link'} as $icon)   {     $icons[] = (string) $icon;   } 

No big tricks here — the minimum and maximum temperatures are recorded, as is the URL for the weather icon. Casting is again used to ensure that only the appropriate data is recorded, not the SimpleXML object containing the data.

   echo "<table>\n<tr>";   $day = 0;   while(isset($weatherDates[$day]))   {      echo "<th colspan=\"2\">{$dayNames[$day]}</th>";      $day++;   }   echo "</tr>";   echo "<tr>";   $day = 0;   while(isset($weatherDates[$day]))   {     echo "<td><b>Low</b>: {$minTemperature[$day]} <br>";     echo "<b>High</b>:{$maxTemperature[$day]}<br></td>";     echo "<td><img src=\"{$icons[$day]}\" align=\"right\">\n\n<br></td>";     $day++;   }   echo "</tr></table>"; 

Finally, the information is printed out in a basic HTML table (if you're one of those anti-table pro-CSS people, just squint really hard and pretend it's CSS).

Take all of that (just raise the number of days you are requesting weather for) and you end up with something like the image in Figure 11-1.

image from book
Figure 11-1

Cloudy Conclusions

The NWS API grants easy access to detailed weather forecasts for locations throughout the contiguous United States. In fact, many (if not most) media outlets use the National Weather Service as a primary source for up-to-date weather forecasts. Now your website or firm can be just as up to date and accurate. This information would be well suited for corporate intranets (at which point you may finally be able to convince fellow staffers to uninstall the various spyware utilities that perform a similar service), particularly ones with multiple sites in different geographic locations. In my experience, employees are very curious to learn what the weather is like where their co-workers are.




Professional Web APIs with PHP. eBay, Google, PayPal, Amazon, FedEx, Plus Web Feeds
Professional Web APIs with PHP. eBay, Google, PayPal, Amazon, FedEx, Plus Web Feeds
ISBN: 764589547
EAN: N/A
Year: 2006
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net