De Yahoo Weersvoorspelling gebruiken …
Zolang Yahoo deze dienst aanbiedt, kunnen we de weersvoorspelling van iedere locatie via de Yahoo Weather API ophalen.
Net zoals met zo veel dingen, relatief makkelijk,… als je eenmaal weet hoe het werkt…
SQL-achtige Weer Query
Als je naar de Yahoo Weather Developer Network pagina gaat, dan zie je dat we een SQL-achtige query taal kunnen gebruiken voor het ophalen van de weersverwachting.
Als je een beetje bekend bent met SQL, dan klinkt dit vast bekend:
SELECT * FROM weather.forecast WHERE woeid IN (SELECT woeid FROM geo.places(1) WHERE text="breda,nederland")
Hier halen we de weersvoorspelling (forecast) op van Breda,Nederland, waarbij we Yahoo laten uitzoeken wat de locatie ID is via een subquery:
SELECT woeid FROM geo.places(1) WHERE text="breda,nederland"
Het gevonden antwoord, “woeid”, hebben we in de query nodig om aan te geven voor welke locatie we de weersvoorspelling willen ophalen uit de weather.forecast tabel.
Weersvoorspelling: JSON of XML?
We kunnen de Yahoo Weersvoorspelling ophalen in 1 van de volgende formaten: JSON of XML. Ik kies het liefste JSON, want daar kan ik met weinig moeite en overhead mee aan de slag. XML heeft me in het verleden al te veel hoofdpijn gegeven, dus ik gebruik XML liever niet.
URL opbouwen voor de Yahoo Weersvoorspellingen
Laten we eens gaan kijken naar de link voor het ophalen van de Yahoo Weersvoorspelling, zoals je die ziet onder aan de Yahoo Weather Developer pagina:
https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22breda%2C
%20nederland%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys
Vergeet het volgende dus niet:
- We willen de weersvoorspelling van “Breda, Nederland“,
- En wel in JSON formaat
De basis URL (link) is:
https://query.yahooapis.com/v1/public/yql?q=...
Dit wordt gevolgd door de SQL-achtige query, welke in in HTML veilige karakters wordt uitgedrukt (ook wel URL Encoding, of Percent-encoding, genoemd, waarbij dus bijvoorbeeld een wordt vervangen door een %20, wat staat voor hex 20, wat decimaal 32 is, en in ASCII code staat voor en spatie).
select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22breda%2C%20nederland%22)...
Zie jet het stukje text%3D%22breda%2C%20nederland%22
?
“Vertaald” staat hier: test=”breda, nederland”
Hier kunnen we dus de locatie als tekst doorgeven. De spatie voor “nederland” hoeft er overigens niet te staan, en hoofdletter maakt ook niets uit.
Echter als jouw plaatsnaam, of land naam, spaties bevat, dan moeten we dit dus met URL Encode behandelen. Om nu zeker te zijn dat we niet tegen problemen aanlopen, heb ik dus een functie gemaakt, die in de unit zit, die dit automatisch voor ons doet.
Overigens, soms moet je wat specifieker zijn, als het om de locatie gaat.
Stel je wilt het weer weten voor “Osceola, WI” (WI = Wisonsin, en dat is in de USA). Als we nu “osceola,usa” opgeven, dan lopen we teen een probleem aan. Amerika kent namelijk meerdere plaatsen met de naam Osceola. Omdat we in de subquery aangeven dat we alleen het eerste resultaat willen voor de locatie, dan zullen we zien dat het weer terug komt voor “osecola,fl” – in Florida dus. In dat geval moeten we dus: “osceola,wi,usa” gebruiken (“usa” hoeft er niet eens bij te staan).
Voor de meeste plaatsen is echter “plaats,land” voldoende, zoals we dus doen met “breda,nederlands”.
Hierbij mag het land in het Engels weergegeven worden (Netherlands) of in de taal van het land (Nederland).
Na opgegeven van de locatie, moeten we ook opgegeven in welk format we de data willen (JSON!).
&format=json...
Dit wordt dan gevolgt door wat extra parameters waar we hier maar niet op ingaan:
&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys
We weten dus nu hoe de link (URL) er uitziet en wat wat is.
Ad Blocking Gedetecteerd Vriendelijk verzoek om te overwegen Ad Blocking uit te zetten voor onze website.
We zijn afhankelijk van inkomen uit Advertenties om de website te kunnen draaien.
Je kunt ons ook op andere manieren ondersteunen (zie Ondersteun ons links bovenin).
De Yahoo Weather Forecast Unit
Zoals ik dus al in het begin zei; ik heb alles in een unit gemikt, om het net even wat gemakkelijker te maken. Uiteraard is er altijd ruimte voor verbetering, maar het geeft je een idee en misschien een goede start, mocht je het e.e.a. anders of efficiënter willen doen. Laat het hier vooral weten als je een betere aanpak weet.
Yahoo Weersvoorspelling in een Record
Om het resultaat eenvoudiger te lezen, heb ik besloten alles in een record te zetten.
De JSON data wordt automatisch uit elkaar getrokken en in dit record type (TYahooForecast) gezet. Omdat de weersvoorspelling van Yahoo meteen 10 dagen voorspelt, heb ik nog een record type gemaakt die elk een dag bevatten (zie de array in de TYahooForcast hieronder).
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
| TDayForcast = record
code:string;
date:string;
day:string;
high:string;
low:string;
text:string;
end;
TYahooForecast = record
success:boolean;
distance:string;
pressure:string;
speed:string;
temperature:string;
location_city:string;
location_country:string;
location_region:string;
wind_chill:string;
wind_direction:string;
wind_speed:string;
atmosphere_humidity:string;
atmosphere_pressure:string;
atmosphere_rising:string;
atmosphere_visibility:string;
astronomy_sunrise:string;
astronomy_sunset:string;
location_latitude:string;
location_longitude:string;
last_updated:string;
current_code:string;
current_date:string;
current_temp:string;
current_text:string;
forecast: array [0..9] of TDayForcast;
end; |
Om nu de weersvoorspelling te krijgen, kunnen we een van deze methoden gebruiken:
1 2 3 4 5 6 7 8
| // Standaard (in Celsius)
tmpData := GetYahooForecast('breda, nederlands');
// forceer Fahrenheit
tmpData := GetYahooForecast('breda, nederland','f');
// forceer Celsius
tmpData := GetYahooForecast('breda, nederland','c'); |
Je kunt speciale karakters gewoon gebruiken omdat ik URL Encoding automatisch toepas. In jouw eigen code hoef je hier dus niets mee te doen en hoef je er dus helemaal niet op te letten.
Na het aanroepen, moeten we eerst even controleren of alles goed is gegaan door naar de waarde van het veld “success” in de record te kijken.
1 2 3 4 5 6 7 8 9 10 11
| if tmpData.success then
begin
with tmpData do
begin
memo1.lines.add('Afstand eenheden: '+distance);
memo1.lines.add('Luchtdruk eenheden: '+pressure);
...
end;
end
else
// DATA OPHALEN MISLUKT |
Zoals je hier al ziet, is het lezen van de data makkelijk geworden.
Voor het lezen vand e voorspelling voor de 10 dagen:
1 2 3 4 5 6 7 8 9
| for Counter:=0 to 9 do
begin
memo1.lines.add('Code: '+tmpdata.forecast[Counter].code);
memo1.lines.add('Datum: '+tmpdata.forecast[Counter].date);
memo1.lines.add('Weekdag: ' +tmpdata.forecast[Counter].day);
memo1.lines.add('Hoog: '+tmpdata.forecast[Counter].high);
memo1.lines.add('Laag: ' +tmpdata.forecast[Counter].low);
memo1.lines.add('Tekst: '+tmpdata.forecast[Counter].text);
end; |
De Unit
Hieronder vindt je de hele unit.
Niet vergeten dus dat je Synapse, nodig hebt, wat gratis is. Je hoeft het niet te installeren, op de Mac faalde dat zelfs. Je hoeft de zip alleen maar uit te pakken en alle bestanden in de directory “/source/lib” in jouw project directory te kopiëren.
Je kunt onderstaande code kopiëren en plakken, of je kunt het hier ook gewoon downloaden (er zit dan een klein voorbeeld programma bij).
Update: HTTPS voor Windows gebruikers …
Omdat het HTTPS protocol gebruikt wordt, hebben we SSL ondersteuning nodig.
Onder MacOS X en Linux, staat OpenSSL al standaard beschikbaar en kan Synapse daar meten mee aan de slag. Onder Windows is dat helaas niet het geval. Met dank aan Joseph Kaminchick voor het ontdekken van dit probleem!
Voor Windows gebruikers zitten nu precompiled OpenSSL tools in de ZIP (libeay32.dll, openssl.exe en ssleay32.dll) .
Bedenk dat ik dit alleen met 32 bits applicaties heb getest.
Download - Lazarus Pascal YahooWeather Unit
Bestandsnaam: |
Lazarus-Pascal-YahooWeatherUnit.zip |
Platform: |
Undefined |
Versie: |
1.1 |
Omvang: |
1.5 MB |
Datum: |
2016-12-17 |
Download Nu
Stuur me Koffie
|
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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
| unit YahooWeather;
{ Unit to retrieve Yahoo Weather Forecast
(C)2015 Hans Luijten, //www.tweaking4all.com
Version 1.0
Uses: Synapse (http://synapse.ararat.cz/,
fpjson (Comes with Lazarus)
openssl (part of synapse, weather is retrieved with https://)
Common use:
GetYahooForecast(location);
Retrieves current weather and weather forecast, and returns this in a record for easy access.
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, httpsend, ssl_openssl, fpjson, jsonparser;
type
TDayForcast = record
code:string;
date:string;
day:string;
high:string;
low:string;
text:string;
end;
TYahooForecast = record
success:boolean;
distance:string;
pressure:string;
speed:string;
temperature:string;
location_city:string;
location_country:string;
location_region:string;
wind_chill:string;
wind_direction:string;
wind_speed:string;
atmosphere_humidity:string;
atmosphere_pressure:string;
atmosphere_rising:string;
atmosphere_visibility:string;
astronomy_sunrise:string;
astronomy_sunset:string;
location_latitude:string;
location_longitude:string;
last_updated:string;
current_code:string;
current_date:string;
current_temp:string;
current_text:string;
forecast: array [0..9] of TDayForcast;
end;
function GetYahooWeatherData(Location:string; AsJSON:boolean =true; TemperatureUnits:string = 'c'):string;
function GetYahooForecast(Location:string; TemperatureUnits:string = 'c'):TYahooForecast;
function YahooURLEncode(s: string): string;
implementation
{
URLEncode
Encodes string to be suitable as an URL.
Example: myencodeURL:=YahooURLEncode(myURL);
}
function YahooURLEncode(s: string): string;
var
i: integer;
source: PAnsiChar;
begin
result := '';
source := pansichar(s);
for i := 1 to length(source) do
if not (source[i - 1] in ['A'..'Z', 'a'..'z', '0'..'9', '-', '_', '~', '.', ':', '/']) then
result := result + '%' + inttohex(ord(source[i - 1]), 2)
else
result := result + source[i - 1];
end;
{ Retrieve Yahoo Weather with forcast and place it in a record for easy access
MyYahooForcast := GetYahooForecast('town,country',true,'c')
}
function GetYahooForecast(Location:string; TemperatureUnits:string = 'c'):TYahooForecast;
var JSONData:TJSONData;
RawData:string;
tmpData:TYahooForecast;
Counter:integer;
begin
RawData := GetYahooWeatherData(Location,true,TemperatureUnits);
Counter:=0;
while ((RawData='') or (pos('ERROR',RawData)>0)) and (Counter<3) do
begin
RawData := GetYahooWeatherData(Location,true,TemperatureUnits);
inc(Counter);
end;
if ((RawData='') or (pos('ERROR',RawData)>0)) then
tmpData.success:=false
else
begin
JSONData := GetJSON(RawData);
with tmpdata do
begin
success:=true;
distance:=JSONData.FindPath('query.results.channel.units.distance').AsString;
pressure:=JSONData.FindPath('query.results.channel.units.pressure').AsString;
speed:=JSONData.FindPath('query.results.channel.units.speed').AsString;
temperature:=JSONData.FindPath('query.results.channel.units.temperature').AsString;
location_city:=JSONData.FindPath('query.results.channel.location.city').AsString;
location_country:=JSONData.FindPath('query.results.channel.location.country').AsString;
location_region:=JSONData.FindPath('query.results.channel.location.region').AsString;
wind_chill:=JSONData.FindPath('query.results.channel.wind.chill').AsString;
wind_direction:=JSONData.FindPath('query.results.channel.wind.direction').AsString;
wind_speed:=JSONData.FindPath('query.results.channel.wind.speed').AsString;
atmosphere_humidity:=JSONData.FindPath('query.results.channel.atmosphere.humidity').AsString;
atmosphere_pressure:=JSONData.FindPath('query.results.channel.atmosphere.pressure').AsString;
atmosphere_rising:=JSONData.FindPath('query.results.channel.atmosphere.rising').AsString;
atmosphere_visibility:=JSONData.FindPath('query.results.channel.atmosphere.visibility').AsString;
astronomy_sunrise:=JSONData.FindPath('query.results.channel.astronomy.sunrise').AsString;
astronomy_sunset:=JSONData.FindPath('query.results.channel.astronomy.sunset').AsString;
location_latitude:=JSONData.FindPath('query.results.channel.item.lat').AsString;
location_longitude:=JSONData.FindPath('query.results.channel.item.long').AsString;
last_updated:=JSONData.FindPath('query.results.channel.item.pubDate').AsString;
current_code:=JSONData.FindPath('query.results.channel.item.condition.code').AsString;
current_date:=JSONData.FindPath('query.results.channel.item.condition.date').AsString;
current_temp:=JSONData.FindPath('query.results.channel.item.condition.temp').AsString;
current_text:=JSONData.FindPath('query.results.channel.item.condition.text').AsString;
for Counter:=0 to 9 do
begin
with tmpData.forecast[Counter] do
begin
code:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].code').AsString;
date:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].date').AsString;
day:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].day').AsString;
high:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].high').AsString;
low:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].low').AsString;
text:=JSONData.FindPath('query.results.channel.item.forecast['+IntToStr(Counter)+'].text').AsString;
end;
end;
end;
end;
GetYahooForecast := tmpData;
end;
{ Retrieve Yahoo Weather information
myString := GetYahooWeatherData('town,country',true,'c');
Location: typically use town,country, for example: 'osceola,wi.usa', 'amsterdam,netherlands', 'breda,nederland'
AsJSON : return as a JSON string if TRUE, otherwise in XML format (JSON default)
TemperatureUnits: 'c' for Celcius, and 'f' for Fahrentheit (C default)
}
function GetYahooWeatherData(Location:string; AsJSON:boolean =true; TemperatureUnits:string = 'c'):string;
var HTTPSender : THTTPSend;
tmpData : TStringList;
resultString, resultFormat: String;
begin
if Location='' then
GetYahooWeatherData:='ERROR: Missing Location'
else
begin
if AsJSON then
resultFormat := 'json'
else
resultFormat := 'xml';
tmpData := TStringList.Create;
HTTPSender := THTTPSend.Create;
try
HTTPSender.HTTPMethod('GET',
'https://query.yahooapis.com/v1/public/yql?'+
'q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20('+ // get forecast
'select%20woeid%20from%20geo.places(1)%20where%20text%3D%22'+YahooURLEncode(Location)+'%22)'+ // find location based on string
'%20and%20u%3D%22'+TemperatureUnits+'%22'+ // force units (c or f)
'&format='+resultFormat+'&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys');
if (HTTPSender.ResultCode >= 100) and (HTTPSender.ResultCode<=299) then
tmpData.LoadFromStream(HTTPSender.Document)
finally
HTTPSender.Free;
end;
if tmpData.Text='' then
resultString:='ERROR: Unable to retrieve data'
else
resultString:=tmpData.Text;
tmpData.Free;
GetYahooWeatherData := resultString;
end;
end;
end. |
Yahoo Weather geeft ook een weer-code terug. Het wordt gebruikt om de weer-conditie in tekst weer te geven, vooral als je met andere talen gaat werken. Voor de Engelse taal doet Yahoo dat al zelf in het “text” veld (voor elk van de 10 dagen) en “current_text” veld (voor vandaag).
Hieronder een lijstje met de Engels tekst, welke je zou kunnen ombouwen naar b.v. Nederlands.
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
| const YahooWeatherCondition : array[0..48] of string = ('tornado',
'tropical storm',
'hurricane',
'severe thunderstorms',
'thunderstorms',
'mixed rain and snow',
'mixed rain and sleet',
'mixed snow and sleet',
'freezing drizzle',
'drizzle',
'freezing rain',
'showers',
'showers',
'snow flurries',
'light snow showers',
'blowing snow',
'snow',
'hail',
'sleet',
'dust',
'foggy',
'haze',
'smoky',
'blustery',
'windy',
'cold',
'cloudy',
'mostly cloudy (night)',
'mostly cloudy (day)',
'partly cloudy (night)',
'partly cloudy (day)',
'clear (night)',
'sunny',
'fair (night)',
'fair (day)',
'mixed rain and hail',
'hot',
'isolated thunderstorms',
'scattered thunderstorms',
'scattered thunderstorms',
'scattered showers',
'heavy snow',
'scattered snow showers',
'heavy snow',
'partly cloudy',
'thundershowers',
'snow showers',
'isolated thundershowers',
'not available'); |
Met een simpele procedure zou je de code (een nummer) dan kunnen “vertalen”.
Overigens, Codes > 48 zijn altijd “niet beschikbaar” (not available).
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function WeatherCode2String(code:string):string;
var intCode:integer;
begin
try
intCode:=StrToInt(code)
except
intCode:=3200
end;
if (intCode<0) or (intCode>47) then
WeatherCode2String:= YahooWeatherCondition[48]
else
WeatherCode2String:= YahooWeatherCondition[intCode]
end; |
Reacties
Er zijn nog geen reacties geplaatst.
Je kunt jouw eigen opmerkingen plaatsen m.b.v. dit formulier, of een reactie op een bestaande opmerking plaatsen door op de "Beantwoorden" knop te klikken.