10

Is there a way to prevent a computer running OS X from going to sleep from within a Python script?

christianbrodbeck
  • 2,113
  • 2
  • 19
  • 24
  • Not a programming answer, but [Caffeine](https://itunes.apple.com/us/app/caffeine/id411246225) is a nice freeware app which stops your computer falling asleep when activated. – Alex Jan 08 '13 at 13:27
  • Thanks @Alex, I've come across several apps that do this, but doing it from inside the script would be cleaner... – christianbrodbeck Jan 08 '13 at 13:30

5 Answers5

12

You can use the built-in caffeinate command.

subprocess.Popen('caffeinate')

This is how I use it:

import sys
import subprocess

if 'darwin' in sys.platform:
    print('Running \'caffeinate\' on MacOSX to prevent the system from sleeping')
    subprocess.Popen('caffeinate')
idbrii
  • 10,975
  • 5
  • 66
  • 107
guya
  • 5,067
  • 1
  • 35
  • 28
5

You can also run caffeinate in an external terminal window and leave it open to achieve what the OP wants.

  1. open a terminal

  2. type caffeinate

  3. press Enter

Once you have done this, your Mac will stay awake for as long as you leave the Terminal running.

You can minimize or hide it, and your Mac will not go to sleep until you use the keyboard shortcut Ctrl+C to interrupt the command.

source

JacoSolari
  • 1,226
  • 14
  • 28
3

Since OS 10.6, you have to make use of the IOPMAssertion family of functions, available in Cocoa. This is really well explained there.

Then, you will have to call it from Python. I'm not sure that there're already specific bindings for Cocoa in Python, but you can call Objective-C functions. It is really well described here.

Community
  • 1
  • 1
dasilvj
  • 10,356
  • 2
  • 17
  • 16
  • So, that would involve using ctypes to implement listing 2 of [qa1340](http://developer.apple.com/library/mac/#qa/qa1340/_index.html)? Are there instructions for that? (E.g., how can I retrieve a value such as kIOPMAssertionTypeNoDisplaySleep?) – christianbrodbeck Jan 08 '13 at 18:02
0

There is a Python utility that illustrates how to raise the required assertions in Python directly: https://github.com/minrk/appnope

christianbrodbeck
  • 2,113
  • 2
  • 19
  • 24
  • appnope is about preventing App Nap not system sleep. See: https://github.com/minrk/appnope/blob/daac76517da8aba6fd0614eb1ab37d9b8ee39633/appnope/_nope.py#L78 – UloPe Nov 06 '19 at 16:17
  • Just look a little further up in the code for the other constants – christianbrodbeck Nov 08 '19 at 00:53
  • Yes, the constants are there but the functionality is not exposed via the documented `nope()` API. – UloPe Nov 08 '19 at 08:48
0

Another alternative would be to run the below script with

python <location/of/my/script.py> <hour until I want the PC to be awake>
e.g.
python /Users/johndee/Downloads/keep_awake.py 18:30

The script, which is to be saved locally:

#!/usr/bin/env python3
import random
import sys
import time
from datetime import datetime
from tkinter import Tk

import pyautogui

CHECK_STATUS_ONCE_IN = 120
WAIT_FOR_POSITION_CHANGE = 10


def current_position():
    tkinter = Tk()
    return [tkinter.winfo_pointerx(), tkinter.winfo_pointery()]


def mouse_is_moving():
    pos1 = current_position()
    time.sleep(WAIT_FOR_POSITION_CHANGE)
    pos2 = current_position()
    return not pos1 == pos2


def keep_awake():
    # Shake the mouse a lil bit
    initial_x, initial_y = current_position()
    try:
        for _ in range(random.randint(1, 10)):
            # Mouse
            pyautogui.moveTo(random.randint(1, 1000), random.randint(1, 1000))

            # Keys
            pyautogui.press("shift")

        # Restore controls
        pyautogui.moveTo(initial_x, initial_y)
    except pyautogui.FailSafeException as e:
        print(e)


def inspect_activity_until(time_to_stop: datetime):
    time_to_stop = datetime.now().replace(
        hour=time_to_stop.hour, minute=time_to_stop.minute
    )
    while datetime.now() < time_to_stop:
        if not mouse_is_moving():
            keep_awake()
        time.sleep(CHECK_STATUS_ONCE_IN)

    print(f"Stopping at {datetime.now()}")


if __name__ == "__main__":
    given_time = sys.argv[1]
    date_time_obj = datetime.strptime(given_time, "%H:%M")
    inspect_activity_until(date_time_obj)

asdf
  • 49
  • 1
  • 5