@@ -178,18 +178,11 @@ def check_if_date_is_custom_or_regular(plan, date):
178
178
def get_shutdown_and_startup_datetimes(plan, current_datetime):
179
179
"""Get the next shutdown/startup date and time
180
180
and return them as datetime.datetime objects"""
181
- # Get next shutdown date and time
181
+ # Get shutdown date and time
182
182
shutdown_date = current_datetime
183
183
shutdown_settings = check_if_date_is_custom_or_regular(plan, shutdown_date)
184
184
shutdown_time = shutdown_settings['stop']
185
- # Check whether the machine should already be off today,
186
- # i.e. if start is before stop, but current time is after stop
187
- startup_time_today = shutdown_settings['start']
188
- if shutdown_time != "None":
189
- shutdown, startup = convert_to_datetime(shutdown_date, shutdown_time, shutdown_date, startup_time_today)
190
- if startup < shutdown and shutdown < current_datetime:
191
- shutdown_time = "None"
192
- # Get next startup date and time
185
+ # Get startup date and time
193
186
startup_date = shutdown_date + datetime.timedelta(days=1)
194
187
startup_settings = check_if_date_is_custom_or_regular(plan, startup_date)
195
188
while startup_settings['start'] == "None":
@@ -198,26 +191,63 @@ def get_shutdown_and_startup_datetimes(plan, current_datetime):
198
191
if startup_date > shutdown_date + datetime.timedelta(days=31):
199
192
raise Exception("Ingen gyldig start-dato fundet")
200
193
startup_time = startup_settings['start']
194
+ # Get the first-coming planned startup
195
+ # This value is only different from startup when a machine is manually turned on
196
+ # after its shutdown time
197
+ planned_startup = convert_to_datetime_helper(startup_date, startup_time)
198
+ # Get next shutdown date and time
199
+ next_shutdown_date = shutdown_date + datetime.timedelta(days=1)
200
+ next_shutdown_settings = check_if_date_is_custom_or_regular(plan, next_shutdown_date)
201
+ next_shutdown_time = next_shutdown_settings['stop']
202
+ # Get next startup date and time
203
+ next_startup_date = next_shutdown_date + datetime.timedelta(days=1)
204
+ next_startup_settings = check_if_date_is_custom_or_regular(plan, next_startup_date)
205
+ while next_startup_settings['start'] == "None":
206
+ next_startup_date = next_startup_date + datetime.timedelta(days=1)
207
+ next_startup_settings = check_if_date_is_custom_or_regular(plan, next_startup_date)
208
+ next_startup_time = next_startup_settings['start']
209
+ startup_time_today = shutdown_settings['start']
210
+ # Handle None values
211
+ if shutdown_time == "None" and next_shutdown_time == "None":
212
+ shutdown_time = f"{current_datetime.hour}:{current_datetime.minute}"
213
+ shutdown_date = next_shutdown_date
214
+ startup_time_today = "0:1"
215
+ elif shutdown_time == "None" and next_shutdown_time != "None":
216
+ shutdown_date, shutdown_time = next_shutdown_date, next_shutdown_time
217
+ startup_date, startup_time = next_startup_date, next_startup_time
218
+ startup_time_today = "0:1"
219
+ elif shutdown_time != "None" and next_shutdown_time == "None":
220
+ next_shutdown_time = shutdown_time
221
+ # Check whether the machine has been turned on manually,
222
+ # i.e. if start is before stop, but current time is after stop
223
+ shutdown, startup = convert_to_datetime(shutdown_date, shutdown_time, shutdown_date, startup_time_today)
224
+ if startup < shutdown and shutdown < current_datetime:
225
+ startup_date, startup_time = next_startup_date, next_startup_time
226
+ shutdown_date, shutdown_time = next_shutdown_date, next_shutdown_time
227
+
201
228
# Convert to datetime.datetime object
202
229
shutdown, startup = convert_to_datetime(shutdown_date, shutdown_time, startup_date, startup_time)
203
230
# Handle shutdown times after 24:00
204
231
shutdown, startup = handle_late_stop(shutdown, startup, current_datetime)
205
- return shutdown, startup
232
+ return shutdown, startup, planned_startup
206
233
207
234
def convert_to_datetime(shutdown_date, shutdown_time, startup_date, startup_time):
208
235
"""Helper method that converts the shutdown/startup date and time
209
236
to datetime.datetime objects and returns those"""
210
237
if shutdown_time == "None":
211
238
shutdown = datetime.datetime.now() + datetime.timedelta(minutes=20)
212
239
else:
213
- shutdown = datetime.datetime(shutdown_date.year, shutdown_date.month, shutdown_date.day,
214
- int(shutdown_time[: shutdown_time.index(":")]),
215
- int(shutdown_time[shutdown_time.index(":") + 1 :]))
216
- startup = datetime.datetime(startup_date.year, startup_date.month, startup_date.day,
217
- int(startup_time[: startup_time.index(":")]),
218
- int(startup_time[startup_time.index(":") + 1 :]))
240
+ shutdown = convert_to_datetime_helper(shutdown_date, shutdown_time)
241
+ startup = convert_to_datetime_helper(startup_date, startup_time)
219
242
return shutdown, startup
220
243
244
+ def convert_to_datetime_helper(date, time):
245
+ """Subfunction for the convert_to_datetime helper method"""
246
+ value = datetime.datetime(date.year, date.month, date.day,
247
+ int(time[: time.index(":")]),
248
+ int(time[time.index(":") + 1 :]))
249
+ return value
250
+
221
251
def handle_late_stop(shutdown, startup, current_datetime):
222
252
"""Helper method to handle late stops"""
223
253
if shutdown < current_datetime:
@@ -238,7 +268,7 @@ def main():
238
268
current_datetime = datetime.datetime.today()
239
269
240
270
# Get shutdown and startup datetimes
241
- shutdown, startup = get_shutdown_and_startup_datetimes(plan, current_datetime)
271
+ shutdown, startup, planned_startup = get_shutdown_and_startup_datetimes(plan, current_datetime)
242
272
243
273
# Refresh the crontab 5 minutes after startup
244
274
# That way, even if a mode such as "mem,"
@@ -247,9 +277,20 @@ def main():
247
277
# To that end, determine the datetime that is 5 minutes after startup
248
278
refresh = startup + datetime.timedelta(minutes=5)
249
279
280
+ # Refresh the crontab 5 minutes before planned_startup
281
+ # This ensures that if a machine is manually turned on
282
+ # after its shutdown time and then left on, it will not
283
+ # end in a state where no startup is planned
284
+ refresh2 = planned_startup - datetime.timedelta(minutes=5)
285
+
250
286
# Determine off time
251
287
off_time = int((startup - shutdown).total_seconds())
252
288
289
+ # Make sure the machine will wake up as planned even if it is not shut down by the schedule
290
+ startup_string = f"{planned_startup.year}-{planned_startup.month}-{planned_startup.day} "\
291
+ f"{planned_startup.hour}:{planned_startup.minute}"
292
+ subprocess.run(["rtcwake", "-m", "no", "--date", startup_string])
293
+
253
294
# Update crontab
254
295
# Get current entries
255
296
TCRON = "/tmp/oldcron"
@@ -260,14 +301,17 @@ def main():
260
301
cronentries = cronfile.readlines()
261
302
with open(TCRON, 'w') as cronfile:
262
303
for entry in cronentries:
263
- if "scheduled_off" not in entry and "set_on-off_schedule" not in entry:
304
+ if "scheduled_off" not in entry and "set_on-off_schedule" not in entry and \
305
+ "shutdown" not in entry and "rtcwake" not in entry:
264
306
cronfile.write(entry)
265
- # Add entry for next shutdown and refresh
307
+ # Add entry for next shutdown and refreshes
266
308
with open(TCRON, 'a') as cronfile:
267
309
cronfile.write(f"{shutdown.minute} {shutdown.hour} {shutdown.day} {shutdown.month} *"
268
310
f" $SCHEDULED_OFF_SCRIPT {MODE} {off_time}\n")
269
311
cronfile.write(f"{refresh.minute} {refresh.hour} {refresh.day} {refresh.month} *"
270
312
f" $ON_OFF_SCHEDULE_SCRIPT \n")
313
+ cronfile.write(f"{refresh2.minute} {refresh2.hour} {refresh2.day} {refresh2.month} *"
314
+ f" $ON_OFF_SCHEDULE_SCRIPT \n")
271
315
subprocess.run(["crontab", TCRON])
272
316
if os.path.exists(TCRON):
273
317
os.remove(TCRON)
0 commit comments