
OpenWeatherMap is a service that offers, among other things, access to current weather information for a given position on a map. This data can be easily retrieved with a single GET query, although we will need an API key beforehand, which fortunately can be obtained for free. Here I will show how to send just such a GET query, but this time without external libraries.
This topic is essentially based on my earlier OWM presentation:
ESP32 and touchscreen display - tutorial part 4 - web weather, API, JSON .
There will be a key difference here, however, and that is that I won't be using Arduino libraries here, I'll try to run the whole thing in pure C on the simplest sockets, which should be available on most platforms - including Windows (Winsock). I will also implement JSON parsing in the simplest possible way, without external libraries.
The motivation behind the topic is simple - I wanted to run my weather download on a microcontroller in an efficient and cost-effective way, reducing the use of Flash memory as much as possible. Ultimately I want to run the code on sockets with LWIP , a solution available on many embedded systems.
Running on Windows .
So let's get started. The first rather positive observation for us is that the sockets are also on Windows, so we'll do the prototype normally on a PC... .
Let's recall the previous code:
Code: C / C++
Basically, we only need to implement this fragment:
Code: C / C++
And here is the first surprise - behind http.GET there is not one request, but two:
- first we have to turn the domain name api.openweathermap.org into an IP address (if we don't have that in the cache)
- then we need to send a GET request to this IP address, which is basically a short HTTP packet via TCP protocol.
To retrieve the IP for a domain name, the function gethostbyname is used, which is available both on Windows/Linux and, for example, in the popular LWIP network library.
Running sockets on Windows still requires a call to WSAStartup, which I have also included in the code:
Code: C / C++
Result:

We already have the IP, now it's time to send the GET request....
First we open a TCP socket (SOCK_STREAM) and establish a connection:
Code: C / C++
The above condition will result in an error if there is no TCP listening on the destination IP address on the specified port. Once the connection has been successfully established, we can send a GET request, i.e. successively an HTTP 1.1 compliant GET header along with the address of the resource of interest and then permission to close the connection after the transaction:
Code: C / C++
Ultimately, we'll assemble the resource address using sprintf (or better - snprintf, respecting the buffer size), but for now I've given a stiff one for a test.
Then all that was left was to receive the response and display it on the screen:
Code: C / C++
Of course, let's not forget to close the socket:
Code: C / C++
Result:

Now it is time to process the response. In the case of the off-the-shelf library-based method, we were getting the JSON file itself straight away, but here the response also contains an HTTP header. We have to skip it. The matter is simple - two passes to the next line in a row mark the end of it:
Code: C / C++
A screenshot, this time from the Visual Studio debugger:

Now it's time to extract the data from this JSON string....
Let's consider its structure (without artificial formatting):
{"coord":{"lon":-74.0059,"lat":40.7127},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":274.3,"feels_like":269.25,"temp_min":272.46,"temp_max":275.13,"pressure":1024,"humidity":71,"sea_level":1024,"grnd_level":1022},"visibility":10000,"wind":{"speed":5.81,"deg":311,"gust":5.81},"clouds":{"all":100},"dt":1733227560,"sys":{"type":1,"id":4610,"country":"US","sunrise":1733227402,"sunset":1733261345},"timezone":-18000,"id":5128581,"name":"New York","cod":200}
The whole thing looks very simple, the key from temperature ("temp") is taken in inverted commas, followed by a colon and its value. We can search for it in the character string using strstr , but before that we will add the inverted commas and this colon. The result can be converted from a string to a floating point number using atof :
Code: C / C++
Example of function use:
Code: C / C++
Result:

It works! Just why is this temperature value so strange?
Correct the temperature unit .
OpenWeatherMap sends the temperature in Kelvin by default. According to the documentation:
Quote:..
Temperature is available in Fahrenheit, Celsius and Kelvin units. Kelvin is used by default, with no need to use the units parameter in API calls.
For temperature in Fahrenheit, use "units=imperial".
For temperature in Celsius, use "units=metric".
You can find examples of API calls in the documentation for the service you are interested in.
To obtain results in °C, please add your choice of unit to the query:

Slightly better, is it really one degree in New York now?

Well, almost. Let's just say it's right.
Starting on the microcontroller (here for the BK7231 example) .
In the case of the BK7231 I mainly had to include other headers, here the sockets are provided by the aforementioned LWIP:
Code: C / C++
In addition, I had to put the whole thing in a thread, because the send, recv and even connect operations are blocking here:
Code: C / C++
The result (on my OBK platform):

The JSON is correctly received, it is now left to parse it as desired.
Summary .
As you can see, you don't need external libraries at all to be able to quickly and efficiently run the retrieval of the current weather situation from the OpenWeatherMap API. What's more, the whole thing can often be run normally on a Windows machine (or Linux there too - there are sockets compatible with my presentation) and then conveniently ported to the embedded platform we are using.... in my case the target platform was BK7231 with LWIP , but I think that not only BK this way can apply to.
Also, extracting measurements from JSON itself has proven to be straightforward. There are off-the-shelf, advanced libraries for this such as cJSON , but as you can see, they are not always necessarily needed....
Do you see any use for this API? Perhaps a display of some sort? .
PS: Obviously the code presented is simplified, it could be improved, e.g. to protect against buffer size overruns in the JSON search function, or it could be optimised, e.g. by creating the search string manually, as the sprintf used there at the moment is quite heavy... .
Cool? Ranking DIY Helpful post? Buy me a coffee.