User Tools

Site Tools


Sidebar

Network and communication

k24:k24.6:k24.6.9:k24.6.9.2:start

24.6.9.2 Weather Data Project

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

B1 - GUI
Figure 24.6.9.2.1: GUI weather data

The following tasks need to be processed in the project:

  • First, the weather data must be downloaded as JSON text from the data server of openweathermap.org/ to the home PC and saved as text in a suitable way (temporarily). For the download you can use the programme 'wget' and the instructions SHELL or EXEC or the HTTP client (gb.net.curl), which is preferred. For the download, provide the following parameters: an API key from openweathermap.org , location and country identifier.
  • Then the JSON text is to be decoded using the method JSON.Decode(JSONString As String [, UseNull As Boolean]). The result is stored - depending on the optional parameter UseNull - in a variable of the type Collection or JSON-Collection.
  • Subsequently, the values of the individual weather data are to be determined from the collection with the help of the keys specified in the JSON text. Either the weather data is immediately displayed in suitable controls → Figure 24.6.9.2.1 or stored in variables. Saving is appropriate if the data still have to be converted and formatted before they are further processed or displayed. This is especially true for date and time information.
  • Since in the weather data, in addition to the short description of the weather (in German if the language is specified accordingly), the identifier for a suitable weather symbol is also specified, a download of the symbol image file (png format) is to be planned with another HTTP client. As (optional) parameters for the method HTTPClient.([Headers As String[], TargetFile As String]) an empty string array and the file path for the symbol image file are to be passed.

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:

  • For processing the first task, the function GetData(…) is used in lines 94 to 113 with the necessary arguments. The arguments are defined via three constants in lines 15 to 17. The JSON text is stored in the variable sJSONData of type string in line 27.
  • For checking purposes, you can output the JSON text in the console of the Gambas IDE in lines 29 to 31. The JSON text is much easier to read if you output it formatted.
  • The processing of the second task requires the decoding of the JSON text. This is done by the JSON.Decode(…) method. Data in JSON format becomes data of the Gambas type Variant - here specifically of the type JSONCollection.

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

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

B2
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.

Download

Project

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k24/k24.6/k24.6.9/k24.6.9.2/start.txt · Last modified: 16.08.2022 (external edit)

Page Tools