logo elektroda
logo elektroda
X
logo elektroda

How to get the weather from the OpenWeatherMap API on sockets alone? API tutorial, JSON, C

p.kaczmarek2 2127 6
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
  • OpenWeather logo with an orange sun and text. .
    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++
    Log in, to see the code
    .
    Basically, we only need to implement this fragment:
    Code: C / C++
    Log in, to see the code
    .
    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++
    Log in, to see the code
    .
    Result:
    Console screen showing IP address 141.95.47.140. .
    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++
    Log in, to see the code
    .
    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++
    Log in, to see the code
    .
    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++
    Log in, to see the code
    .
    Of course, let's not forget to close the socket:
    Code: C / C++
    Log in, to see the code
    .
    Result:
    Windows console with weather information from OpenWeatherMap .

    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++
    Log in, to see the code
    .
    A screenshot, this time from the Visual Studio debugger:
    Screenshot of C code with 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++
    Log in, to see the code
    .
    Example of function use:
    Code: C / C++
    Log in, to see the code
    .
    Result:
    Screenshot showing weather data from an API, including temperature and humidity for New York in JSON format. .
    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:
    Screenshot showing JSON code and data processing result. .
    Slightly better, is it really one degree in New York now?
    Current weather forecast for New York, showing temperature, chance of precipitation, and wind speed. .
    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++
    Log in, to see the code
    .
    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++
    Log in, to see the code
    .
    The result (on my OBK platform):
    Screenshot displaying the results of an application retrieving weather data from OpenWeatherMap using an HTTP request. .
    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.
    Do you have a problem with Arduino? Ask question. Visit our forum Arduino.
    About Author
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    p.kaczmarek2 wrote 11858 posts with rating 9941, helped 566 times. Been with us since 2014 year.
  • ADVERTISEMENT
  • #2 21331741
    metalMANiu
    Level 21  
    p.kaczmarek2 wrote:
    Do you see any use for this API? Maybe a display of some kind?
    .
    I have an idea.
    With information about the current cloud cover, one could compare the performance of a photovoltaic installation having actuators that follow the sun to a classic stationary installation. It would be interesting to make such a comparison on cloudy days.
    For this you would need another API giving information about the current azimuth and elevation of the sun at a specific location.
    Where to get such data from?
    Do you perhaps have a collection of other useful sources with useful APIs?
    How to "import" any API into influxDB?
  • ADVERTISEMENT
  • #3 21331900
    krzbor
    Level 27  
    Has anyone tested OpenWeather's weather forecasts over an extended period? As I used to analyse it, it didn't work very well. In any case, Google weather was much more accurate.
  • ADVERTISEMENT
  • #4 21332144
    pier
    Level 24  
    A couple of years ago I made a weatherman with a colour display and esp8266 that downloaded data from OpenWeatherMap. It worked fine but a few months ago it stopped, not sure why but I suspect they changed something. I lack the time to look into it.
  • ADVERTISEMENT
  • #5 21332157
    krzbor
    Level 27  
    pier wrote:
    Several years ago I made a weatherman with a colour display and esp8266 which took data from OpenWeatherMap
    .
    I see you have been testing this for an extended period of time. What was the verifiability of the weather forecast? Was it different from other forecasts?
  • #6 21332169
    pier
    Level 24  
    krzbor wrote:
    pier wrote:
    Some years ago I made a weatherman with a colour display and esp8266 that took data from OpenWeatherMap
    .
    I see you have been testing this for an extended period of time. What was the verifiability of the weather forecast? Was it different from other forecasts?
    .

    The correspondence with reality is, as we know, varied but compared to other services it was rather not different.
  • #7 21339253
    Duch__
    Level 31  
    I only download information about the level of cloud cover based on the weather forecast from openweathermap. If it is sunny(ID 800 and 801), I lower the temperature in the house by -1 deg C on the thermostat. This causes the gas furnace to heat less and the temperature in the house to rise from the sunshine. This prevents overheating in the rooms and reduces gas consumption.

    As for not decrypting the json response with libraries, I used to struggle with AIRLY. There, the response is mercilessly long, the data is a lot. After receiving a certain piece of data (I counted quotes), I would break the connection and add curly brackets to make the whole json look correct, and only then proceed to decrypt it manually (counting quotes).

Topic summary

The discussion revolves around retrieving weather data from the OpenWeatherMap API using pure C and sockets, without relying on external libraries. The author aims to implement a simple GET request to access current weather information, emphasizing the need for an API key. Participants share experiences with OpenWeatherMap's accuracy compared to other services, such as Google Weather, and discuss the challenges of parsing JSON responses manually. Suggestions for additional APIs, such as those providing solar position data, are also mentioned, along with practical applications like optimizing thermostat settings based on cloud cover data.
Summary generated by the language model.
ADVERTISEMENT