Suppose you are building a small display that shows electricity prices, an installation that reacts to online information, or a sensor device that uploads readings. Getting the first successful web request is encouraging. Before handing the prototype to someone else, you need to know whether it can repeat that request while the rest of the product is running, and what it does when the reply is unusable.
This is a real integration problem. In a December 2023 MicroPython discussion, a developer fetching electricity prices for an ILI9341 display reported memory failures after initializing the graphical interface. A simpler request test worked, but combining the functions still failed. The discussion is a useful problem report, not a measured limit for every board or proof of a universal fix.
On our bench we ran a small HTTP client baseline: send a query, post a JSON value and inspect what comes back. Keeping that baseline separate helps distinguish a working connection from the additional behavior your product needs.
Start with an exchange you can understand
The setup used a W5500 Ethernet interface on a W5500-EVB-Pico (RP2040), MicroPython v1.23.0 and the urequests library. The network interface ran on SPI0 at 2 MHz, with GP19/GP16/GP18 for MOSI/MISO/clock, GP17 for chip select and GP20 for reset. Use the appropriate driver and connections for your actual board rather than treating the chip name as a complete configuration.
The Ethernet cable went to a network with a route to the online test service. The program tries DHCP and falls back to an example static configuration if that call raises an exception. That fallback is a bench convenience, not a guarantee of connectivity on a different network.
Once initialized, it requests http://httpbin.org/get?WIZnet=W5100S_W5500. The test service echoes the query parameters in a JSON response:
r = urequests.get(geturl + "?WIZnet=W5100S_W5500")
print("Request response code:", r.status_code)
print("Request response args:", r.json()["args"])
The next request posts {"WIZnet": "W5100S_W5500"} to /post, then prints the response's data field. These are test values. They let us compare what was sent with what the service returned without needing a sensor, a database or an account.
Both requests returned status 200, and the terminal showed the submitted values coming back. That supports a successful exchange in that run. It does not establish that a production service stored a reading, that an account accepted it, or that the same request will work indefinitely. A second recorded run, with different DHCP-assigned network settings, showed the same two successful responses.
The field names also belong to this particular test service. args and data are not mandatory fields in every HTTP response. When you replace httpbin with your own service, read its response format and decide which values the device actually needs.
Add the rest of the prototype before declaring the request finished
A blank-board example and an assembled application can have very different memory demands. A display interface, sensor buffers and a network response all compete for the device's available working memory. Test them together early, especially if the response contains a growing list rather than a single value.
The current MicroPython requests implementation reads and caches the response body when its JSON method is used. Parsing then creates Python objects from that content. This is a reason to examine response size; it is not a calculation of our test's memory use, and we have not pinned the urequests build we ran to that current source.
For an electricity-price display, you might need one day's values rather than an entire history. For a connected sign, you might need one short message rather than a full web page. Prefer a service response shaped for the device's actual job, and measure the combined application before deciding that more memory is the only solution.
Treat a reply as data that still needs checking
The test program immediately decodes JSON and accesses a field. That is easy to follow when the service returns the expected body. A product needs to decide what to do with an HTTP error, invalid JSON, a missing field or a value outside the range it can use.
For a display, that decision might be "keep the previous value, show when it was last updated, and mark it as stale." For an uploader, it might be "retain the reading until the service confirms acceptance." Choose the behavior from the user's task. A generic "connected" icon cannot explain whether a displayed number is current or whether a reading was saved.
Our test's if not r check after the POST is not a complete failure strategy: requests can raise exceptions before returning an object, and the code continued to access r after printing its warning. A timeout, a rejected request and a response with the wrong data should lead to different records, even if the interface uses one simple message for the user.
Give each request an end, and a reason to retry
Keep a response object only as long as needed, and close it even if processing fails. The current library provides close() to release its raw stream and cached body; its content-reading path already closes the underlying stream. So the absence of an explicit close in a simple test is not, by itself, proof that every successful JSON request leaks a socket. Check the installed library rather than guessing from its import name.
Likewise, choose and test a request timeout supported by the actual firmware and library. A socket timeout is not necessarily an end-to-end deadline covering lookup, connection and processing. The practical question for a trial is how long the device can wait before it must return control to its display, sensors or operator.
Retrying also depends on the operation. Fetching the current display value and submitting a new measurement are different jobs. If a POST reached the service but its reply was lost, blindly sending it again can create a duplicate unless the service can recognize the same submission. Agree on that behavior with whoever implements the receiving service.
Test the real service before the first user trial
Our baseline used plain HTTP and harmless echo values. It does not demonstrate a secure account connection. For a real service, verify HTTPS support and server-certificate validation in the exact firmware and library combination, together with how credentials are stored. Changing a URL prefix is not evidence that those checks are in place.
Use the GET and POST result as your baseline, then run a small set of deliberate trials with the full application:
| Condition | What the team needs to observe |
|---|---|
| Screen and sensors active | Requests finish without disrupting the other functions |
| Largest expected response | Parsing fits the available memory, with headroom for the rest of the application |
| Delayed or missing response | The agreed timeout behavior leaves the device usable |
| HTTP error or wrong JSON fields | Old data is not silently presented as a fresh result |
| Repeated uploads and a lost reply | The receiving service handles duplicates as intended |
| Extended repeated operation | Resource use and recovery remain acceptable for the trial |
We have not run these trials on this setup. Start with the normal exchange, then make one condition fail at a time. That produces a clearer handover than a single screenshot of status 200.