Micropython asynchronous function for garage door opener

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Post Reply
boadeletrius
Posts: 4
Joined: Fri Jun 18, 2021 2:03 am

Micropython asynchronous function for garage door opener

Post by boadeletrius » Fri Jun 18, 2021 3:11 am

I am trying to make a simple web server with the sole purpose of showing a web page with a button for opening the garage door and showing whether the door is open or closed.

Is there an easy way to make the pushbutton() function run asynchronously? I was looking at https://github.com/peterhinch/micropython-async but it seems somewhat overkill for my purpose.

Code: Select all

#import, pin out defs & html code removed for brevity

wlan = network.WLAN(network.STA_IF)

def pushbutton():
    relay.value(1)
    time.sleep(1)
    relay.value(0)
    return

def waitforconn(w):
    count=0
    while not w.isconnected() and count < 10:
        print('Reconnecting')
        time.sleep(5)
        count += 1
    return w.isconnected()

#Reconnect to wifi with 10 retries
def do_connect():
    maxtries=10
    if not wlan.active():
        wlan.active(True)
    wlan.connect()
    waitforconn(w=wlan)
    if not wlan.isconnected():
        raise NameError('WIFI failed')
    print('network config:', wlan.ifconfig())

def sendhtml(conn, response):
    conn.send(b'HTTP/1.1 200 OK\r\n')
    conn.send(b'Content-Type: text/html; encoding=utf8\r\nContent-Length: ')
    conn.send(str(len(response)))
    conn.send(b'\r\nConnection: close\r\n\r\n')
    conn.sendall(response)
    conn.close()
    return

#Start simple server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 80))
s.listen(5)
startrelay=time.time()
while True:
    try:
        if gc.mem_free() < 102000:
            gc.collect()
        if not wlan.isconnected():
            print("Not connected...")
            do_connect()
        conn, addr = s.accept()
        print('Got a connection from %s' % str(addr))
        request = conn.recv(1024)
        header=request[0:3].decode()
        if header.find('GET') >= 0:
            temp = [i.strip() for i in request.decode('utf-8').split('\r\n')]
            method, uri, proto=temp[0].split(' ')
            if 'HTTP' in proto:
                page_req=uri.split('?')
                get_arr=page_req[1].split('&') if (len(page_req) > 1) else []
                if uri.find("/pushbutton") >= 0:
                    now=time.time()
                    if ( now - startrelay > 4 ) :
                        print('Relay button push')
                        startrelay = now
                        pushbutton()
                    else :
                        print('Block relay button push')
                    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
                    conn.close()
                else:
                   response = html # contains html of page
                    size = len(html)
                    conn.send(b'HTTP/1.1 200 OK\r\n')
                    conn.send(b'Content-Type: text/html; encoding=utf8\r\nContent-Length: ')
                    conn.send(str(size))
                    conn.send(b'\r\nConnection: close\r\n\r\n')
                    # Send response
                    conn.sendall(html)
                    conn.close()
            else:
                response = 'Error: Not a http connection ({})'.format(proto)
                print(response)
                sendhtml(conn=conn, response="<html><head>Error</head><body><p>{}<p></body></html>".format(response))
              
        else:  
            # Send response
            response = 'Error: Not a GET request ({})'.format(request[0:3].decode())
            print(response)
            sendhtml(conn=conn, response="<html><head>Error</head><body><p>{}<p></body></html>".format(response))
            print(request.decode('utf-8'))

        
    except OSError as e:
        gc.collect()
        text = str(e)
        print('Connection closed: {}'.format(text))
        conn.close()
        if 'WIFI' in text:
            print('Do reboot')
            time.sleep(120)
            machine.reset()

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Micropython asynchronous function for garage door opener

Post by pythoncoder » Fri Jun 18, 2021 11:37 am

My Pushbutton class to which you refer is for interfacing a physical switch: it copes with debouncing, detecting long and double presses, and suchlike. There is a simpler Switch class which just debounces an on/off switch or button.

However your Pushbutton method is called from code, not from a physical switch. Making this asynchronous is simply a matter of writing

Code: Select all

import uasyncio as asyncio

async def pushbutton():
    relay.value(1)
    await asyncio.sleep(1)
    relay.value(0)
    return
and the function would be launched with

Code: Select all

asyncio.create_task(pushbutton())
If you have a physical switch detecting if the door is open, it can be interfaced with my Switch class. I assume your web server uses uasyncio so it can run concurrently.
Peter Hinch
Index to my micropython libraries.

boadeletrius
Posts: 4
Joined: Fri Jun 18, 2021 2:03 am

Re: Micropython asynchronous function for garage door opener

Post by boadeletrius » Fri Jun 18, 2021 5:38 pm

Thank you very much for the reply!

This is exactly what I was looking for. I have never used Python previously and a garage door opener seemed like a relatively easy project to get going with. I actually looked at uasyncio but I could not find a good example of how to use it for this type of situation. I am afraid my server is very much not asynchronous - it is just a single thread. This is why it seemed like a good idea not to lock things up with the pushbutton() function.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Micropython asynchronous function for garage door opener

Post by pythoncoder » Sat Jun 19, 2021 2:50 pm

Have you seen my uasyncio tutorial?
Peter Hinch
Index to my micropython libraries.

boadeletrius
Posts: 4
Joined: Fri Jun 18, 2021 2:03 am

Re: Micropython asynchronous function for garage door opener

Post by boadeletrius » Tue Jun 22, 2021 4:29 am

pythoncoder wrote:
Sat Jun 19, 2021 2:50 pm
Have you seen my uasyncio tutorial?
No, I have not. That looks excellent! I will have a look.

katesimon123
Posts: 15
Joined: Mon Jun 14, 2021 12:49 am

Re: Micropython asynchronous function for garage door opener

Post by katesimon123 » Wed Jun 23, 2021 12:59 pm

pythoncoder wrote:
Sat Jun 19, 2021 2:50 pm
Have you seen my uasyncio tutorial?
Nice one ..... I will give it a try.

Post Reply