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  6 2754 Cool? (+5)
📢 Listen (AI):

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

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14460 posts with rating 12470 , helped 650 times. Been with us since 2014 year.

Comments

metalMANiu 03 Dec 2024 22:25

. 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.... [Read more]

krzbor 04 Dec 2024 00:32

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. [Read more]

pier 04 Dec 2024 09:41

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... [Read more]

krzbor 04 Dec 2024 09:49

. 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? [Read more]

pier 04 Dec 2024 09:55

. The correspondence with reality is, as we know, varied but compared to other services it was rather not different. [Read more]

Duch__ 08 Dec 2024 21:18

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.... [Read more]

FAQ

TL;DR: Port 80 and a 4 KB receive buffer are enough to prototype OpenWeatherMap over plain C sockets. "You don't need external libraries at all," the tutorial argues, if you resolve DNS, send an HTTP/1.1 GET, skip \r\n\r\n, and parse JSON fields manually. This FAQ helps embedded and C developers fetch weather data with minimal Flash and no Arduino HTTP stack. [#21330951]

Why it matters: This thread shows how to cut library overhead on microcontrollers by replacing Arduino networking and JSON helpers with sockets, simple string parsing, and a portable workflow from Windows to LWIP targets.

Method Networking layer JSON handling Platform shown Main trade-off
Arduino HTTPClient High-level HTTP library ArduinoJson ESP32 Fast to build, larger software stack
Raw Winsock TCP socket + manual GET strstr + atof Windows PC Minimal dependencies, manual HTTP handling
Raw LWIP TCP socket + manual GET Manual parsing BK7231 / OBK Portable to embedded, blocking calls need a thread

Key insight: The core job is small: resolve api.openweathermap.org, connect by TCP, send one HTTP GET, then strip the HTTP header before reading JSON. On embedded targets, the biggest practical issue is not JSON but blocking socket calls.

Quick Facts

  • The Windows prototype resolves api.openweathermap.org, opens a SOCK_STREAM socket, and connects to port 80 before sending the weather request. [#21330951]
  • The sample desktop code allocates a 4096-byte buffer, while the BK7231/LWIP example receives in a 512-byte buffer inside a loop. [#21330951]
  • OpenWeatherMap returns temperature in Kelvin by default; adding units=metric changes the output to °C. [#21330951]
  • The BK7231 example creates a worker thread with an 8192-byte stack because connect, send, and recv are blocking operations there. [#21330951]
  • One real automation use from the thread lowers the thermostat by -1 °C when forecast cloud cover indicates sunny conditions, reducing overheating and gas use. [#21339253]

How do I fetch current weather from the OpenWeatherMap API using raw C sockets without Arduino HTTP libraries?

You fetch it with four low-level steps: 1. resolve api.openweathermap.org with gethostbyname; 2. open a SOCK_STREAM TCP socket and connect to port 80; 3. send an HTTP/1.1 GET containing /data/2.5/weather, your query, and Host; 4. read the response with recv and then parse the JSON body. The tutorial demonstrates this first on Windows with Winsock, then ports the same idea to LWIP on BK7231. [#21330951]

What is gethostbyname and how is it used to resolve api.openweathermap.org before sending an HTTP GET request?

gethostbyname resolves a domain name into an IP address before the TCP connection starts. In the example, the code calls gethostbyname("api.openweathermap.org"), reads the first address from h_addr_list, prints it with inet_ntoa, and then copies that IP into server.sin_addr for connect. That DNS step matters because http.GET() hides two operations: name resolution first, HTTP over TCP second. [#21330951]

Why does an OpenWeatherMap socket request return an HTTP header before the JSON body, and how do I skip it in C?

It returns an HTTP header first because a raw socket receives the full HTTP response, not just JSON. Skip it by finding the header terminator \r\n\r\n with strstr, then start parsing after that pointer. The tutorial shows const char *json_start = strstr(buffer, "\r\n\r\n"); because two consecutive line breaks mark the end of the header in HTTP/1.1. [#21330951]

How can I parse OpenWeatherMap JSON manually in C with strstr and atof instead of using cJSON or ArduinoJson?

You can parse simple numeric fields by searching for "key": and converting the following characters with atof. The sample function builds a search string such as "temp":, calls strstr, and returns a float; the author then extracts temp and humidity that way. This works for flat numeric values, but the post also warns the simplified code should be hardened against buffer overruns. [#21330951]

Why does OpenWeatherMap return temperature in Kelvin by default, and how do I request Celsius with units=metric?

OpenWeatherMap returns Kelvin because that is the API default when no units parameter is supplied. Request Celsius by appending units=metric to the query string, such as the same weather endpoint plus that extra parameter. The tutorial shows a result near 1 °C for New York after adding the metric units option. [#21330951]

What is LWIP and why is it useful for running OpenWeatherMap API requests on embedded platforms like BK7231?

"LWIP is a lightweight TCP/IP stack that provides sockets and DNS for embedded systems, with a small footprint and broad portability." It is useful here because the author wanted a cost-effective implementation with reduced Flash use and a path from PC testing to microcontroller deployment. The thread states the same socket approach used on Windows can run on BK7231 because LWIP exposes compatible networking primitives. [#21330951]

How can I port a Windows Winsock OpenWeatherMap example to a BK7231 microcontroller using LWIP sockets?

Port it by keeping the socket flow and replacing the platform layer. On BK7231, the example swaps Winsock headers for lwip/sockets.h, lwip/ip_addr.h, lwip/inet.h, and lwip/dns.h, then reuses gethostbyname, socket, connect, send, and recv. The receive loop reads up to 512 bytes per pass and closes the socket when recv stops returning positive data. [#21330951]

Why do connect, send, and recv block on BK7231/LWIP, and how should I move weather downloading into a separate thread?

They block because the LWIP socket calls in this example wait for network I/O to finish before returning. Move the download into a worker thread so the rest of the firmware stays responsive; the post shows rtos_create_thread creating an OWM thread with an 8192-byte stack and deleting it after the transfer ends. That design fits periodic weather polling much better than running blocking calls in the main path. [#21330951]

What's the difference between using Arduino HTTPClient and using raw sockets for OpenWeatherMap on a microcontroller?

Arduino HTTPClient hides DNS, TCP, request formatting, and much of the response handling, while raw sockets expose every step. The thread starts from an ESP32 sketch using HTTPClient and ArduinoJson, then replaces that stack with manual DNS, a hand-written GET request, header stripping, and strstr-based parsing. The raw-socket approach saves dependencies and can reduce Flash use, but you must handle errors and protocol details yourself. [#21330951]

How accurate are OpenWeatherMap forecasts over longer periods compared with Google Weather and other forecast services?

The thread reports mixed long-range accuracy rather than a clear winner. One participant said OpenWeather forecasts "didn't work very well" in earlier analysis and judged Google Weather more accurate, while another user who ran an OpenWeather display for years said its correspondence with reality was varied but not noticeably different from other services. That means the forum evidence is anecdotal and split, not a measured benchmark. [#21331900]

What could cause an ESP8266 weather display that used OpenWeatherMap a few years ago to stop working now?

A likely cause is that something in the API path changed after the device was built. One user wrote that an ESP8266 color-display weather device worked fine, then stopped a few months before the December 2024 post, and suspected OpenWeatherMap had changed something. In practical terms, old request formats, endpoints, or assumptions about the response can break even when the hardware still works. [#21332144]

How can cloud cover codes from OpenWeatherMap be used to control home heating or compare solar tracker performance with a fixed photovoltaic installation?

You can turn cloud-cover data into a control rule or a comparison input. One user already uses forecast cloud codes 800 and 801 as a sunny signal and lowers the thermostat by 1 °C so sunlight offsets gas heating and prevents room overheating. Another user suggests combining cloud data with sun azimuth and elevation to compare a solar tracker against a fixed PV installation on cloudy days. [#21339253]

Where can I get an API that provides the current sun azimuth and elevation for a specific location?

This thread does not name a specific API for sun azimuth and elevation. A participant asks for a source that would provide current azimuth and elevation for a given location, but no later post answers that request with a service name, endpoint, or example. The actionable fact here is the requirement itself: the desired API must return both values for a specific location. [#21331741]

What other useful APIs pair well with OpenWeatherMap for embedded dashboards, automation, or energy monitoring projects?

This thread identifies useful API categories rather than a confirmed list of services. The strongest pairing ideas are an astronomy-style API for current sun azimuth and elevation, plus weather cloud-cover data for PV analysis or home automation. Those combinations support displays, energy dashboards, and thermostat logic, especially when weather and solar geometry must be evaluated together at one location. [#21331741]

How do I import data from any external API into InfluxDB for logging and visualization?

This thread asks that question but does not provide an import procedure. One participant explicitly asks how to "import" any API into InfluxDB, and no later reply gives a pipeline, script, or database write example. The only solid takeaway is scope: the intended workflow is external API ingestion for logging and visualization, but the implementation is not covered in the discussion. [#21331741]
Generated by the language model.
%}