Search code examples
pythontimewhile-loopraspberry-pipython-datetime

How to loop a function to perform a task every 15 minutes (on the 0/15/30/45 minute mark)?


I have a program running on a Raspberry Pi, and I want to pull some data from a thermometer every 15 minutes at 0, 15, 30 and 45 minutes past the hour.

I have tried this using a while loop, I previously used time.sleep(900) effectively, but this sometimes drifted away from 0, 15, 30 and 45 minutes past the hour.

At the moment I currently have this;

from datetime import datetime

def run(condition):
    while condition == True:
        if (datetime.now().minute == (0 or 15 or 30 or 45)):
            #perform some task
        temperature_store()

For sake of simplicity I have not got into what temperature_store() does, but it reads the temperature from a sensor plugged into the Pi and then prints it.

I want temperature_store() to occur every 15 minutes, but currently, it is happening every second.

I am aware that it is probably because I have the logic/syntax of the while loop wrong, but I cannot figure it out. (Do not have much experience with python scripts and delays in time).


Solution

  • There's two ways to do this: the 'easy' way, and the stable way.

    The easy way is simply to do the following:

    from datetime import datetime
    from time import sleep
    
    def run(condition):
        while datetime.now().minute not in {0, 15, 30, 45}:  # Wait 1 second until we are synced up with the 'every 15 minutes' clock
            sleep(1)
    
        def task():
            # Your task goes here
            # Functionised because we need to call it twice
            temperature_store()
        
        task()
    
        while condition == True:
            sleep(60*15)  # Wait for 15 minutes
            task()
    

    This essentially waits until we are synced up with the correct minute, then executes it, and simply waits 15 minutes before looping. Use it if you wish, it's the simplest way in pure Python. The issues with this are countless, however:

    • It syncs up with the minute, not the second
    • It's machine dependent, and may give incorrect readings on some machines
    • It needs to run continuously!

    The second method is to use cron-jobs, as suggested in the comments. This is superior because:

    • It uses system-level events, not timers, so we can assure the best possible accuracy
    • Since we're not waiting, there's no room for error
    • It only runs the function once it gets the aforementioned event setter.

    So, to use, simply (assuming you're on Linux):

    from crontab import CronTab
    
    cron = CronTab(user='username')  # Initialise a new CronTab instance
    job = cron.new(command='python yourfile.py')  # create a new task
    job.minute.on(0, 15, 30, 45)  # Define that it should be on every 0th, 15th, 30th and 45th minute
    
    cron.write()  # 'Start' the task (i.e trigger the cron-job, but through the Python library instead
    

    (obviously, configure username appropriately)

    In yourfile.py, in the same path, simply put your code for temperature_store().

    I hope this helps. Obviously, go with the first methods or even the suggestions in the comments if you prefer, but I just felt that the entire loop structure was a bit too fragile, especially on a Raspberry Pi. This should hopefully be something more stable and scalable, should you want to hook up other IoT things to your Pi.