简体   繁体   中英

Python: Run code every n seconds and restart timer on condition

This may be simpler than I think but I'd like to create timer that, upon reaching a limit (say 15 mins), some code is executed.

Meanwhile every second, I'd like to test for a condition. If the condition is met, then the timer is reset and the process begins again, otherwise the countdown continues.

If the condition is met after the countdown has reached the end, some code is executed and the timer starts counting down again.

Does this involve threading or can it be achieved with a simple time.sleep() function?

If the whole process is as simple as you say, I would go about it like this (semi-psuedo-code):

def run_every_fifteen_minutes():
  pass
def should_reset_timer():
  pass
def main():
  timer = 0
  while True:
    time.sleep(1)
    timer+=1
    if should_reset_timer():
      timer = 0
    if timer == 15*60:
      run_every_fifteen_minutes()
      timer = 0

Note that this won't be exactly fifteen minutes in. It might be late by a few seconds. The sleep isn't guaranteed to sleep only 1 second and the rest of the loop will take some time, too. You could add a system time compare in there if you need it to be really accurate.

You could probably accomplish it with threading really elegantly but if you need a quick fix you could try

import time
timer = 15 * 60 # 60 seconds times 15 mins
while timer > 0:
    time.sleep(0.985) # don't sleep for a full second or else you'll be off
    timer -= 1
    if someCondition:
          timer = 15 * 60
executeCode() # called when time is zero and while loop is exited

Thanks for the help everyone, your answers pointed me in the right direction. In the end I came up with:

#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import subprocess

GPIO.setmode(GPIO.BCM)
PIR_PIN = 4
GPIO.setup(PIR_PIN, GPIO.IN)
timer = 15 * 60 # 60 seconds times 15 mins

subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)

try :
    print "Screen Timer (CTRL+C to exit)"
    time.sleep(5)
    print "Ready..."

    while True:
        time.sleep(0.985)

        # Test PIR_PIN condition
        current_state = GPIO.input(PIR_PIN)

        if timer > 0:
            timer -= 1

            if current_state: #is true
                # Reset timer
                timer = 15 * 60

        else:
            if current_state: #is true
                subprocess.call("sudo /opt/vc/bin/tvservice -p", shell=True)

                # Reset timer
                timer = 15 * 60
            else:
                subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)

except KeyboardInterrupt:
    print "Quit"
    GPIO.cleanup()

To put it in context, I'm using a PIR sensor to detect motion and switch on an hdmi connected monitor on a Raspberry Pi. After 15 mins of no movement I want to switch the monitor off and then if (at a later time) movement is detected, switch it back on again and restart the time.

The description sounds similar to a dead main's switch / watchdog timer . How it is implemented depends on your application: whether there is an event loop, are there blocking functions, do you need a separate process for proper isolation, etc. If no function is blocking in your code:

#!/usr/bin/env python3
import time
from time import time as timer

timeout = 900 # 15 minutes in seconds
countdown = timeout # reset the count
while True:
    time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
    countdown -= 1
    if should_reset_count():
        countdown = timeout # reset the count
    if countdown <= 0: # timeout happened
        countdown = timeout # reset the count
        "some code is executed"

The code assumes that the sleep is never interrupted (note: before Python 3.5, the sleep may be interrupted by a signal). The code also assumes no function takes significant (around a second) time. Otherwise, you should use an explicit deadline instead (the same code structure):

deadline = timer() + timeout # reset
while True:
    time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
    if should_reset_count():
        deadline = timer() + timeout # reset
    if deadline < timer(): # timeout
        deadline = timer() + timeout # reset
        "some code is executed"

也许您应该查看Linux工具cron来安排脚本的执行。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM