I have the following where it keeps checking for current time in a while loop, and when it eventually matches the time_defined
then runs the code in the if statement.
Also, any suggestions of improvement are welcome.
Thank you in advance!
I have the following where it keeps checking for current time in a while loop, and when it eventually matches the time_defined
then runs the code in the if statement.
Also, any suggestions of improvement are welcome.
Thank you in advance!
Any long-running Python script (including yours) will run while the computer is awake, pause execution while the computer sleeps, then automatically resume execution when the computer wakes up again. However, there are a couple of problems with your script that may be preventing it from running correctly, especially if the computer sleeps through the time specified in time_defined
.
First, datetime.datetime.now()
and datetime.datetime()
have 1-microsecond precision. Depending how fast your loop runs, it may not evaluate the time_now = datetime.datetime.now()
line during the exact microsecond specified in time_defined
(implicitly 20:00:00.000000). This is especially true if your computer happens to be asleep during that particular microsecond. In either of these cases, the test will never come out true, and your script will never emerge from its loop. You could fix both of these problems by testing for time_now >= time_defined
instead of time_now == time_defined
. There is no way to run the scheduled code while the computer is sleeping. However, with this change, if the computer sleeps through the scheduled time, the scheduled code will run as soon as it wakes up.
Second, your code is using a busy loop for scheduling, which is very inefficient. This won't prevent it from running correctly, but it will peg one core of your processor at 100% usage while it is running. If you use time.sleep()
, you can reduce the processor use nearly to zero. In principle, you could use something like time.sleep((time_defined-time_now).totalseconds())
to sleep exactly the right number of seconds. However, (at least on a Mac) that timer only counts seconds during which the computer is awake, so suspending the computer would throw off the schedule. However, you could use a sequence of short sleeps (e.g., 1 second) to improve efficiency dramatically and still have fairly precise timekeeping.
Here's some code that fixes both of these problems:
import datetime, time
def background_program():
time_defined = datetime.datetime(2017, 4, 7, 20, 0, 0)
...
while(True):
time_now = datetime.datetime.now()
if time_now >= time_defined:
try:
# Run some code
pass
except:
print('Failed to run')
finally:
break
else:
# use a shorter delay if you want a more exact runtime
time.sleep(1)
Here's some more streamlined code that does the same thing. I've also added a command line argument, so you can call this like python myscript.py --start-time 2017-04-17 20:00:00
. (You can also run python myscript.py --help
to get a little help.)
import datetime, time, argparse
def background_program(time_defined):
# wait until time_defined, sleeping in short steps
# note: you could use a shorter delay for more precision
print "waiting until {}".format(time_defined.strftime('%Y-%m-%d %H:%M:%S'))
while(datetime.datetime.now() < time_defined):
time.sleep(1)
# perform scheduled action
try:
print('Running the scheduled task.')
except:
print('Failed to run')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Run a background task.')
parser.add_argument(
'--start-time', nargs=2, default=None,
help='Specify the time to run the task, in YYYY-MM-DD HH-MM-SS format.'
)
args = parser.parse_args()
if args.start_time is not None:
start_time = datetime.datetime.strptime(' '.join(args.start_time), '%Y-%m-%d %H:%M:%S')
background_program(start_time)
What you are asking is not possible (everything stops executing at sleep mode).
What you can do is mark your file to resume when the PC is turned back on and on startup. There are some great answers on this matter:
For the Linux case:
For the wakeup-resume case:
Find the /usr/lib/pm-utils/sleep.d
, or /etc/pm/sleep.d
(whichever works in your system - personally used the first choice)
Add a script in there, which will look like this:
myWakeupScript
#!/bin/sh
case "$1" in
resume)
python path/to/your_script.py
esac
Make your script executable: chmod +x /usr/lib/pm-utils/sleep.d/myWakeupScript
For the startup case:
Place a script inside /etc/init.d/
:
myStartupScript
#!/bin/sh
python path/to/your_script.py
Make it executable: chmod +x /etc/init.d/myStartupScript
Possible problem and fix:
Thanks to @meetamit, if this does not run you have to create a symlink to
/etc/rc.d/
ln -s /etc/init.d/start_my_app /etc/rc.d/
For the Windows case:
The provided solutions are pretty much self-explanatory and you can choose one of those to fit your purpose
I recommend this (seems the easiest):
Windows, right? Open Task Scheduler and create a new task with a trigger of event log entry Microsoft-Windows-Kernel-Power, Kernel-Power and whatever the EventID is for sleep/wake.
Use the task scheduler and trigger on an event. Choose to trigger by an event and then choose. Setting Basic Log: System Source: Kernel-Power Event ID: 42