Discovering the Weather Underground using Objective-XML and Objective-Smalltalk

After starting various forms last year (from flying), I became very interested in weather data, especially wind information. While many websites offer this, like Jeff Greenbaum’s excellent Wind Conditions Page for Pacifica, they don’t present the data in a way that suits me, and often work poorly on mobile devices.

I believe I can improve on this. The Weather Underground offers well-documented XML APIs, so let’s explore this data.

Using the Smalltalk Shell (stsh), we’ll load the Objective-XML framework:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
marcel@spock\[Projects\]stsh
> context loadFramework:'MPWXmlKit'

```Now, let's examine the raw XML from Weather Underground's API.```
\> urlstr:='http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCADALYC1'
> url:=NSURL URLWithString: urlstr
> NSString stringWithContentsOfURL:url.
>

```No result. (Weather Underground seems to require a User Agent, which these methods lack). Let's try with curl:```
\>context addExternalCommand:'curl'.
>curl run:'http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCADALYC1'
	 Weather Underground Personal Weather Station
		http://wunderground.com/weatherstation/
		
		http://icons.wunderground.com/graphics/bh-wui\_logo.gif
		Weather Underground
		http://wunderground.com/weatherstation/
		
		 Mussel Rock, Daly City, CA
		Mussel Rock
		Daly City
		CA
		
		37.667347
		\-122.489342
		514 ft 
		KCADALYC1
		Fan-aspirated Davis Vantage Pro 2 Plus
		Last Updated on November 7, 1:55 PM PST
		Sat, 07 November 2009 21:55:21 GMT
		
		56.9 F (13.8 C)
		56.9
		13.8
		83
		From the NW at 15.0 MPH Gusting to 16.0 MPH
		NW
		313
		15.0
		16.0
		30.07" (1018.2 mb)
		1018.2
		30.07
		51.8 F (11.0 C)
		51.8
		11.0
		
		
		
		
		
		
		
		
		
		483.00
		2.5
		0.00 in (0.0 mm)
		0.00
		0.0
		0.01 in (0.0 mm)
		0.01
		0.0
		http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCADALYC1
		http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.667347,-122.489342

```That's better. Let's parse this XML into a Cocoa Property List.```
\> parser := MPWMAXParser parser.
> parser parsedDataFromURL: 'http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCADALYC1'
{
    UV = "2.5";
    credit = "Weather Underground Personal Weather Station";
    "credit\_URL" = "http://wunderground.com/weatherstation/";
    "dewpoint\_c" = "11.1";
    "dewpoint\_f" = "51.9";
    "dewpoint\_string" = "51.9 F (11.1 C)";
    "heat\_index\_c" =     {
    };
    "heat\_index\_f" =     {
    };
    "heat\_index\_string" =     {
    };
    "history\_url" = "http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCADALYC1";
    image =     {
        link = "http://wunderground.com/weatherstation/";
        title = "Weather Underground";
        url = "http://icons.wunderground.com/graphics/bh-wui\_logo.gif";
    };
    location =     {
        city = "Daly City";
        elevation = "514 ft";
        full = "Mussel Rock, Daly City, CA";
        latitude = "37.667347";
        longitude = "-122.489342";
        neighborhood = "Mussel Rock";
        state = CA;
        zip =         {
        };
    };
    "ob\_url" = "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.667347,-122.489342";
    "observation\_time" = "Last Updated on November 7, 1:55 PM PST";
    "observation\_time\_rfc822" = "Sat, 07 November 2009 21:55:51 GMT";
    "precip\_1hr\_in" = "0.00";
    "precip\_1hr\_metric" = "0.0";
    "precip\_1hr\_string" = "0.00 in (0.0 mm)";
    "precip\_today\_in" = "0.01";
    "precip\_today\_metric" = "0.0";
    "precip\_today\_string" = "0.01 in (0.0 mm)";
    "pressure\_in" = "30.07";
    "pressure\_mb" = "1018.2";
    "pressure\_string" = "30.07\\" (1018.2 mb)";
    "relative\_humidity" = 83;
    "solar\_radiation" = "482.00";
    "station\_id" = KCADALYC1;
    "station\_type" = "Fan-aspirated Davis Vantage Pro 2 Plus";
    "temp\_c" = "13.9";
    "temp\_f" = "57.0";
    "temperature\_string" = "57.0 F (13.9 C)";
    weather =     {
    };
    "wind\_degrees" = 342;
    "wind\_dir" = NNW;
    "wind\_gust\_mph" = "24.0";
    "wind\_mph" = "18.0";
    "wind\_string" = "From the NNW at 18.0 MPH Gusting to 24.0 MPH";
    "windchill\_c" =     {
    };
    "windchill\_f" =     {
    };
    "windchill\_string" =     {
    };
}

```This looks good. The wind data, with keys "wind\_degrees" and "wind\_mph", is near the bottom. Let's extract these values:```
\> (parser parsedDataFromURL:'http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCADALYC1' ) collect objectForKey: #( wind\_mph wind\_dir wind\_string ) each. 
21.0
NW
From the NW at 21.0 MPH Gusting to 24.0 MPH

```We retrieved the wind data, but the direction is a string, not the numerical value. Let's fix that:```
\> (parser parsedDataFromURL: 'http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCADALYC1' ) collect objectForKey: #( wind\_mph wind\_degrees wind\_string ) each.
12.0
318
From the NW at 12.0 MPH Gusting to 24.0 MPH
>

```Perfect! We now have the wind speed, numerical direction, and a descriptive string for display.
Licensed under CC BY-NC-SA 4.0
Last updated on Feb 21, 2023 15:18 +0100