deckerego / ampule

A tiny HTTP server made for CircuitPython WiFi devices (like the ESP32)
MIT License
60 stars 10 forks source link

Non-blocking behaviour #28

Open wurls80 opened 12 months ago

wurls80 commented 12 months ago

I was trying ampule to replace adafruit httpserver as have been seeing some issues with reliability.

I got the code working to host the html page and respond to button presses on that page - so long as running in blocking mode. However I need to run in non-blocking mode (I was polling the server instance formed with httpserver, as the hardware checks for a physical button press too).

I can't get the non-blocking examples to work - whenever I try to connect to the IP address I get: "Error reading from socket [Errno 11] EAGAIN Error with request: need more than 0 values to unpack" And the device trying to connect to the IP address reports it can't connect and the connection is being reset. I see this same behaviour with my code as well when set socket.setblocking(False) too.

I've seen your advice in [(https://github.com/deckerego/ampule/pull/26)] however I can't determine how to manually override the setting on the accept() socket (I assume this is what I need to do). I've tried setting the timeout on the socket created (i.e. the listening socket) that the accept socket should then inherit the timeout from, but it doesn't make any difference to the behaviour.

Any ideas why I can't get your non-blocking example to work? I'm using a pi pico running circuitpython 8.1.0.

Many thanks.

deckerego commented 11 months ago

@wurls80 - apologies for the delay in replying, GitHub evidently no longer feels I should be notified for open issues...

Does the blocking example work? It sounds to me like you already have an open socket or something else using the listening network interface - so my guess is that the blocking code will fail in the same way that the non-blocking one will.

If you have some sample code to share, happy to take a look.

deckerego commented 9 months ago

@wurls80 following up again, let me know if you have any code samples to share. Thanks!

wurls80 commented 9 months ago

Hi John, Sorry for sluggish reply. I ended up getting some improvements with the other library I was using, so didn't follow up with ampule. As the hardware it's on is in use I haven't got another set to carry on trying it out with. When next on the machine with the code on I will have a look back and dig out some samples. Thanks for following up, appreciate it.

On Tue, 21 Nov 2023, 19:36 John Ellis, @.***> wrote:

@wurls80 https://github.com/wurls80 following up again, let me know if you have any code samples to share. Thanks!

— Reply to this email directly, view it on GitHub https://github.com/deckerego/ampule/issues/28#issuecomment-1821564089, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMQKFW6G7KKD4SB4SPTOUL3YFT7D3AVCNFSM6AAAAAA43GXB52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMRRGU3DIMBYHE . You are receiving this because you were mentioned.Message ID: @.***>

deckerego commented 9 months ago

Sounds good - will close this for now, but happy to re-open later!

szampardi commented 2 months ago

hi @deckerego, I have stumbled into the same issue and am able to reproduce and help you investigate the issue which is still occurring on latest stable CircuitPython 9.0.5 running on a pi pico w. Here's the code:

import time
import board
import busio
from digitalio import DigitalInOut

gate = DigitalInOut(board.GP0)
gate.switch_to_output(value=True)
def open_gate():
    gate.value = False
    time.sleep(0.05)
    gate.value= True
    print('gate opened')

bell = DigitalInOut(board.GP1)
bell.switch_to_output(value=True)
def ring_bell(t: float = 1.0):
    bell.value = False
    time.sleep(t)
    bell.value = True
    print('rang bell')

import wifi
import socketpool
import ampule

headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Access-Control-Allow-Origin": '*',
    "Access-Control-Allow-Methods": 'GET, POST',
    "Access-Control-Allow-Headers": 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
}

@ampule.route("/open_gate")
def api_open_gate(request):
    try:
        open_gate()
        return (200, headers, '{"ok":true}')
    except Exception as e:
        print(e)

@ampule.route("/ring_bell")
def api_ring_bell(request):
    t = 1.0
    if (request.params is None) or (request.params["t"] is None):
        ring_bell(t)
        return (200, headers, '{"ok":true}')
    try:
        t = float(request.params["t"])
    except Exception as e:
        print(e)
        return (502, headers, '{"ok":false}')
    try:
        ring_bell(t)
        return (200, headers, '{"ok":true}')
    except Exception as e:
        print(e)
        return (500, headers, '{"ok":false}')

pool = socketpool.SocketPool(wifi.radio)
socket = pool.socket()
socket.setsockopt(pool.SOL_SOCKET, pool.SO_REUSEADDR, 1)
socket.bind(['0.0.0.0', 8000])
socket.listen(1)
socket.setblocking(False)
print("HTTP API starting on port 8000")
while True:
    print('socket listening')
    ampule.listen(socket)
    time.sleep(1)

few things probably worth noting:

Regards,

deckerego commented 2 months ago

I would guess that the address re-use could cause the problem - it seems like you would have multiple resources competing for the same sockets. Do things work (until you have to soft reload) without those socket options?

szampardi commented 2 months ago

Ok! Will try over the weekend and let you know