-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Memory Error when sending a get_request AFTER using http server with AP on CP9 beta 2 #8968
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Please post the complete example. This one has no imports. I wasn't able to reproduce it because they are missing. |
Could you retry with the latest ConnectionManager library? Thanks. adafruit/Adafruit_CircuitPython_ConnectionManager#16 has fixed several other issues that seem similar. |
I've run into this problem on a similar board (unexpected maker FeatherS2) CircuitPython version
Here's a complete code snippet that reproduces the error. It is based on the code above. I'm using the latest versions of adafruit_connection_manager, adafruit_requests and adafruit_httpserver. Also worth mentioning. I have the CircuitPython Web Workflow Code Editor enabled. So the code below isn't initializing wifi. To get the error to happen hit the webserver running on the esp32 at "/". import wifi
import adafruit_connection_manager
import adafruit_requests
from adafruit_httpserver import Server, Request, Response, GET
# print(f"Connecting to {os.getenv("CIRCUITPY_WIFI_SSID")}...")
# wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
# print(f"Connected to {os.getenv("CIRCUITPY_WIFI_SSID")}")
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
### Starting the Server
server = Server(pool, debug=True)
@server.route("/")
def base(request: Request):
url = "https://www.adafruit.com/api/quotes.php"
# pings adafruit quotes
print("Fetching text from %s" % url)
# gets the quote from adafruit quotes
response = requests.get(url)
print("-" * 40)
# prints the response to the REPL
print("Headers: ", response.headers)
print("-" * 40)
response.close()
return Response(request, "Hello from the CircuitPython HTTP Server!")
server.serve_forever(str(wifi.radio.ipv4_address)) Here's the error:
|
The requests-module (to be specific: the |
I tried to recreate the original post code, but with latest CircuitPython and libraries, and use of ConnectionManager (due especially to multiple uses of sockets). I'm not sure why the partial original gets a memory exception, but this version looks fine with regard to use of RAM:
code.py...import time
time.sleep(3) # wait for serial
import gc
print(f"code start {gc.mem_free()=}")
import os
import wifi
import mdns
import socketpool
import adafruit_requests
import adafruit_connection_manager
from adafruit_httpserver import Server, Request, Response
print(f"after imports {gc.mem_free()=}")
# start wifi Station
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
# start wifi AP
wifi.radio.start_ap("test", "passw0rd")
print(f"after AP {gc.mem_free()=}")
# start mDNS
mdns_server = mdns.Server(wifi.radio)
mdns_server.hostname = "MDNS_HOSTNAME"
mdns_server.advertise_service(service_type="_http", protocol="_tcp", port=80)
print(f"after mDNS {gc.mem_free()=}")
# init socket pool
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
print(f"{gc.mem_free()=}")
# init Requests
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
print(f" after requests {gc.mem_free()=}")
# start HTTP Server
http_server = Server(pool, "/static", debug=True)
print(f"after HTTP Server init {gc.mem_free()=}")
@http_server.route("/")
def base(request: Request):
return Response(request, "Hello from the CircuitPython HTTP Server!")
http_server.start(str(wifi.radio.ipv4_address_ap), 80)
print(f"after HTTP server start {gc.mem_free()=}")
# stop everything
http_server.stop()
mdns_server.deinit()
wifi.radio.stop_ap()
print(f"after stop {gc.mem_free()=}")
### Then using requests (connected to Wi-Fi with internet connection)
try:
url = "https://www.adafruit.com/api/quotes.php"
# pings adafruit quotes
print("Fetching text from %s" % url)
# gets the quote from adafruit quotes
response = requests.get(url)
print("-" * 40)
# prints the response to the REPL
print("Headers: ", response.headers)
print("-" * 40)
response.close()
except Exception as e:
print("Error:\n", str(e))
print(f"after stop {gc.mem_free()=}") It's possible that |
Re: @bablokb Re: @anecdata
I do wonder if this is somehow PSRAM related. The UM FeatherS2 has 8mb there. Maybe I'll try running this with the CircuitPython code editor disabled. That might save some ram. |
@chadj I haven't reproduced that (yet?). I added some code in the middle to allow clients to connect (my phone, connected to the S2 AP, then connecting to the HTTP server by IP address) and that worked too in brief testing. code.py...import time
time.sleep(3) # wait for serial
import gc
print(f"code start {gc.mem_free()=}")
import os
import wifi
import mdns
import socketpool
import adafruit_requests
import adafruit_connection_manager
from adafruit_httpserver import Server, Request, Response
print(f"after imports {gc.mem_free()=}")
# start wifi Station
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
# start wifi AP
wifi.radio.start_ap("test", "passw0rd")
print(f"after AP {gc.mem_free()=}")
# start mDNS
mdns_server = mdns.Server(wifi.radio)
mdns_server.hostname = "MDNS_HOSTNAME"
mdns_server.advertise_service(service_type="_http", protocol="_tcp", port=80)
print(f"after mDNS {gc.mem_free()=}")
# init socket pool
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
print(f"{gc.mem_free()=}")
# init Requests
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
print(f" after requests {gc.mem_free()=}")
# start HTTP Server
http_server = Server(pool, "/static", debug=True)
print(f"after HTTP Server init {gc.mem_free()=}")
@http_server.route("/")
def base(request: Request):
return Response(request, "Hello from the CircuitPython HTTP Server!")
http_server.start(str(wifi.radio.ipv4_address_ap), 80)
print(f"after HTTP server start {gc.mem_free()=}")
print(f"waiting for connection from HTTP client...")
start = time.monotonic_ns()
while time.monotonic_ns() - start < 60_000_000_000:
http_server.poll()
# stop everything
http_server.stop()
mdns_server.deinit()
wifi.radio.stop_ap()
print(f"after stop {gc.mem_free()=}")
### Then using requests (connected to Wi-Fi with internet connection)
try:
url = "https://www.adafruit.com/api/quotes.php"
# pings adafruit quotes
print("Fetching text from %s" % url)
# gets the quote from adafruit quotes
response = requests.get(url)
print("-" * 40)
# prints the response to the REPL
print("Headers: ", response.headers)
print("-" * 40)
response.close()
except Exception as e:
print("Error:\n", str(e))
print(f"after stop {gc.mem_free()=}") full output...
It would be very odd if more PSRAM triggered the issue. P.S. Also seems OK if I access the HTTP Server using its mDNS name. |
239 if is_ssl:
240 socket = ssl_context.wrap_socket(socket, server_hostname=host) fwiw the failing call is to We take the default esp-idf configuration and restrict allocation of mbedtls data to internal SRAM:
It would be interesting to see if this failure went away with the setting MBEDTLS_EXTERNAL_MEM_ALLOC, with some reduction in security (i.e., if someone takes apart your powered device they can read out some key data from the PSRAM chip!). In CircuitPython we probably don't care about such a scenario. |
@jepler Surprise twist though. I flashed back to stock 9.2.1 and tried my code again. And surprise, my code worked! I verified boot_out.txt. I'm running stock 9.2.1 from 2024-11-20 and it executes now without throwing a MemoryError. So there might not be an issue to begin with. When I initially ran into this issue and then did subsequent testing I never power cycled the device. I'm wondering if a power cycle cleared up the problem. I'm still trying to get the MemoryError to throw. I'll update this thread if I'm able to figure out how to duplicate the problem |
Ok On stock 9.2.1 it fails. With the patch from @jepler it works. So the change to allow mbedtls psram allocation solves this problem. import time
time.sleep(5) # wait for serial
import gc
print(f"code start {gc.mem_free()=}")
import os
import wifi
import mdns
import socketpool
import adafruit_requests
import adafruit_connection_manager
from adafruit_httpserver import Server, Request, Response
import board
import math
import audiocore
import audiobusio
import array
print(f"after imports {gc.mem_free()=}")
# start wifi Station
#wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
wifi.radio.connect("<set ap>", "<set password>")
# start wifi AP
wifi.radio.start_ap("test", "passw0rd")
print(f"after AP {gc.mem_free()=}")
# start mDNS
mdns_server = mdns.Server(wifi.radio)
mdns_server.hostname = "MDNS_HOSTNAME"
mdns_server.advertise_service(service_type="_http", protocol="_tcp", port=5000)
print(f"after mDNS {gc.mem_free()=}")
# init socket pool
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
print(f"{gc.mem_free()=}")
# init Requests
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
print(f" after requests {gc.mem_free()=}")
# start HTTP Server
http_server = Server(pool, "/static", debug=True)
print(f"after HTTP Server init {gc.mem_free()=}")
@http_server.route("/")
def base(request: Request):
return Response(request, "Hello from the CircuitPython HTTP Server!")
http_server.start(str(wifi.radio.ipv4_address_ap), 5000)
print(f"after HTTP server start {gc.mem_free()=}")
sample_rate = 8000
tone_volume = .1 # Increase or decrease this to adjust the volume of the tone.
frequency = 440 # Set this to the Hz of the tone you want to generate.
length = sample_rate // frequency # One freqency period
sine_wave = array.array("H", [0] * length)
for i in range(length):
sine_wave[i] = int((math.sin(math.pi * 2 * frequency * i / sample_rate) *
tone_volume + 1) * (2 ** 15 - 1))
audio = audiobusio.I2SOut(board.D1, board.D0, board.D9)
sine_wave_sample = audiocore.RawSample(sine_wave, sample_rate=sample_rate)
audio.play(sine_wave_sample, loop=False)
print(f"after audio init {gc.mem_free()=}")
# stop everything
http_server.stop()
mdns_server.deinit()
wifi.radio.stop_ap()
print(f"after stop {gc.mem_free()=}")
### Then using requests (connected to Wi-Fi with internet connection)
try:
url = "https://www.adafruit.com/api/quotes.php"
# pings adafruit quotes
print("Fetching text from %s" % url)
# gets the quote from adafruit quotes
response = requests.get(url)
print("-" * 40)
# prints the response to the REPL
print("Headers: ", response.headers)
print("-" * 40)
response.close()
except Exception as e:
print("Error:\n", str(e), e.__class__.__name__)
print(f"after stop {gc.mem_free()=}") |
CircuitPython version
Code/REPL
Behavior
Description
It seems that there is a MemoryError when doing a get request after using the socket (?) for an http server. I'm utilizing the server along with the AP. When Im not starting the server beforehand, the requests work fine. Not sure what the problem is here. Under previous version 8.x this seems to have worked fine on the ESP32-S2.
Additional information
No response
The text was updated successfully, but these errors were encountered: