An HTTP GET from an ESP32: fetch the weather
- 192parts on the bench
- 25boards running now
- 1.00xreal time, on every board
Most connected projects are a board asking a server for a small piece of data and doing something with it: the weather, the time, a setting. On an ESP32 in the Arduino world that is the HTTPClient library, and the pattern is always the same five steps: join the network, begin a request, GET it, read the body, end the request.
The circuit above is an ESP32-C3 running the built-in WiFi: fetch the weather example. Before anything else, the honest part: the network in Mokxi is simulated. There is no radio, no real internet and nothing leaves your browser tab. Four made-up names answer (time.mokxi, weather.mokxi, echo.mokxi and api.mokxi) and the board’s code is the code you would upload to a real ESP32. Press Run and the serial monitor shows the connect loop’s dots, then "IP address: 192.168.4.2", then every five seconds:
Each fetch prints "HTTP 200", then the body, {"location":"Mokxi","temperatureC":21.5,"humidity":48,"simulated":true}, and then the two numbers the sketch pulled out of it: "temperature: 21.5 C" and "humidity: 48 %".
The five steps
WiFi.begin(ssid, password) starts joining, and the sketch waits in a loop until WiFi.status() returns WL_CONNECTED. Then, for each request, it makes a WiFiClient and an HTTPClient, calls http.begin(client, url), and http.GET() sends the request and waits for the reply. GET returns the HTTP status code, 200 for success, and http.getString() returns the body. http.end() frees the connection.
Two details matter on real hardware. Check the code before using the body: a negative number means the request never completed (no network, a name that does not resolve, a timeout) and a 404 or 500 means the server answered with an error. And always call end(), even after a failure, so the connection and its buffers are released before the next request; a board that skips it can leak a little memory with every request until it stops working.
WiFiClient client;
HTTPClient http;
http.begin(client, "http://weather.mokxi/");
int code = http.GET();
if (code <= 0) {
Serial.print("request failed: ");
Serial.println(HTTPClient::errorToString(code));
http.end();
return;
}
Serial.print("HTTP ");
Serial.println(code);
String body = http.getString();
http.end();Pulling numbers out of the JSON
The reply is JSON, a small text format of names and values. This sketch finds the text "temperatureC", skips the quote, the colon and any spaces, and copies characters until the next comma or closing brace. That is enough for a flat reply you control, and it keeps the sketch readable. For anything nested or from a third-party service, use a real parser; on a physical board most people install the ArduinoJson library.
Open the Cloud tab beside Serial while it runs. It lists every request the board made with its status and body, and it has two fields for the numbers weather.mokxi answers with. Change the temperature to 30 and the next fetch, at most five seconds later, prints "temperature: 30 C". That is the same round trip a real board makes to a real weather service, with the server under your control.
When the request fails
The sketch deliberately asks for http://example.com/ once in setup(), and the serial monitor prints the reason it fails: no real internet, names under .mokxi only. A real board with no route to a server fails in the same place, at GET, with a negative code, and printing HTTPClient::errorToString(code) is the fastest way to see why.
To practice handling server errors, open the API lab example with the button below. It fetches http://api.mokxi/data, and the Cloud tab lets you choose the status code and the JSON it gets back. Set it to 404 or 500 and watch what your code does with a reply it did not expect. https:// addresses fail here on purpose, with a message saying TLS is not simulated; on a real ESP32 an https request needs WiFiClientSecure and the server’s certificate.
Habits worth building
Do not ask too often. A real weather service updates every few minutes and many limit how often one key can call them; every five seconds is fine against weather.mokxi and too often for most real services. Once a minute or less is a polite default.
Keep secrets out of shared code. A sketch with a WiFi password or an API key in it goes wherever you paste it. Put them in a separate header you do not share, and change the password on any network whose details ended up in a public post.
A blocked GET blocks everything. http.GET() waits for the reply, so while it waits the sketch is not reading buttons or updating a display. In Mokxi a request costs the sketch its simulated round trip, as it would on hardware, which is why a project that must stay responsive fetches rarely and does its other work with millis() rather than delay().
Questions
Which boards can run this?
In Mokxi, the boards with a radio on the real hardware: the ESP32-C3, the ESP32-C6, the classic ESP32 DevKit, the ESP8266 NodeMCU and the Raspberry Pi Pico W. The same example ships for each of them.
Can my sketch reach a real website from the simulator?
No. Only names under .mokxi resolve, and nothing leaves the browser tab. Anything else returns an error with one sentence explaining why.
What does HTTP code -1 mean on an ESP32?
The connection was refused or could not be made: usually no WiFi, a wrong address, or a server that is not there. HTTPClient::errorToString(code) prints the reason in words.
Should I use GET or POST?
GET to read data, POST to send it, for example a sensor reading to a logging service. HTTPClient has http.POST(body), and echo.mokxi answers a POST with the body you sent, so you can test it here.
Why does http.getString() come back empty?
Usually because the request failed and the code was negative, or the server answered with no body, as a 204 does. Print the status code first; if it is 200 and the body is still empty, print http.getSize() to see how many bytes the server said it was sending.
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.