Timers - several timers + several run per day

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
Jerremy09
Posts: 28
Joined: Wed May 08, 2019 7:40 am

Timers - several timers + several run per day

Post by Jerremy09 » Wed Jul 21, 2021 7:28 am

Hello all,

I would need help from you. I´m trying to build my own solution to build a machine that will TurnON/OFF 2 devices based on the scheduler. So my task also was to split the day into 3 periods:
1) morning
2) Day
3) evening
- each period may start/end at a specified time. and "Switch" can be different for every period

tools Description:
Firmware - 1.14
Board - lolin d32 pro

So my solution:
build 4 timers based on which will be triggered based on a defined period whole through the day and inside called function there is "if" block to determine whether RTC is within time range or not. Unfortunately non of the timer is triggered.

Code Example:

Code: Select all

#----------------------------------------------------#
def morning_timer0(pin):
   RTC read
   If statemen to compare wheter RTC is within day period:
      process

def day_timer1(pin):
   RTC read
   If statemen to compare wheter RTC is within day period:
      process

def evening_timer2(pin):
   RTC read
   If statemen to compare wheter RTC is within day period:
      process

def timer3(pin):
   process
#----------------------------------------------------#
# Timers definition
SCHED_TIME0 = 21 600 000   # Becuse it should run only 4 times per day
tim0 = machine.Timer(0)
tim0.init(mode=machine.Timer.PERIODIC, period=SCHED_TIME0, callback=morning_timer0)

# - all of them has the same definition, there is just "period" changing --> so they are called in different moment of the day
1) Cannot it be that the Scheduled period is simply too much? (I read that in Firmware 1.16 - there is a limitation to the number of timers = 4 (0 - 3)). (I can send the code - but it is too long )
2) I need them to run parallelly
3) I tried to use also "uasyncio" library with no success (based on documentation - https://docs.micropython.org/en/latest/ ... yncio.html)

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

Re: Timers - several timers + several run per day

Post by jimmo » Wed Jul 21, 2021 7:37 am

Jerremy09 wrote:
Wed Jul 21, 2021 7:28 am
1) Cannot it be that the Scheduled period is simply too much? (I read that in Firmware 1.16 - there is a limitation to the number of timers = 4 (0 - 3)). (I can send the code - but it is too long )
Possibly, I would need to check. But in general the timers make more sense when you need low-latency and short interval functionality. (i.e. you can use a timer to toggle a pin thousands of times per second).

A much easier and more flexible way to do this is to have a single timer that runs e.g. every 1 minute, and checks the time and decides what to do based on the current state.

i.e. if time is now > 9am, and the 9am thing isn't on yet, turn it on.
Jerremy09 wrote:
Wed Jul 21, 2021 7:28 am
2) I need them to run parallelly
Can you clarify what you mean by that?
Jerremy09 wrote:
Wed Jul 21, 2021 7:28 am
3) I tried to use also "uasyncio" library with no success (based on documentation - https://docs.micropython.org/en/latest/ ... yncio.html)
You've come to the right place! Let us know what you tried and what didn't work.

See also Peter (@pythoncoder)'s excellent tutorial here: https://github.com/peterhinch/micropyth ... /README.md

Jerremy09
Posts: 28
Joined: Wed May 08, 2019 7:40 am

Re: Timers - several timers + several run per day

Post by Jerremy09 » Wed Jul 21, 2021 3:53 pm

Hi there,

I think I figured it out :-) (as test example)

Code: Select all

import uasyncio

# Define Function to be planned
async def text1(text,time):
    while True:
        print(text)
        await uasyncio.sleep(time)

# Delete infinite loop
try:
    import uasyncio
    uasyncio.Loop.stop()
    uasyncio.Task.cancel()
except:
    pass

# Define infinite loop with Tasks
run = uasyncio.new_event_loop()
run.create_task(text1("Log - Taks1 - 2s",2))
run.create_task(text1("Log - Taks2 - 10s",10))
run.run_forever()
run.close()
works for me to print :
1) "Log - Taks1 - 2s" - every 2 seconds
2) "Log - Taks2 - 10s" - every 10 seconds

Question:
How to terminate "run_forever()"?
- I tested:

Code: Select all

try:
    import uasyncio
    uasyncio.Loop.stop()
    uasyncio.Task.cancel()
except:
    pass
result:
Running selected lines
Traceback (most recent call last):
File "<stdin>", line 22, in <module>
File "uasyncio/core.py", line 1, in run_forever
File "uasyncio/core.py", line 1, in run_until_complete
File "uasyncio/core.py", line 1, in wait_io_event
KeyboardInterrupt:

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

Re: Timers - several timers + several run per day

Post by jimmo » Wed Jul 21, 2021 11:55 pm

Jerremy09 wrote:
Wed Jul 21, 2021 3:53 pm
I think I figured it out (as test example)
Yep, that looks good.
Jerremy09 wrote:
Wed Jul 21, 2021 3:53 pm
How to terminate "run_forever()"?
The simple answer is that "you don't"... i.e. the only reason to terminate run_forever is when your program is stopped (i.e. by you hitting Ctrl-C or resetting the board). Your entire program should run inside an asyncio task.

In general with asyncio you shouldn't need to ever access the event loop:

Code: Select all

async def main_task():
  asyncio.create_task(text1("Log - Taks1 - 2s",2))
  asyncio.create_task(text1("Log - Taks1 - 2s",2))

asyncio.run(main())
If you want to cancel a task (i.e. to stop one of the timers) you can use:

Code: Select all

async def main_task():
  t1 = asyncio.create_task(text1("Log - Taks1 - 2s",2))
  t2 = asyncio.create_task(text1("Log - Taks1 - 2s",2))
  
  ... do other stuff ...
  await asyncio.sleep(10)
  
  t1.cancel()
  t2.cancel()

asyncio.run(main())
and then the task will raise asyncio.CancelledError and exit.

Post Reply