Whilst thinking about how to tackle my Raspberry Pi temperature project, I found and issue that needed resolving.
In short, I want to record the temperature of my room every 15 minutes. I wanted to record every 15th minute of every hour for a couple of reasons:
- To keep the data fair: simply rounding to the nearest quarter hour could mean a difference of up to 15 minutes should the Pi turn off and start running again.
- Uniformity: I didn’t want the time to be every 15 minutes after the program starts, for
example10:21 and then 10:36. I want to make a clear comparison of the temperature exactly at the same time for any time I start or stop the program.
Now there are a couple of ways to start this automation, specifically in Linux:
- cronjob: can run code on a specified time/interva
- init.d startup: can run
codeonce when startup commences
The cronjob method would be good, but let’s think about this in some more detail:
Every 15 minutes, the system will fire up the code from scratch. Which means all imports will take place, load functions into memory, assign variables etc. which costs time (yes I am being THAT pedantic) and would not always be accurate. Also, it takes extra setting up (so if someone else uses my project, it can be more complicated to set up)
Init.d will simply run the code once on startup. This will allow you to manage time better, although if the code crashes (for some reason), you will have to manually start it or restart the machine.
There a pros and cons to both methods, but ultimately I wanted full control over time and as you may have gathered, opted for init.d.
Now, the interesting bit! Getting the time right, every time.
Again there were a couple of ways that can accomplish this. I needed to offset the start time (start of the script) to take measurement at exactly every quarter hour.
Obviously, this can be any time between a 15 minute window.
I could have arbitrarily looped over the current UNIX time until it divided by 900 (seconds in 15 minutes) but this takes processing time and if the difference to run the loop (in MS) pushes it over a second, I could potentially miss a record of data.
Ideally, I wanted to calculate the time difference and wait it out. Then I could take a record of data and process it, before calculating the difference again for the next time. Doing things this way means I have a 14 minute 59 seconds window to run whatever code I wanted to, until the next time. Obviously, 14 minutes 59 seconds is a long time in terms of running
For example, processing dynamic data could take you different times to complete.
Below is my algorithm to calculate the time needed to wait until the next quarter hour. Immediately after time.sleep(), the
# Calculate the time required to wait until the next quart hour from datetime import datetime import time # minute, second, millisecond to a string and split into list min_sec = datetime.now().strftime("%M %S .%f").split(" ") # calculate minutes to wait for the next whole quart hour # explanation of m calculation: e.g. time = 12:33 : min = 33 # 33 % 15 = 3 : find out minutes since last quart # 15 - 3 = 12 : whole minutes to wait for next quart # 12 * 60 = 720 : whole seconds to wait with time.sleep() m = (15-(int(min_sec)%15))*60 # convert string to int and calculate seconds s = int(min_sec) # convert string to int ms = float(min_sec) # convert ms string to float # time to sleep until next whole quart # calculation: # minutes in seconds minus seconds over whole minute minus ms over whole second # sleep for required time time.sleep(float(m-s) - ms) # .. # whole quart of hour reached.... # time should be X:(00/15/30/45):00.000 # run time sensitive code here