helps with uasyncio and raspberry pico

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
Donquizote99
Posts: 5
Joined: Thu Aug 05, 2021 6:08 am

helps with uasyncio and raspberry pico

Post by Donquizote99 » Thu Aug 05, 2021 7:06 am

I started a small personal project to learn and practice micropython and raspberry pico, I try to use uasyncio to read sensors and transmit the data, only I have a problem, I don't know what I'm missing, the data reading and transmission is done correctly (dataout ( )), in main () when assigning await humedadsustrato() to a task (huj) it executes correctly, but the humedadsustrato() value does not change within the task, it only changes if I manually restart raspberry pico, humedadsustrato() is an async function that returns the value read from a sensor

I hope you can help me, it is worth mentioning that I am relatively new to micropython


Code: Select all

async def dataout():
        
    while True:
        
        uart = UART(0, baudrate=9600, tx=machine.Pin(16), rx=machine.Pin(17))

        d1d = uasyncio.create_task (h())
        d2d = uasyncio.create_task (t())
        d3d = uasyncio.create_task (humedadsustrato())
        d4d = uasyncio.create_task (tempico())
        d5d = uasyncio.create_task (tsustrato())
        
        ji = await uasyncio.gather(d1d, d2d, d3d, d4d, d5d)
              
        d1 =ji[0]
        d2 =ji[1]
        d3 =ji[2]
        d4 =ji[3]
        d5 =ji[4]        
        
        if d1 == None:
            p1 = "xxx"
        else:
            p1 = "{0:.3f}".format( float(d1))

        if d2 == None:
            p2 = "xxx"
        else:
            p2 = "{0:.3f}".format( d2)
        
        if d3 == None:
            p3 = "xxx"
        else:
            p3 = "{0:.3f}".format( d3)
        
        if estatus == True:
            p4 = "on"
        if estatus == False:
            p4 = "of"

        if ledazul.pin.value() == 0:
            p5 = "aon"
        if ledazul.pin.value() == 1:
            p5 = "aof"

        if ledblanco.pin.value() == 0:
            p6 = "bon"
        if ledazul.pin.value() == 1:
            p6 = "bof"

        if ledrojo.pin.value() == 0:
            p7 = "ron"
        if ledrojo.pin.value() == 1:
            p7 = "rof"

        if bomba1.pin.value() == 0:
            p8 = "xon"
        if bomba1.pin.value() == 1:
            p8 = "xof"

        p9 = "{0:.3f}".format( d4)

        if d5 == None:
            p10 = "xxx"
        else:
            p10 = "{0:.3f}".format( float(d5))

        data_send =str("a"+p1+"b"+p2+"c"+p3+"d"+p4+"e"+p5+"g"+p6+"h"+p7+"i"+p8+"j"+p9+"k"+p10+"l")
        uart.write(data_send)
        await uasyncio.sleep(2)

Code: Select all

async def main():
                    
    horas_de_luz = 20
    horas_de_obscuridad = 15
    
    while True:
         
        huj = uasyncio.create_task( humedadfun( humedadsustrato() ))
        tpl= uasyncio.create_task( tempo( estatus, horas_de_luz, horas_de_obscuridad))
        llo = uasyncio.create_task( dataout() )
        
        await uasyncio.gather(huj, tpl, llo)

Code: Select all

try:
    
    estatus = True
    
    uasyncio.run(main())
    
except onewire.OneWireError:
    pass
except TypeError:
    pass
except KeyboardInterrupt:
    pass
except InvalidPulseCount:
    pass
except InvalidChecksum:
    pass

finally:
    uasyncio.new_event_loop()  

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: helps with uasyncio and raspberry pico

Post by jimmo » Fri Aug 06, 2021 2:28 am

Donquizote99 wrote:
Thu Aug 05, 2021 7:06 am
it executes correctly, but the humedadsustrato() value does not change within the task,
Are you able to share teh code for all the other functions?

I'm a bit confused why both main() and dataout() create the same tasks. Also do the tasks use the uart?

Maybe a good first step would be to make everything work synchronously (i.e. replace all the create_task with await), and then make it parallel after that's working.

FYI you can write:

Code: Select all

d1, d2, d3, d4, d5 = await asyncio.gather(...)
rather than the temporary j1 tuple.

I'd also suggest writing:

Code: Select all

if ledblanco.pin.value() == 0:
  p6 = "bon"
else:
  p6 = "bof"
  
or even simpler:

Code: Select all

p6 = "bon" if ledblanco.pin.value() == 0 else "boff"

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

Re: helps with uasyncio and raspberry pico

Post by pythoncoder » Fri Aug 06, 2021 8:24 am

Repeatedly initialising the UART is odd (although I don't think this is causing the problem). I'd write

Code: Select all

async def dataout():
    uart = UART(0, baudrate=9600, tx=machine.Pin(16), rx=machine.Pin(17))        
    while True:
        # code
Peter Hinch
Index to my micropython libraries.

Donquizote99
Posts: 5
Joined: Thu Aug 05, 2021 6:08 am

Re: helps with uasyncio and raspberry pico

Post by Donquizote99 » Sat Aug 07, 2021 9:10 am

Thanks for the suggestions
I share the modified code and the other functions, however, at first glance the operation does not change

Code: Select all

async def dataout():
    
    uart = UART(0, baudrate=9600, tx=machine.Pin(16), rx=machine.Pin(17))
        
    while True:

        d1 = await h()
        d2 = await t()
        d3 = await humedadsustrato()
        d4 = await tempico()
        d5 = await tsustrato()
                
        if d1 == None:
            p1 = "xxxx"
        else:
            p1 = "{0:.3f}".format(d1)

        if d2 == None:
            p2 = "xxxx"
        else:
            p2 = "{0:.3f}".format( d2)
        
        if d3 == None:
            p3 = "xxxx"
        else:
            p3 = "{0:.3f}".format( d3)
        
        if estatus == True:
            p4 = "on"
        else:
            p4 = "of"

        if ledazul.pin.value() == 0:
            p5 = "aon"
        else:
            p5 = "aof"

        if ledblanco.pin.value() == 0:
            p6 = "bon"
        else:
            p6 = "bof"

        if ledrojo.pin.value() == 0:
            p7 = "ron"
        else:
            p7 = "rof"

        if bomba1.pin.value() == 0:
            p8 = "xon"
        else:
            p8 = "xof"

        p9 = "{0:.3f}".format( d4)

        if d5 == None:
            p10 = "xxxx"
        else:
            p10 = "{0:.3f}".format(d5)

        data_send =str("a"+p1+"b"+p2+"c"+p3+"d"+p4+"e"+p5+"g"+p6+"h"+p7+"i"+p8+"j"+p9+"k"+p10+"l")
        uart.write(data_send)
        await uasyncio.sleep(2)
     

Code: Select all

async def main():
                    
    horas_de_luz = 20
    horas_de_obscuridad = 15
    
    while True:
            
        huj = uasyncio.create_task( humedadfun( await humedadsustrato() ))
        tpl= uasyncio.create_task( tempo( estatus, horas_de_luz, horas_de_obscuridad))
        pp = uasyncio.create_task( datain() )
        llo = uasyncio.create_task( dataout() )
        
        await uasyncio.gather(huj, tpl, pp, llo)
    
try:
    estatus = True
    
    loop = uasyncio.get_event_loop()
    loop.create_task(main()) 
    loop.run_forever()  
    
except onewire.OneWireError:
    pass
except TypeError:
    pass
except KeyboardInterrupt:
    pass
except InvalidPulseCount:
    pass
except InvalidChecksum:
    pass

finally:
    uasyncio.new_event_loop()      

the only function that "dataout ()" and "main ()" share would be "humedadsustrato()", which is the one that presents the problem, in the first one the data read by the sensor is sent via UART and in "main ()" is part of the "humedadfun ()" task, which aims to activate or deactivate a timer according to the value registered by the sensor

Code: Select all


sh_sustrato = machine.ADC(pin_hsustrato)
fc_voltaje = 3.3/(65535)

v_maxsolucion = 1.4  
v_maxcontinuo = 0.024  
h_minabs = 0.001       

fc_humedad = 100/(v_maxsolucion)  
fc_humedadmax = 100/(v_maxcontinuo)  
fc_seco = h_minabs/(3.3)         
        

async def humedadsustrato():
        
    lectura = sh_sustrato.read_u16()
    voltaje = (lectura * fc_voltaje)
  
    if 0.1 < voltaje < 3.2:
        
        humedad = (fc_humedad * voltaje)
        await uasyncio.sleep(0)
    
    if voltaje < 0.1:
        
        humedad = voltaje * fc_humedadmax
        await uasyncio.sleep(0)

    if voltaje > 3.2:
    
        humedad = voltaje * fc_seco
        await uasyncio.sleep(0)
        
    return humedad
    

Code: Select all

async def humedadfun(humedad_sustrato):
    
    hity_min = 50 
    hity_max = 80
    time_auto = 10
    
    try:
                
        if humedad_sustrato <= hity_min:
            await onallb()

        if hity_min < humedad_sustrato < hity_max:
        
            while True :
                                    
                for lb in listabomba:
                    lb.pin.value(1)
                await uasyncio.sleep(time_auto)
                 
                for lb in listabomba:
                    lb.pin.value(0)
                await uasyncio.sleep(time_auto)
            
        if humedad_sustrato >= hity_max:
            await offallb()
            
    except:
        pass
        

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

Re: helps with uasyncio and raspberry pico

Post by pythoncoder » Sun Aug 08, 2021 8:28 am

What do the coroutines offalb() and onallb() do?

It's perhaps worth pointing out that humedadsustrato() doesn't gain any advantage by being a coroutine: it could equally well be a synchronous function.

I can't see an obvious error but my guess is that perhaps an unduly long delay is being called up. I can only offer general tips on debugging. One is inserting lots of print statements in the problematic code. Another is creating a radically simplified test script which runs the problematic code and does little else. These kind of tricks can help pin down the problem.

Another general point (which won't fix your problem) is to learn about the stream mechanism which is the way to communicate with a UART asynchronously. The way you are doing it should work OK, but it will block for the duration of the transmission which can be a problem in some applications.
Peter Hinch
Index to my micropython libraries.

Donquizote99
Posts: 5
Joined: Thu Aug 05, 2021 6:08 am

Re: helps with uasyncio and raspberry pico

Post by Donquizote99 » Tue Aug 10, 2021 5:06 am

Thanks for your advice, I could already obtain the desired behavior, instead of passing the coroutine as an argument of the task, the introduction as a variable within the function, with this I obtained the desired behavior; substrate humidity () I have it as a coroutine to be able to execute it in parallel together with the other sensors, otherwise I got an error when sending the data, I'm still not sure if it is correct, however it already works as expected, I still have a lot to understand, thank you for your help.

Code: Select all

async def humedadfun():
    
    while True:
        
        
        humedad_sustrato =  await humedadsustrato()
        
        hity_min = 50 
        hity_max = 100
        temp_max_sustrato = 40
        temp_min_sustrato = 15
        time_auto = 5
        
        
        if humedad_sustrato <= hity_min:
            await onallb()

        
        if hity_min < humedad_sustrato < hity_max:
                                    
            for lb in listabomba:
                lb.pin.value(1)
            await uasyncio.sleep(time_auto)
             
            for lb in listabomba:
                lb.pin.value(0)
            await uasyncio.sleep(time_auto)
            
        if humedad_sustrato >= hity_max:
            await offallb()
            

Code: Select all


async def onallb():

    for lb in listabomba:
        lb.pin.value(0)
    await uasyncio.sleep(0)


async def offallb():
        
    for lb in listabomba:
        lb.pin.value(1)
    await uasyncio.sleep(0)
    

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

Re: helps with uasyncio and raspberry pico

Post by pythoncoder » Tue Aug 10, 2021 12:31 pm

Much as I'm an enthusiast for asynchronous coding, there is no point in making functions like this asynchronous:

Code: Select all

async def onallb():
    for lb in listabomba:
        lb.pin.value(0)
    await uasyncio.sleep(0)
It will work just as well as a synchronous function:

Code: Select all

def onallb():
    for lb in listabomba:
        lb.pin.value(0)
The purpose in making a function asynchronous is to cater for the case where otherwise it would block for a long time:

Code: Select all

async def foo():
    for _ in range(1000):  # 10 seconds worth of work
        send(data)  # Say this takes 10ms
        await uasyncio.sleep(0)
In this case the function would block for 10s if coded synchronously. As above, other tasks would get to run while that 10s period was in progress.
Peter Hinch
Index to my micropython libraries.

Post Reply