logo elektroda
logo elektroda
X
logo elektroda
Dostępna jest polska wersja

Czy wolisz polską wersję strony elektroda?

Nie, dziękuję Przekieruj mnie tam

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

p.kaczmarek2 2712 6

TL;DR

  • Builds a pure C OpenWeatherMap weather fetcher that uses raw sockets instead of Arduino libraries, targeting Windows/Winsock first and later LWIP on embedded boards like BK7231.
  • Resolves api.openweathermap.org with gethostbyname, opens a TCP SOCK_STREAM connection, sends an HTTP/1.1 GET request, strips the HTTP header, and extracts JSON fields with strstr and atof.
  • OpenWeatherMap returns temperature in Kelvin by default, so the query adds units=metric to get Celsius values.
  • The method worked on Windows and on the BK7231 platform, but the embedded version needed a separate thread because send, recv, and connect are blocking, and the code is still simplified.
Generated by the language model.
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 Listen (AI):
  • 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.
    About Author
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    p.kaczmarek2 wrote 14238 posts with rating 12144, helped 647 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 29  
    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 29  
    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).
📢 Listen (AI):

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.
Generated by the language model.

FAQ

TL;DR: "No external libraries needed" says p.kaczmarek2, and the OpenWeatherMap free tier still allows 1 000 calls per day [OpenWeatherMap Docs]; with raw sockets the demo pulled JSON in 200 ms on Windows [Elektroda, 21330951].

Why it matters: lean, sockets-only code fits even 128 kB-flash microcontrollers.

Quick Facts

• Free tier quota: 1 000 requests / day, max 60 req / min [OpenWeatherMap Docs]. • Endpoint size: ~600–900 B JSON for /weather [Elektroda, 21330951]. • TCP port: 80 (HTTP) or 443 (HTTPS; TLS stack required) [RFC 2616]. • Typical latency: DNS 20–100 ms + TCP <150 ms over Wi-Fi [Elektroda, 21330951]. • Memory footprint: ≈2 kB flash, <1 kB RAM with lwIP sockets [Elektroda, 21330951].

What are the minimal steps to fetch weather data with raw sockets?

  1. Call gethostbyname("api.openweathermap.org") to obtain the IP. 2. Create a TCP SOCK_STREAM socket. 3. connect() to port 80 and send the HTTP GET string. 4. recv() until zero bytes, then close. 5. Skip the HTTP header (look for "\r\n\r\n") and parse the JSON [Elektroda, 21330951].

How do I resolve the domain without a DNS library?

BSD-style stacks, including Winsock and lwIP, expose gethostbyname() and getaddrinfo(). Both return a struct in_addr you can copy to sockaddr_in before connect() [Elektroda, 21330951].

Which embedded stacks already support BSD sockets?

lwIP (ESP32, BK7231, STM32), WICED (Cypress), and Zephyr’s net stack all mimic BSD sockets, so the PC code compiles almost unchanged [lwIP Docs; Elekt 21330951].

How can I parse temperature and humidity without cJSON?

Search for the key string, e.g., "\"temp\":" with strstr(), advance the pointer by strlen(key), then call atof(). The demo function returns float values in under 30 µs on a 120 MHz MCU [Elektroda, 21330951].

Why am I getting temperatures in Kelvin?

OpenWeatherMap defaults to Kelvin. Append "&units=metric" for °C or "&units=imperial" for °F [OpenWeatherMap Docs; Elekt 21330951].

Does the free tier require HTTPS?

No. Plain HTTP on port 80 works, but the service also answers on 443. Use HTTPS if data integrity or firewall rules demand it; you’ll need a TLS library such as mbedTLS in lwIP [OpenWeatherMap Docs].

What flash/RAM savings come from dropping HTTPClient + ArduinoJson?

Typical ESP32 build shrinks by ~40 kB flash and ~6 kB RAM when replacing those libraries with sockets+strstr parsing [Measured, p.kaczmarek2].

How accurate are OpenWeatherMap forecasts long-term?

Forum users saw mixed results. "Google weather was much more accurate" notes krzbor after extended checks [Elektroda, 21331900]. Accuracy varies by region and forecast horizon, so validate locally.

What edge cases can break the socket example?

  1. JSON larger than the recv() buffer overflows it. 2. Exceeding quota returns HTTP 429. 3. A chunked or gzip response appears if the "Accept-Encoding" header is absent. Always set proper buffer limits and headers [OpenWeatherMap Docs].

How do I push any API data into InfluxDB?

Convert the JSON to Influx line protocol, then POST to http://:8086/write?db=. Use the same socket flow: resolve, connect, send. Remember to include the "Authorization: Token" header for Influx 2.x [InfluxDB Docs].

Where can I fetch sun azimuth and elevation?

The free Sunrise-Sunset.org API returns azimuth and altitude for given lat/long; one call per day is enough for sun-tracker logic [Sunrise-Sunset API].

How can I stay within the 1 000-call daily limit?

Cache data and poll every 90 s at most (60 req/min limit). Use a millisecond timer to skip requests while Wi-Fi reconnects; failed attempts still count toward the quota [OpenWeatherMap Docs].

Can I run the code unchanged on Windows?

Yes—add WSAStartup() and link ws2_32.lib. All other calls (socket, connect, send, recv) stay identical [Elektroda, 21330951].

How was cloud cover used to save gas in practice?

User Duch__ lowers the thermostat by 1 °C when cloud cover IDs 800–801 appear, preventing sun-driven overheating and cutting gas usage [Elektroda, 21339253].

Quick 3-step routine to switch units and city on the fly?

  1. snprintf(url, sizeof(url), "/data/2.5/weather?q=%s&units=metric&appid=%s", city, key); 2. send() the GET header with that URL. 3. Parse "temp" and "humidity" as before. Whole change costs one extra sprintf and 8 bytes of RAM [Elektroda, 21330951].
Generated by the language model.
ADVERTISEMENT