sco1 / skyportal

A PyPortal based flight tracker
MIT License
1 stars 0 forks source link

Investigate async functionality #9

Closed sco1 closed 1 year ago

sco1 commented 1 year ago

Currently the main loop is just one task: checking OpenSky and then sleeping. I haven't checked yet but I'm assuming this sleep also blocks other functionality (e.g. touchscreen interaction), so will need to investigate how to accommodate this while keeping the refresh loop alive & on time.

sco1 commented 1 year ago

Trying to find an async way to make the web request to OpenSky seems like it will be a challenge, since the request library is not async & the asyncio library does not have run_in_executor. On average, a lot of time seems to be spent making this request (timeouts aren't uncommon), so unless it can be done in the background I think it's going to block any screen touching.

sco1 commented 1 year ago

Gathering thoughts here as I go along so I don't have to keep going back and finding them. One suggestion from Discord is to chunk the response so other tasks can be run:

import random
import board
import wifi
import socketpool
import ssl
import neopixel
import asyncio
import adafruit_requests

# Choose your own URL adventure...
URL = "https://anecdata.dev/ada/chunked3/"

async def iter(req):
    while True:
        print(f"\nGET {URL}")
        with req.get(URL) as resp:
            print(resp.status_code, resp.reason.decode(), resp.headers)
            for c in resp.iter_content():
                print(f"{c.decode()}", end="")
                await asyncio.sleep(0)

async def pixel():
    with neopixel.NeoPixel(board.NEOPIXEL, 1) as pixels:
        while True:
            pixels.fill(random.randrange(0, 256*256*256))
            await asyncio.sleep(0.1)

async def main():
    iter_task = asyncio.create_task(iter(req))
    neo_task = asyncio.create_task(pixel())
    await asyncio.gather(iter_task, neo_task)

pool = socketpool.SocketPool(wifi.radio)
req = adafruit_requests.Session(pool, ssl.create_default_context())

asyncio.run(main())

This would need some adjusting since the PyPortal doesn't have wifi or socketpool modules. The PyPortal initializes a legacy session that takes care of this part of the setup. However, I don't think that chunking the response is going to be helpful here since the primary issue is the call to OpenSky timing out.

I'm thinking what might have to be done is replace the session itself. There is a PR drafted for an async session that may be able to be worked on to fit the bill.