Prevent sleep mode python (Wakelock on python)
Asked Answered
J

11

21

How I can prevent sleep-mode on python without using extra apps on different OS(Ubuntu, Windows...) but in most cases I need Linux solution

I am making app that works big amount of time. It uses like 80% of CPU, so a user just start this app and go away from keyboard. So I think I need something like system api or library that lock sleep-mode. I am sure that, it exists. For example, if you open any video player on your OS, your (PC, Laptop) will not go to sleep mode, the same thing in browser.

Also, there is the same thing in Android (WakeLock) or Windows (SetThreadExecutionState)

Jazmin answered 25/8, 2019 at 14:44 Comment(4)
What kind of app is this? Is it made using tkinter ? You need to give details for people to help you.Grumble
@mishsx No, it does not use tkinter, just simple app that runs in terminal.Jazmin
I would not expect that a cross-platform solution is available. You might need to implement a platform-specific solution yourself, which uses WakeLock or SetThreadExecutionState or something else depending on the OS on which it is running.Theresa
I created a package for it called stay-awake PyPi: pypi.org/project/stay-awake Github: github.com/singhsidhukuldeep/stay-awake MORE DETAILS IN ANSWERSCentigrade
G
16

While googling around to find a solution there was no package available, so I decided to package it to put it to PyPI: wakepy. I got PRs for cross-platform support, and currently wakepy supports Windows, Linux and macOS.

CLI

python -m wakepy [-p]

Using the optional -p flag will use a presentation mode, which keeps the screen on & unlocked.

Python API

Prevent sleep:

from wakepy import keep

with keep.running():
    # do stuff that takes long time

Prevent screensaver/screen lock (and sleep):

from wakepy import keep

with keep.presenting():
    # do stuff that takes long time
Gamopetalous answered 13/1, 2021 at 20:10 Comment(0)
G
13

I ran into similar situation where a process took long enough to execute itself that windows would hibernate. To overcome this problem I wrote a script.

The following simple piece of code can prevent this problem. When used, it will ask windows not to sleep while the script runs. (In some cases, such as when the battery is running out, Windows will ignore your request.)

    class WindowsInhibitor:
        '''Prevent OS sleep/hibernate in windows; code from:
        https://github.com/h3llrais3r/Deluge-PreventSuspendPlus/blob/master/preventsuspendplus/core.py
        API documentation:
        https://msdn.microsoft.com/en-us/library/windows/desktop/aa373208(v=vs.85).aspx'''
        ES_CONTINUOUS = 0x80000000
        ES_SYSTEM_REQUIRED = 0x00000001

        def __init__(self):
            pass

        def inhibit(self):
            import ctypes
            print("Preventing Windows from going to sleep")
            ctypes.windll.kernel32.SetThreadExecutionState(
                WindowsInhibitor.ES_CONTINUOUS | \
                WindowsInhibitor.ES_SYSTEM_REQUIRED)

        def uninhibit(self):
            import ctypes
            print("Allowing Windows to go to sleep")
            ctypes.windll.kernel32.SetThreadExecutionState(
                WindowsInhibitor.ES_CONTINUOUS)

To run the script, simply :

    import os

    osSleep = None
    # in Windows, prevent the OS from sleeping while we run
    if os.name == 'nt':
        osSleep = WindowsInhibitor()
        osSleep.inhibit()

    # do slow stuff

    if osSleep:
        osSleep.uninhibit()
Grumble answered 25/8, 2019 at 15:2 Comment(0)
D
10

Created sample TK application to keep windows awake

import tkinter as tk
import ctypes
import sys

def display_on():
    global root
    print("Always On")
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
    root.iconify()

def display_reset():
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
    sys.exit(0)


root = tk.Tk()
root.geometry("200x60")
root.title("Display App")
frame = tk.Frame(root)
frame.pack()

button = tk.Button(frame,
                   text="Quit",
                   fg="red",
                   command=display_reset)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
                   text="Always ON",
                   command=display_on)
slogan.pack(side=tk.LEFT)

root.mainloop()
Dissyllable answered 24/7, 2020 at 7:46 Comment(3)
Worked for me on Windows 10. Thank you.Behm
This worked but how do I wake up a display if it already went to sleep prior to calling the SetThreadExecutionState(0x80000002)Aghast
@Aghast : it prevent windows to goto sleep, it can't wake up screen.Dissyllable
C
4

I created a package for it called stay-awake

PyPi: https://pypi.org/project/stay-awake/

Github: https://github.com/singhsidhukuldeep/stay-awake

Go to https://pypi.org/project/stay-awake/ Go to https://pypi.org/project/stay-awake/ Go to https://pypi.org/project/stay-awake/ Go to https://pypi.org/project/stay-awake/

Stay-Awake is a Simple Platform Independent Python package to keep your system awake without affecting workflow!

  • Does this affect workflow?

No, this only get's triggered when you don't do any mouse movements!

  • Is there a GUI?

This was intended to be a light weight solution, so as of now it only has a CLI!

  • How does it work?

If in a span of 60 seconds you don't move your mouse, this script will automatically move your mouse for about 1 to 4 pixels randomly. There won't be any mouse displacement! If you are working, this will do absolutely nothing!

Setup

Installing Package

pip3 install stay-awake

Running

python3 -m stay-awake

You can also give custom timeouts Eg: for 5 minutes (default is 1 min) python3 -m stay-awake 5

enter image description here

Centigrade answered 17/9, 2021 at 11:32 Comment(0)
T
3

Based on multiple approaches I've found throughout the internet I've come up with this module below. Special thanks to @mishsx for the Windows workaround.

Using it is very simple. You may opt for the decorator approach using standby_lock or via StandbyLock as a context manager:

## decorator
@standby_lock
def foo(*args, **kwargs):
    # do something lazy here...
    pass

## context manager
with StandbyLock():
    # ...or do something lazy here instead
    pass

While foo is executing, your system will stay awake.

Note: There are still some caveats, as Linux may require sudo privileges and OS X (Darwin) is not tested yet.

from functools import wraps
import platform

class MetaStandbyLock(type):
    """
    """

    SYSTEM = platform.system()

    def __new__(cls, name: str, bases: tuple, attrs: dict) -> type:
        if not ('inhibit' in attrs and 'release' in attrs):
            raise TypeError("Missing implementations for classmethods 'inhibit(cls)' and 'release(cls)'.")
        else:
            if name == 'StandbyLock':
                cls._superclass = super().__new__(cls, name, bases, attrs)
                return cls._superclass
            if cls.SYSTEM.upper() in name.upper():
                if not hasattr(cls, '_superclass'):
                    raise ValueError("Class 'StandbyLock' must be implemented.")
                cls._superclass._subclass = super().__new__(cls, name, bases, attrs)
                return cls._superclass._subclass
            else:
                return super().__new__(cls, name, bases, attrs)

class StandbyLock(metaclass=MetaStandbyLock):
    """
    """

    _subclass = None

    @classmethod
    def inhibit(cls):
        if cls._subclass is None:
            raise OSError(f"There is no 'StandbyLock' implementation for OS '{platform.system()}'.")
        else:
            return cls._subclass.inhibit()

    @classmethod
    def release(cls):
        if cls._subclass is None:
            raise OSError(f"There is no 'StandbyLock' implementation for OS '{platform.system()}'.")
        else:
            return cls._subclass.release()

    def __enter__(self, *args, **kwargs):
        self.inhibit()
        return self

    def __exit__(self, *args, **kwargs):
        self.release()

class WindowsStandbyLock(StandbyLock):
    """
    """

    ES_CONTINUOUS      = 0x80000000
    ES_SYSTEM_REQUIRED = 0x00000001

    INHIBIT = ES_CONTINUOUS | ES_SYSTEM_REQUIRED
    RELEASE = ES_CONTINUOUS

    @classmethod
    def inhibit(cls):
        import ctypes
        ctypes.windll.kernel32.SetThreadExecutionState(cls.INHIBIT)

    @classmethod
    def release(cls):
        import ctypes
        ctypes.windll.kernel32.SetThreadExecutionState(cls.RELEASE)

class LinuxStandbyLock(metaclass=MetaStandbyLock):
    """
    """

    COMMAND = 'systemctl'
    ARGS = ['sleep.target', 'suspend.target', 'hibernate.target', 'hybrid-sleep.target']

    @classmethod
    def inhibit(cls):
        import subprocess
        subprocess.run([cls.COMMAND, 'mask', *cls.ARGS])

    @classmethod
    def release(cls):
        import subprocess
        subprocess.run([cls.COMMAND, 'unmask', *cls.ARGS])

class DarwinStandbyLock(metaclass=MetaStandbyLock):
    """
    """

    COMMAND = 'caffeinate'
    BREAK = b'\003'

    _process = None

    @classmethod
    def inhibit(cls):
        from subprocess import Popen, PIPE
        cls._process = Popen([cls.COMMAND], stdin=PIPE, stdout=PIPE)

    @classmethod
    def release(cls):
        cls._process.stdin.write(cls.BREAK)
        cls._process.stdin.flush()
        cls._process.stdin.close()
        cls._process.wait()

def standby_lock(callback):
    """ standby_lock(callable) -> callable
        This decorator guarantees that the system will not enter standby mode while 'callable' is running.
    """
    @wraps(callback)
    def new_callback(*args, **kwargs):
        with StandbyLock():
            return callback(*args, **kwargs)
    return new_callback
Taurus answered 22/5, 2020 at 3:56 Comment(3)
Great solution! Would you mind releasing that as a PyPI package?Allhallowtide
Thanks for your advice! My approach was indeed very simple and it just didn't occoured to me considering a multiprocess scenario. I guess I will follow @BenHagen's request and build a pypi package soon, taking into account multiprocessing stuff.Taurus
This Linux implementation has several issues. It would be better to use an inhibitor lock: systemd.io/INHIBITOR_LOCKSTucana
L
2

The logic in Keep.Awake will solve your problem on ubuntu or any Linux Distro running Gnome (old and new including Unity), works on both Wayland and X. It is easy to use.

I posted a solution to a similar question here: https://askubuntu.com/a/1231975/183131

So logic-wise do the following:

  1. Use DBus command via subprocess.Popen(...) to clear the sleep/suspend counter.
  2. Use psutil.cpu_percent() to query the the amount of cpu usage periodically or just put logic once your program is done doing its thing to re-set the sleep config.

You can view the code here for details or hints on how you can mod your code: https://launchpad.net/keep.awake

Alternatively you can just run keepawake.py on the Linux box you're running your cpu-intensive program on and it will solve your problem! It just works!

Example usage taken from the webpage:

To run as background service and set minimum CPU load as 13%:

nohup ./keepawake.py -c 13 -r > /dev/null 2>&1 &

To run as background service and set 15 min (900 sec) as the user activity idle time before it determines that the user is idle:

nohup ./keepawake.py -u 900 -r > /dev/null 2>&1 &

To run as background service and set minimum network traffic as 5KB (5120 bytes):

nohup ./keepawake.py -s 5120 -r > /dev/null 2>&1 &

To run as background service and set the schedule to sleep/suspend after 1 hour (this value is only set if user-activity, cpu, and network traffic are all determined to be idle) :

nohup ./keepawake.py -w 3600 -r > /dev/null 2>&1 &

To run all settings above (network, CPU, User idle, sleep schedule) in the one go and set the log-file path to "/home/$USER/sleep/log/Keep.Awake/" with detailed output:

nohup ./keepawake.py -s 5120 -c 13 -u 900 -w 3600 -l /home/$USER/sleep/log/Keep.Awake/ -v Detail -r > /dev/null 2>&1 &
Lulualaba answered 30/4, 2020 at 7:29 Comment(0)
S
2

This code is used to move mouse cursor after every n minutes to keep the system awake.

First install pyautogui for Python.

Run the following code:

import pyautogui
import time
import sys
from datetime import datetime
pyautogui.FAILSAFE = False
numMin = None
if ((len(sys.argv)<2) or sys.argv[1].isalpha() or int(sys.argv[1])<1):
    numMin = 2 # move cursor after numMin minutes
else:
    numMin = int(sys.argv[1])
while(True):
    x=0
    while(x<numMin):
        time.sleep(60)
        x+=1
    for i in range(0,50):
        pyautogui.moveTo(i*6+50,i*4)
    pyautogui.moveTo(1,1)
    for i in range(0,3):
        pyautogui.press("shift")
    print("Movement made at {}".format(datetime.now().time()))
Scopp answered 29/9, 2021 at 10:46 Comment(0)
P
0

You can also use Caffeine+, it's a tiny tray application that keeps the system awake without simulate keyboard events or interfering with the ui at all. https://enemydevelopment.com/software/caffeine

Phosphatase answered 3/7, 2022 at 2:21 Comment(1)
Stack Overflow is for programming questions. OP is asking how to do this programmatically, not as an end user.Dianadiandra
I
0

On Windows, not sure if this will help anyone, but the above didn't work for me. What finally worked was running 2nd process that just keeps calling "shutdown /a" (abort shutdown) every 30 sec. Windows says you have approx. ~1 min to do this so that's why the 30 seconds.

Totally stupid solution, but this is a pretty dumb problem to not have an os-provided solution anyway.

import subprocess
from time import sleep

def main():
    while(True):
        p = subprocess.Popen("shutdown /a", stdout=subprocess.PIPE, 
                             stderr=subprocess.PIPE)
        res = p.communicate()
        p.kill()
        sleep(30) # sleep 30 sec.

if __name__ == "__main__":
    main()
Imminence answered 15/7, 2022 at 18:21 Comment(0)
D
0

GUI Application to keep windows active


Python3

install library

pip install pywin32

save below code as alive.pyw file

from ctypes import windll, wintypes, byref, c_uint, sizeof, Structure
import tkinter as tk
import ctypes
import sys
import threading
import time
import win32api
import win32con


stop_threads = True
SET_IDLE_TIME = 40 #in seconds

class LASTINPUTINFO(Structure):
    _fields_ = [
        ('cbSize', c_uint),
        ('dwTime', c_uint),
    ]

def get_idle_duration():
    lastInputInfo = LASTINPUTINFO()
    lastInputInfo.cbSize = sizeof(lastInputInfo)
    windll.user32.GetLastInputInfo(byref(lastInputInfo))
    millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime
    return millis / 1000.0


def press_key_2():
    global stop_threads
    while True:
        if not stop_threads:
            break
        idle_time = get_idle_duration() #seconds
        time.sleep(0.1)
        if idle_time < SET_IDLE_TIME:
            continue

        print("in ideal state pressing cltr")
        win32api.keybd_event(ord('x'), 0, win32con.KEYEVENTF_EXTENDEDKEY, 0)


#---------------- Monitor threads ------------------------------

t1 = threading.Thread(target=press_key_2, name='t1')
t1.daemon = True

#----------------- TK functions ----------------------

def display_on():
    global tk, t1, stop_threads
    stop_threads = True
    print("Always On")
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
    root.iconify()
    t1.start()
    # t2.start()

def display_reset():
    print("quit pressed")
    global stop_threads
    stop_threads = False
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
    sys.exit(0)



root = tk.Tk()
root.geometry("200x110")
root.title("Display App")
frame = tk.Frame(root)
frame.pack()

var = tk.StringVar()
label = tk.Label(frame, textvariable =  var)#, bd = 5, justify = tk.RIGHT, padx = 10, pady = 10)
var.set("")
button = tk.Button(frame,
                   text="Quit",
                   fg="red",
                   command=display_reset)

slogan = tk.Button(frame,
                   text="Always ON",
                   command=display_on)

label.pack(side=tk.BOTTOM,padx=0, pady=0)
slogan.pack(side=tk.LEFT,padx=15, pady=20)
button.pack(side=tk.LEFT,padx=15, pady=20)

root.mainloop()
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
Dissyllable answered 7/9, 2022 at 11:21 Comment(0)
N
0

I've written this Python Code that doesn't only keep your screen active but also let's you work without disturbing you. Basically, You don't have to turn it on and off. You can keep it running and work at the same time -

Here's the python code - https://github.com/sudhanshuism/keepPCAliveUserEnabled

Naylor answered 18/7 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.