Stopping the code from halting when using a function that takes a long time

77 Views Asked by At

I'm trying to use Adafruit IO connected to a Pico W as a remote control for some Neopixels. It takes about 0.25 seconds to read the value, which ruins the LED patterns that require a delay. Not using time.sleep for this delay wouldn't change anything - as the reading of the feed halts the code anyway. I've tried reading it in the loop, in a function, in an asynchronous function with asyncio, but all these have not fixed the problem - they've changed nothing. I'm probably doing the asyncio part wrong, but I don't know and can't find good examples.

Does anyone know how to make the reading happen faster, or happen in the background.

Here's the code I'm using with asyncio:

import os
import ssl
import wifi
import socketpool
import microcontroller
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError

wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'),
                   os.getenv('CIRCUITPY_WIFI_PASSWORD'))
aio_username = os.getenv('aio_username')
aio_key = os.getenv('aio_key')

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(aio_username, aio_key, requests)
print("connected to io")

statefeed = io.get_feed(<insert feed here>)

async def statefunc():
    global state
    state = io.receive_data(statefeed["key"])["value"] # This is the part that takes 0.25 seconds.
    
async def main():
    asyncstate = asyncio.create_task(statefunc())
    await asyncio.gather(asyncstate)

while True:
    asyncio.run(main())

    if state == "0":
        # do a thing

    if state == "1":
       # do another thing```
1

There are 1 best solutions below

1
On

To address the problem, you can use a different approach without relying on asyncio, as microcontrollers don't support truly concurrent threads.

Here's an approach using a timer-based check to poll the Adafruit IO less frequently, allowing your LED patterns to run smoothly:

Use a Timer for Polling: Instead of constantly polling Adafruit IO in every loop iteration, you can set up a timer. When the timer expires, you poll Adafruit IO, update the state, and reset the timer.

Here's how you can structure the code:

import os
import ssl
import wifi
import socketpool
import microcontroller
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
import time

# Connect to WiFi
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'),
                   os.getenv('CIRCUITPY_WIFI_PASSWORD'))

# Adafruit IO credentials
aio_username = os.getenv('aio_username')
aio_key = os.getenv('aio_key')

# Set up socket pool and HTTP session for Adafruit IO
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(aio_username, aio_key, requests)

print("Connected to Adafruit IO")

# Fetch the feed
statefeed = io.get_feed(<insert feed here>)

# Polling configuration
POLL_INTERVAL = 5  # Poll every 5 seconds
last_poll_time = time.monotonic()
state = None  # Initial state

def update_state():
    """Update the state by polling Adafruit IO."""
    global state
    try:
        state = io.receive_data(statefeed["key"])["value"]
    except AdafruitIO_RequestError:
        print("Error fetching state")
        state = None

while True:
    current_time = time.monotonic()
    
    # If the poll interval has passed, update the state
    if current_time - last_poll_time >= POLL_INTERVAL:
        update_state()
        last_poll_time = current_time

    # Check the state and perform the corresponding action
    if state == "0":
        # do a thing (e.g., light up LEDs in a certain pattern)
        pass
    elif state == "1":
        # do another thing (e.g., light up LEDs in a different pattern)
        pass

    # Run your LED patterns or other non-blocking code here
    # ...

Replace "insert feed here" with the appropriate feed name or ID. This code will poll Adafruit IO every 5 seconds to update the state. In between these polling intervals, you can execute your LED patterns or other non-blocking tasks without being interrupted by the IO fetch operation. Adjust the POLL_INTERVAL as needed.