Skip to content

Building a weather station with MBS by using a JSON API

I want to show you how to retrieve the data of an API over a CURL connection and evaluate the JSON to build a weather station.

In this example I work with a free key from the OpenWeather API. OpenWeather provides an API with weather data that you can access by an URL. The API returns a JSON text containing information such as current weather description, current temperature, pressure, humidity and many more. This is uses the CURL Plugin for the network query and Util plugin for JSON.

The Layout 

We want to take a closer look at this JSON together later. But first we want to build the layout in which we can enter our weather information. This layout basically consists of two areas, one is the data area where our information will be displayed and the other is our area where we can enter the location of the wanted forecast and the unit of measurement for the temperature. 

We start with the settings area. Here there must be a text field for the location. To set the temperature unit we use a popup menu. 

The popup menu has the following entries: °C, °F and K. So later you should be able to choose between Celsius, Fahrenheit and Kelvin as display unit. °C is the default value of the popup menu. In the event “Change” of this popup menu we write the selected unit into a property which we can later need in the program. The default value of the property is “C” and stands for the unit Celsius. The code of the event then looks like this: 

 If PopupMenu1.SelectedRowValue="°C" Then
  TempUnit="C"
Elseif PopupMenu1.SelectedRowValue="°F" Then
  TempUnit="F"
Else
  TempUnit="K"
end if 

We also need a button with which we can start the search.  So we are done with the layout in the settings area. Of course this area can also be decorated and highlighted. 

Now let’s get to the layout of the data area. We first need to know which data should be displayed. 

You can visit the OpenWeather website for more details about the available information. In our application the following information should be displayable:

*Weather description
*Current temperature
*Perceived temperature
*Minimum temperature
*Maximum temperature
*Humidity
*Wind speed
*Atmospheric pressure
*Sunrise and sunset time

We create a separate label for each of these information. Information behind which a unit of measurement should be placed, gets an additional label field with the unit of measurement. The unit of measurement fields for the temperatures are all named the same, so we create an array of labels. This is important, because these units of measurement are to be changed afterwards by script. Of course the inscription must not be missing, so that we can see what information is actually displayed. These can then also be decorated appropriately. 

The CURL Connection to the API 

When we have entered a location and clicked on the search button, the matching values should appear. Now we have to think about where we get our current weather data. As mentioned before we work with the OpenWeather API. To access this API we pass some information with our URL like the desired location and our key. The structure of the URL can look like this:

api.openweathermap.org/data/2.5/weather?q={city name}&appid={your api key}

The informations in the curly brackets must be replaced with your wanted query. For example you want the current weather information for London, where the next Xojo conference will take place and your key would be „123“ the url look like this 

api.openweathermap.org/data/2.5/weather?q=London&appid=123

example result of the URL with a valid key

The result that the URL returns is a JSON text, that contains the requested informations. So we need the text in our program. For this we use a CURL connection. We build it in the action event of the search button and pass the URL 

Action Event: 

Dim c As New MyCURL
c.OptionURL = “api.openweathermap.org/data/2.5/weather?
q=”+Search.Text+”&appid=”+Key
Call c.Perform

In the code we see that we create a new instance of the MyCurl class. The MyCurl class has the superclass CURLSMBS. We need the new class because we want to fill events with code. 

Then we build our URL. We pass the location that is contained in the search text field. Our key is in a property. This has the advantage that we only have to change it in one place and don’t have to search in the source code in case we would query several URLs. At this point it should be mentioned that the Open Weather API can find the weather not only by place name, but also by longitude and latitude, City ID or ZipCode.

Besides the current weather data, forecasts and much more can be called up. When using an API, it is always useful to have a look at the documentation of an API to be able to use it correctly.

The Perform method calls the specified URL. In the event Write of the MyCurl class we get the data of the url. We save the data in the property JSONText as String, because we need this text in different scripts. Then we test if we get valide weather data. E.g. Our key can be wrong or the city is not found. For that test we write a method test, that return a boolean value. If the return value is true we run the method run, that set the informations form the API to our labels. If the result is false, we display in a message Box an error code that is save in a property Error. 

Write Event: 

weather.JSONText=data
Dim c As Boolean=weather.test If c Then weather.run Else MsgBox weather.Error End If

So let’s start to write the method test as first. 

Let’s think about what could go wrong: For example our API key might be wrong. Let’s enter our URL in the browser and change a character in the key so that it doesn’t match ours. The result looks like this: 

{"cod":401, "message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info.“}

We get a code number and an error message as result. The same we can test for a wrong city name 

{"cod":"404","message":"city not found“}

Also here we get only these two keys. We look whether there are also these keys with a normal and valid, functioning query. The answer is yes! In a validquery the key „cod“ always has the value 200, also for different Cities in different Countries. We can use this. So we check whether cod has the value 200. If it is not equal, there was an error and we save the text under the key message in the property Error. This text will be written into a dialog in the Write event. Otherwise the method returns true. 

Method test()as boolean :

Dim json As New JSONMBS(JSONText)
Dim cod As JSONMBS =json.Child ("cod") If cod.toString <>"200" Then Dim message As JSONMBS= json.Child ("message") Error=message.toString Return False Else Error="" Return True End If

So we first create a new instance of the class JSONMBS, to which we pass our JSON from the API. 

We want the result of „cod”. We can compare it. We call the method Child, which we pass the key as parameter. The result is again of type JSONMBS. To be able to read the result, we call the method toString to convert the result to a string that we can compare. 

If the result is not equal 200, we use again the method Child to get the information from the key „message“ and read the information with toString.

Working with the JSON 

We now come to the already used method run. 

In this method we first enter the units of temperature into the labels. Then we create a new instance of the JSONMBS class, that gets the JSON text from the API. 

For i As Integer= 0 To 3
deg(i).Text= PopupMenu1.SelectedRowValue Next Dim json As New JSONMBS(JSONText)

This instance is used for all data queries. The idea of the data query is always the same. We look at the original JSON where the information we want to read is. e.g. the description text of the weather. We go backwards and note the path 


"weather":[ { "id":804, "main":"Clouds", "description":"overcast clouds", "icon":"04d" } ], …

The description text is located under the key description. Description is located in an array. In the array, the desired description is in the first element. (Note that an array starts counting at 0) The array is located in the object weather. So we can build the path from right to left as follows 

weather[0].description

We now unravel this path with various methods and go deeper layer by layer. We start with weather. This key is a Child of or JSON Text. Because of this we write :

Dim weather As JSONMBS= json.Child („weather“)

Now the variable has the following content 

"weather":[
      {
         "id":804,
         "main":"Clouds",
         "description":"overcast clouds",
         "icon":"04d"
      }
   ],

Next we need to get into the array. We need the first element. We use the method ArrayItem and pass 0 as parameter, because we want to address the first element with the index 0.

Dim weatherArray As JSONMBS=weather.ArrayItem(0)

The JSON in weatherArray has the following structure: 

  {
"id":804, "main":"Clouds", "description":"overcast clouds", "icon":"04d" }

Now the description is again a child of this object. And we use the Child method again 

Dim description As JSONMBS= weatherArray.Child(„description“)

Now we have to put the JSON text as MBSJSON datatype into a format that can be read.  For this we use the toString method. Now we have a string that still has quotation marks, which we can replace with an empty string by using the ReplaceAll method.

weatherDes.Text=ReplaceAll(description.toString, Chr(34),"")

The paths of the other information can be read and build similarly.

Convert the temperature 

We get the temperatures by default in Kelvin. You can change this with an addition in the URL. But because we want to choose between Kelvin, Celsius and Fahrenheit anyway, we mostly have to convert the extracted results into the desired unit. So we pass any temperature we get from the API to the tempConvert method. This method has as input the temperature as a double

In If and Else If statements we check which temperature unit is selected in the popup menu. Matching this we do the conversion. The formulas are as follows:

Kelvin -> Fahrenheit 
Fahrenheit= Kelvin*(9/5)-459.67

Kelvin ->Celsius 
Celsius= Kelvin -273

Kelvin-> Kelvin 
Kelvin = Kelvin

These conversions can of course result in unwanted decimal digits. Therefore we format to the first digit after the decimal point and return this value. The Code of this method look like this: 

tempConvert (temp as double) as double:

Dim tempConv As Double

If tempunit="F" Then tempConv = temp*(9/5)-459.67 Elseif tempunit="C" Then tempConv = temp-273.15 Else tempConv = temp End If tempConv=Format(tempConv, "#.#").Val Return tempConv

A further conversion is needed for the sunset and sunrise time. We have given the times in Unix time. That means we have given the seconds from January 1st 1970 00:00 to the time of our time value. We have to convert this into a time that is readable for humans. The code for the sunrise look like this. 

 Dim d1 As New DateTime(rise.ValueInteger, TimeZone.Current)
sunrise.Text=d1.Hour.ToString+":"+d1.Minute.ToString

The code for the sunset looks similar.

the weather in London

Now I wish you a lot of fun with your own weather station. Download the project here and if you have any questions please feel free to contact me. 

Stefanie Juchmes studies computer science at the University of Bonn. She came in touch with Xojo due to the work of her brother-in-law and got a junior developer position in early 2019 at Monkeybread Software. You may have also read her articles in Xojo Developer Magazine