According to https://en.wikipedia.org/wiki/Openweathermap, OpenWeatherMap is an online service that provides a programming language-independent and freely usable interface (API) for weather data. However, you must request a free API key via https://home.openweathermap.org/users/sign_up to access this weather data. Important in relation to the presented project is the fact that all weather data can be obtained in JSON format (standard). One restriction for the free API is that the weather data is only updated every two hours.
For calling the weather data for the place Osterburg in Germany, these values were used:
Ort: q={city name} → q=Osterburg Ort und Landeskenner: q={city name},{country code} → q=Osterburg,de Daten-Format: mode={ xml | html } JSON ist Standard Sprache für kurze Wetterbeschreibung: lang={Landeskenner} → lang=de Temperatur-Skala: units={ metric (°C) | imperial (F) } Standard ist Kelvin → units=metric API-Key: APIID={ API-Key } → APIID=YourAPIKEY
URL: http://api.openweathermap.org/data/2.5/weather?q=Osterburg,de&lang=de&units=metric&APPID=yorAPIKEY
Figure 24.6.9.2.1: GUI weather data
The following tasks need to be processed in the project:
The source code is specified in full and then commented:
[1] ' Gambas class file [2] [3] Public sJSONData As String [4] Public sAPIKey As String [5] [6] Public jCollection As JSONCollection [7] Public cWind As Collection [8] Public cClouds As Collection [9] Public cMain As Collection [10] Public cSys As Collection [11] Public aWeather As Variant[] [12] Public iTimeStampGMT As Integer [13] Public sCity As String [14] [15] Const _API_KEY As String = "YOUR_API_KEY" [16] Const _CITY As String = "YOUR_CITY" [17] Const _COUNTRY As String = "YOUR_COUNTRY" [18] [19] Public Sub Form_Open() [20] [21] Dim sFormat, sMessage As String [22] [23] FMain.Center() [24] FMain.Resizable = False [25] FMain.Title = ("Current weather data") [26] [27] sJSONData = GetWeatherData(_CITY, _COUNTRY, _API_KEY) [28] [29] ' Print sJSONData [30] ' Shell "echo '" & sJSONData & "' | python -m json.tool" To sFormat [31] ' Print sFormat [32] [33] jCollection = JSON.Decode(sJSONData, True) [34] [35] If jCollection["cod"] = 401 Then [36] sMessage = "Sie müssen einen (kostenlosen) API-Key von<br>" [37] sMessage &= "<b>https://home.openweathermap.org/users/sign_up</b>" [38] sMessage &= "<br>anfordern, um die Wetter-Daten auslesen zu können!" [39] Message.Error(sMessage) [40] FMain.Close() [41] Else [42] ShowWeatherData() [43] Endif [44] [45] End ' Form_Open() [46] [47] '--------------------------------------------------------------------------------------------------- [48] [49] Private Sub ShowWeatherData() [50] [51] Dim iTimeStampUTC As Integer [52] Dim sCityName, sDate, sIcon, sDay, sDateDMY, sTime As String [53] Dim dDate As Date [54] [55] sCityName = jCollection["name"] [56] [57] iTimeStampUTC = jCollection["dt"] [58] dDate = TimeStampToDate(iTimeStampUTC) [59] sDay = Format$(dDate, "dddd") [60] sDateDMY = Format$(dDate, "d. mmmm yyyy") [61] sTime = Format$(dDate, "hh:nn") & " Uhr (UTC)" [62] sDate = sDay & ", " & sDateDMY & " - " & sTime [63] FMain.Text = ("Current weather data") & (" for ") & sCityName & ": " & sDate [64] [65] cWind = jCollection["wind"] [66] txbWindSpeed.Text = cWind["speed"] [67] txbWindDirection.Text = Round(cWind["deg"], 0) [68] '----------------------------------------------- [69] ' cMain = jCollection["main"] [70] ' txbTemperature.Text = cMain["temp"] [71] ' txbPressure.Text = cMain["pressure"] [72] ' txbHumidity.Text = cMain["humidity"] [73] txbTemperature.Text = jCollection["main"]["temp"] [74] txbPressure.Text = jCollection["main"]["pressure"] [75] txbHumidity.Text = jCollection["main"]["humidity"] [76] '---------------------------------------------------- [77] cClouds = jCollection["clouds"] [78] txbCloudiness.Text = cClouds["all"] [79] '------------------------------------ [80] cSys = jCollection["sys"] [81] txbSunRise.Text = Format(TimeStampToDate(cSys["sunrise"]), "hh:nn") [82] txbSunSet.Text = Format(TimeStampToDate(cSys["sunset"]), "hh:nn") [83] '-------------------------------------------------------------------- [84] aWeather = jCollection["weather"] [85] lblDescription.Text = aWeather[0]["description"] [86] sIcon = aWeather[0]["icon"] [87] ' lblDescription.Text = jCollection["weather"][0]["description"] [88] ' sIcon = jCollection["weather"][0]["icon"] [89] GetWeatherIcon(sIcon) [90] pboxWeather.Picture = Picture[Application.Path &/ "Icon/weathericon.png"] [91] [92] End ' ShowWeatherData() [93] [94] Private Function GetWeatherData(City As String, Country As String, APIKey As String) As String [95] [96] Dim sURL As String [97] Dim hHTTPClient As HttpClient [98] [99] sURL = "http://api.openweathermap.org/data/2.5/weather" [100] sURL &= "?q=" & City & "," & Country [101] sURL &= "&lang=" & Country [102] sURL &= "&units=metric" [103] sURL &= "&APPID=" & APIKey [104] [105] hHTTPClient = New HttpClient As "hHTTPClient" [106] hHttpClient.URL = sURL [107] hHTTPClient.Async = False [108] hHTTPClient.Timeout = 10 [109] Try hHTTPClient.Get() [110] [111] Return hHTTPClient.ReadLine() [112] [113] End ' GetData(City As String, Country As String, APIKey) [114] [115] Private Sub GetWeatherIcon(Icon As String) [116] [117] Dim hHTTPClient As HttpClient [118] [119] hHTTPClient = New HttpClient As "hHTTPClient" [120] hHttpClient.URL = "http://openweathermap.org/img/w/" & Icon & ".png" [121] hHTTPClient.Async = False [122] hHTTPClient.Timeout = 10 [123] Try hHTTPClient.Get([], Application.Path &/ "Icon/weathericon.png") [124] [125] End ' GetWeatherIcon(...) [126] [127] Private Function TimeStampToDate(TimeStamp As Integer) As Date [128] Return DateAdd(CDate("1/1/1970"), gb.Second, TimeStamp) [129] End ' TimeStampToDate
Comment:
If one analyses the following JSON text
{"coord":{"lon":11.77,"lat":52.78},"weather":[{"id":500,"main":"Rain","description":"leichter Regen", "icon":"10d"}],"base":"cmc stations","main":{"temp":8.61,"pressure":1021.23,"humidity":92, "temp_min":8.61,"temp_max":8.61,"sea_level":1025.91,"grnd_level": 1021.23},"wind":{"speed":3.66, "deg":90.505}, "rain":{"3h":0.84},"clouds":{"all":92},"dt":1460443601,"sys": {"message":0.0036, "country":"DE","sunrise":1460434806, "sunset":1460484485},"id":2856639,"name":"Osterburg","cod":200}
then one recognises for the individual keys in the JSONCollection, in addition to the values of the weather data, also the value type, which are once again explicitly specified here:
Anzahl der Elemente in der JSON-Collection: 11 ----------------------------------------------------- Schlüssel 1 : "coord" ---> Wert-Typ: JSONCollection Schlüssel 2 : "weather" ---> Wert-Typ: Variant[] Schlüssel 3 : "base" ---> Wert-Typ: String Schlüssel 4 : "main" ---> Wert-Typ: JSONCollection Schlüssel 5 : "wind" ---> Wert-Typ: JSONCollection Schlüssel 6 : "clouds" ---> Wert-Typ: JSONCollection Schlüssel 7 : "dt" ---> Wert-Typ: Integer Schlüssel 8 : "sys" ---> Wert-Typ: JSONCollection Schlüssel 9 : "id" ---> Wert-Typ: Integer Schlüssel 10 : "name" ---> Wert-Typ: String Schlüssel 11 : "cod" ---> Wert-Typ: Integer
Example 1: Determining the date and time at which the weather data was collected
The key 7 “dt” stands for DateTime and returns the value for this key as a time stamp (TimeStamp) of the type Integer. As you can see, the complete date was mapped to an integer. In lines 58 to 60, the TimeStampToDate(..) function is used to convert the time stamp into a date (type Date), which is formatted three times differently for display in the window line:
iTimeStampUTC = jCollection["dt"] dDate = TimeStampToDate(iTimeStampUTC) sDay = Format$(dDate, "dddd") sDateDMY = Format$(dDate, "d. mmmm yyyy") sTime = Format$(dDate, "hh:nn") & " Uhr (UTC)" sDate = sDay & ", " & sDateDMY & " - " & sTime FMain.Text = ("Current weather data") & (" for ") & sCityName & ": " & sDate
Example 2: Determining temperature, air pressure and humidity
The key 4 “main” returns a collection with the keys “temp”, “pressure” and “humidity” as value. You can either display the values for temperature, air pressure and humidity immediately with the help of the variable cMain in lines 2 to 4 or use lines 5 to 7:
[1] ' cMain = jCollection["main"] [2] ' txbTemperature.Text = cMain["temp"] [3] ' txbPressure.Text = cMain["pressure"] [4] ' txbHumidity.Text = cMain["humidity"] [5] txbTemperature.Text = jCollection["main"]["temp"] [6] txbPressure.Text = jCollection["main"]["pressure"] [7] txbHumidity.Text = jCollection["main"]["humidity"]
Example 3: Determining the weather description and the identifier for the weather icon
The key 2 “weather” in the JSONCollection returns as value in this case a variant array whose only element is a collection! Since only the weather description and the identifier for the weather icon are of interest here, the two keys “description” and “icon” are required. Using the variable aWeather of the type Variant[], you can immediately display the weather description. Line 3 in conjunction with lines 6 and 7 loads the file for the weather icon and displays the weather icon immediately in a picture box. An alternative for lines 1 to 3 - omitting a variable for the Variant array - can be found in lines 4 and 5:
[1] aWeather = jCollection["weather"] [2] lblDescription.Text = aWeather[0]["description"] [3] sIcon = aWeather[0]["icon"] [4] ' lblDescription.Text = jCollection["weather"][0]["description"] [5] ' sIcon = jCollection["weather"][0]["icon"] [6] GetWeatherIcon(sIcon) [7] pboxWeather.Picture = Picture[Application.Path &/ "Icon/weathericon.png"]
Here you can see the easily readable JSON text, because it is output formatted:
{ "base": "cmc stations", "clouds": { "all": 92 }, "cod": 200, "coord": { "lat": 52.78, "lon": 11.77 }, "dt": 1460443601, "id": 2856639, "main": { "grnd_level": 1021.23, "humidity": 92, "pressure": 1021.23, "sea_level": 1025.91, "temp": 8.61, "temp_max": 8.61, "temp_min": 8.61 }, "name": "Osterburg", "rain": { "3h": 0.84 }, "sys": { "country": "DE", "message": 0.0036, "sunrise": 1460434806, "sunset": 1460484485 }, "weather": [ { "description": "leichter Regen", "icon": "10d", "id": 500, "main": "Rain" } ], "wind": { "deg": 90.505, "speed": 3.66 } }
If there are umlauts in the weather description, for example, they will be converted:
"weather": [ { "description": "\u00fcberwiegend bew\u00f6lkt", "icon": "04d", "id": 803, "main": "Clouds" } ]
You also get the error messages in JSON format - like here with a missing API key:
{ "cod": 401, "message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info." }
This error is also caught in the project in lines 35 to 43:
If jCollection["cod"] = 401 Then sMessage = "Sie müssen einen (kostenlosen) API-Key von<br>" sMessage &= "<b>https://home.openweathermap.org/users/sign_up</b>" sMessage &= "<br>anfordern, um die Wetter-Daten auslesen zu können!" Message.Error(sMessage) FMain.Close() Else ShowWeatherData() Endif
Figure 24.6.9.2.2: Error message
The project presented is an adaptation of a project by Steve Dee that he presented on his website http://captainbodgit.blogspot.de.
Project