uasyncio - How detect the end task in another task.

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.
Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Mon Aug 31, 2020 1:55 pm

A gotcha thanks! Yeah, it's not suuuper important. Another question - can you write a function that let's you toggle between two (or more functions) via button push? I.e. first function runs, button press, second function runs, button press, first function runs again.

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

Re: uasyncio - How detect the end task in another task.

Post by pythoncoder » Mon Aug 31, 2020 2:13 pm

There are plenty of ways to do this

Code: Select all

toggle = False
def foo():
    global toggle
    if toggle:
        print('toggle was True')
    else:
        print('toggle was False')
    toggle = not toggle
Result:

Code: Select all

>>> foo()
toggle was False
>>> foo()
toggle was True
>>> foo()
toggle was False
>>> 
Clearly foo() could call other functions if that's what you want.
Peter Hinch

Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Mon Aug 31, 2020 10:33 pm

Ah nice! Thanks, Pete!

Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Fri Sep 04, 2020 8:09 pm

Hi Pete,

Follow up to the toggle function. I'm not trying to get carried away, but this keeps popping up in my mind ;)

Do you think it's possible to use the toggle function you showed me in the async main function to switch between two asynchronous tasks while all others keep doing their thing?

Toggle function

Code: Select all


toggle = False
def foo():
    global toggle
    if toggle:
        uasyncio.create_task(my_class.blink())
    else:
        uasyncio.create_task(my_class.temp())
    toggle = not toggle
It would be called by switch.press_func, or double/long press alternatively

Code: Select all

async def main():
    set_global_exception()  # Debug aid
    my_class = tempReader(led, sensor, oled, sw, enc, lcd)  # Constructor might create tasks
    switch = my_class.sw#Pushbutton(sw, suppress = True)
    switch.press_func(foo, ()) # this is where the toggle would get called
    #uasyncio.create_task(my_class.blink()) # Or you might do this
    #uasyncio.create_task(my_class.temp())
    uasyncio.create_task(my_class.encoder_loop(enc))
    uasyncio.create_task(my_class.show())
    uasyncio.create_task(my_class.show_lcd())
    await my_class.cancel() # Non-terminating method
try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()  # Clear retained state
Please let me know your thoughts. I imagine that could be one way to switch between two display functions.

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

Re: uasyncio - How detect the end task in another task.

Post by pythoncoder » Sat Sep 05, 2020 5:52 am

As written each time you press the switch you are creating a new task instance. I think you need to cancel the running task before creating a new one.
Peter Hinch

Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Sat Sep 05, 2020 11:12 am

Ah gotcha. That makes sense. Is there a uasyncio function that lets me cancel a specific task? In this case it would just be the two in the toggle, right? A la, cancel 1 create 2, and vice versa.

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

Re: uasyncio - How detect the end task in another task.

Post by pythoncoder » Sun Sep 06, 2020 9:43 am

Peter Hinch

Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Sun Sep 06, 2020 3:40 pm

Hey, thanks - found it!

I tried a simple example

Code: Select all

from machine import Pin, Timer, I2C
import dht
import time
import uasyncio
import gc
from aswitch import Switch, Pushbutton

led2 = Pin(19, Pin.OUT) #green
led4 = Pin(33, Pin.OUT) #red

sw = Pin(18, Pin.IN, Pin.PULL_UP)

switch = Pushbutton(sw, suppress = True)


async def blink2(led):
    while True:
      led.on()
      await uasyncio.sleep_ms(100)
      led.off()
      await uasyncio.sleep_ms(100)
      
async def blink3(led):
    while True:
      led.on()
      await uasyncio.sleep_ms(200)
      led.off()
      await uasyncio.sleep_ms(200)
      
async def nothing():
  await uasyncio.sleep_ms(2)
 
 
toggle = False
def foo():
    global toggle
    if toggle:
      blink2_task.cancel()
    else:
        blink2_task = uasyncio.create_task(blink2(led2))
    toggle = not toggle

async def cancel():
    await uasyncio.sleep(60)

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

async def main():
    set_global_exception()  # Debug aid
    switch.release_func(foo(), ())
    #other async tasks...
    await cancel() # Non-terminating method

try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()  # Clear retained state

gc.collect()
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
However, pushing the button doesn't actually cancel blink2_task = uasyncio.create_task(blink2(led2)). What am I missing here?

If I wanted to alternate tasks, I assume they would have to be in the foo() function and cancel each other. I have tried that too, but wanted to know if they have to defined before the actual function body? I got assigned but not used errors, e.g.

Code: Select all


toggle = False
def foo():
    global toggle
    if toggle:
      blink2_task.cancel()
      blink3_task = uasyncio.create_task(blink3(led4))
    else:
        blink2_task = uasyncio.create_task(blink2(led2))
        blink3_task.cancel()
    toggle = not toggle

As always, greatly appreciate the help :)

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

Re: uasyncio - How detect the end task in another task.

Post by pythoncoder » Mon Sep 07, 2020 6:19 am

Can I respectfully suggest you find an online course or buy a book on Python programming? You need to learn about Python scoping rules and the lifetime of variables.

The reason I declared toggle as global is that functions forget variables declared in their body when they terminate. The global declaration enables the named variable to persist.
Peter Hinch

Primesty
Posts: 38
Joined: Sun Jun 28, 2020 11:06 pm

Re: uasyncio - How detect the end task in another task.

Post by Primesty » Tue Sep 08, 2020 2:28 pm

Hey Pete, you sure can! I read up on it and figured it out with the input on the global stuff from you.

I got it to work like this:

Code: Select all


def foo():
    global toggle
    global blink2_task
    global blink3_task

    if toggle:
       blink2_task.cancel()
       blink3_task = uasyncio.create_task(blink3(led4))


       print('Toggle')
    else:
        blink2_task = uasyncio.create_task(blink2(led2))
        try: # this is necessary b/c otherwise it throws an attribution error b/c blink3_task is a boolean before assignment
          blink3_task.cancel()
        except:
          pass
        print('Else')
    toggle = not toggle
I had to add the exception b/c otherwise it throws an attribute error.

Post Reply