»

Apr 01

Extracting Data from the Weather Underground API

Many companies are beginning to bring external data into their data infrastructure.  One of the most common and easily available types of external data is weather data.

There are several excellent sources of weather data.  If you need historical weather data then Fetch Climate is a great resource.  The data has been combined from many sources and patched together into a consistent whole.  The Microsoft Research project was conceived of and led by Drew Purves.

Fetch Climate doesn’t include current weather data, though. Recently I was working with a client that needed a daily average temperature inserted into a table in their SQL Server database.  Another resource on the web, Weather Underground, publishes current daily weather data. It also has an API that you can program against.  Since there isn’t much documentation out there about how to connect to the Weather Underground API using a .Net client, I decided to document how I accessed it and inserted the data into SQL Server using a CLR assembly.

The first step is to sign up for a developers account on Weather Underground.  This will give you a personal key that you can use to authenticate against the API.  The free Developer account gives you 500 API calls per day for free.  This should be plenty to get started and it’s easy to upgrade later if your business case justifies it.

You use a http request to call the API and it returns either a JSON or XML object with the requested weather data included.  Since we’ll be accessing the API using .Net, XML will be the easiest to parse.  We’ll need to create a C# Class Library to store the code for the SQL Server CLR library.  I used Visual Studio 2010 as the development environment.

Class Library Dialogue

The end result that we want to achieve is a SQL function that takes a date and a Weather Underground key and returns a decimal with the average temperature for that day.  We’ll use the .Net XML library as well as the SQL Server API to achieve this end.  The code that can fetch the data looks like:

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.SqlServer.Server;

public partial class WeatherUndergroundFunctions
{
public const string weatherUndergroundAddress = "http://api.wunderground.com/api/{0}/history_{1}/q/MN/Minneapolis.xml";
public const string tempXPath = "/response/history/observations/observation/tempi";
[SqlFunction()]
public static SqlDecimal getDailyAverageTemperature(SqlDateTime tempDate, SqlString weatherUndergroundKey)
{
string formattedDate = tempDate.Value.ToString("yyyyMMdd");
decimal totalTemp = 0;
decimal observationCount = 0;

XmlDocument xmlTemp = new XmlDocument();
xmlTemp.Load(string.Format(weatherUndergroundAddress, weatherUndergroundKey.ToString(), formattedDate));

foreach(XmlNode obs in xmlTemp.SelectNodes(tempXPath))
{
totalTemp += Convert.ToDecimal(obs.InnerText);
observationCount += 1;
}

return new SqlDecimal(totalTemp/observationCount);
}
}

Let’s walk through a few parts of this code.  The weatherUndergroundAddress variable stores the http address to fetch the weather for Minneapolis.  It’s simple to get weather data for any major U.S. city by substituting its state code and name into the URL. We’ll substitute the key and date into the string as parameters.  The tempXPath stores the path to extract the temperature from the XML.  There are multiple temperature readings per day that the code averages out.

The first step in the function code creates a new XmlDocument to store the retrieved XML.  This variable is then loaded by using Load to retrieve data from the http address.  A foreach loop then averages out the temperatures during the day and finally the result is returned to the caller.

At this point I created an application to wrap the library in for testing.  It was simply a C# Console project with a reference to the class library.  I’ll provide the code, but won’t go into detail on it.  It simply displays the average temperature to the console window.

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.SqlServer.Server;

namespace WeatherUndergroundTestApp
{
class WeatherUndergroundTestApp
{
static void Main(string[] args)
{

SqlDateTime yesterday = new SqlDateTime(DateTime.Today.AddDays(-1));
SqlString key = new SqlString("<your_api_key_here>");
SqlDecimal avgTemp = WeatherUndergroundFunctions.getDailyAverageTemperature(yesterday, key);
Console.WriteLine("Average Temp: " + avgTemp.ToString());
Thread.Sleep(5000);

}
}
}

Once the class library has been tested successfully, all we need to do is to install the assembly into SQL Server as a CLR library.  Be sure to enable CLR before you take the next steps.  The first step is to make sure that the database will run the CLR code securely.  Two ways to do this are to cryptographically sign the code and the other is to set the TRUSTWORTHY property to ON.  Be sure to understand the implications of this choice in your own environment.  We’ll use the TRUSTWORTHY property to keep things simple.

USE Sandbox
GO

ALTER DATABASE Sandbox SET TRUSTWORTHY ON
GO

CREATE ASSEMBLY WeatherUnderground
FROM 'C:\CLR Code\WeatherUnderground\WeatherUndergroundFunctions.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO

Next we’ll create a function that uses the assembly.  This is essentially a wrapper for the CLR function.

CREATE FUNCTION dbo.getDailyAverageTemperature(@tempDate DATETIME, @weatherUndergroundKey NVARCHAR(30))
RETURNS DECIMAL(10,2)
AS EXTERNAL NAME WeatherUnderground.WeatherUndergroundFunctions.getDailyAverageTemperature

Finally we’ll test the function.

SELECT dbo.getDailyAverageTemperature(DATEADD(DAY,-1,GETDATE()), N'<your_api_key_here>')

Run CLR Function

Once the function has been created you can use it like any other function in SQL Server.

Leave a Reply