Windows utility to override power requests blocking sleep/hibernate.
Project description
sleeper_service
Minor breaking v0.20.0 change The manual_suspend_after and check_interval options
in the config.toml configuration file are now in seconds rather than minutes - please
update your values if you use this feature!
This is a minimal Windows tray utility that enables (forces) sleep based on the active power plan "Sleep After" parameter.
For a long rant on why this exists, see the Package Rationale.
For the short version of why this exists, if you are looking for something/anything that deals with the "Legacy Kernel Caller" blocking sleep problem, hopefully this will work for you. In particular, if you have issues with Elgato Wave Link killing sleep, this is intended to help.
The v0.9 release provides a tray utility to trigger sleep or hibernate.
The v0.20 release supports restarting media playback on resume from suspend.
Beta: App/program Launch on Resume
v0.10.0 Beta functionality Use with caution. I have added a beta function that can (re-)launch apps/programs when resuming from a suspension triggered by sleeper_service (it does not work when sleep is triggered by the system or the start menu). This capability uses python's subprocess Popen to launch programs.
I've added this functionality because it allows me to manage issues in the Elgato Wave Link 3.0 beta. Specifically there are some people (myself included) who are having problems with Wave Link resuming from sleep properly. In my case, Wave Link either crashes (most of the time), or breaks mixes and/or channel/mix connections. I'm hoping that Elgato will address this issue as part of their beta.
In the interim, I'm using this function to restart Wave Link each time I resume from sleep (my examples in this section are for Wave Link). This is working well enough to allow me to use the beta. The one downside is that Wave Link will always open a foreground desktop window on resume, as the beta does not support opening minimised to the tray. I'm assuming this will be addressed towards the end of the beta. If not, I will tweak the restart functionality when the final version releases.
To set it up, run sleeper_service to create/update the settings file, then exit, and
edit the settings so that the [restarts] section of the config.toml file looks like:
[restarts]
"Elgato.Wavelink.exe" = "Popen"
In my case "Elgato.Wavelink.exe" is a system alias for starting the UWP Wave Link 3.0 app. Please replace this with your app name. Currently, "Popen" is the only launch mode suppported, so this is the only valid value. Finally, if you want to start more than one app on resume, just add another line per app.
Using my sample [restarts], Wave Link should restart after every resume triggered by
sleeper_service. As noted previously, manual or other automatic resumes will not
trigger this restart.
This functionality will work with program or app that:
- Can be launched with Popen call.
- Does not require admin privileges.
- Returns immediately from the Popen call.
This may be useful for other audio control apps that cause the "Legacy Kernel Caller" problem - e.g. Voicemeeter or SteelSeries Sonar (I haven't tested either of these, but I know it was an issue for older versions of Voicemeeter, and may still be?). If you do test this successfully with apps other than Wave Link, can you please add a comment to the end of this issue so that I can update the list of programs known to restart correctly.
If you have a program that you can't get to work with [restarts], please raise an
issue so that we can
address the problem.
We do have a live issue which may affect some programs/apps - any program/app restarted after sleep will have the same Windows "Current Directory" as the sleeper_service. This could be a problem if it relies on finding configuration or data files in the current directory. I'm treating this as a lower priority enhancement for a future release. If this is affecting you, please add a comment on this issue so that I know to make it a higher priority.
Change Log
- v0.20.1 Minor changes that (hopefully) eliminate double sleep events.
- v0.20.0 Added an option to restart media playback on resume from suspend. This is useful for media streams that pause after losing internet connectivity (e.g. Deezer, youtube).
- v0.11.0 Added an option to add a "Suspend now!" button to the tray menu for
testing. This can only be enabled by editing the
config.tomlsettings. - V0.10.0 Converted to .pyw app, added beta function to enable restarting Wave Link on resume from sleep.
- v0.9.0 Tray manager interface, core sleep functions implemented.
- v0.0.2 Functional beta. Still requires pystray wrapper.
- v0.0.1 Proof of concept.
Installation and Usage
sleeper_service is a system tray application for Windows. I'd recommend downloading the
zip file from the Release
page, unzipping and adding the executable to your start programs. However, if you
prefer, you can install via pip (pip install sleeper_service) and either create your
own pyinstaller bundle or run it from a local python installation or virtual
environment.
Right click on the sleeper_service icon to see the interface:
Clicking on Enabled will enable/disable the service. You can also enable/disable by
left clicking on the sleeper_service icon. The icon will have a red cross when disabled.
You can also switch between using the system timers and a manual timer specification.
The Suspend: and After: lines are information only to tell you what the suspend
action is and when it will be triggered.
Some media players automatically pause when the system is suspended, and will not
restart playing on resume from suspend (some like youtube will play out their buffer
and then pause). If you are like me, you will want your music to resume streaming
when you wake your PC. In which case, enabling Resume playback may sort your problem.
The playback resume works adequately for me, but does have a couple of wrinkles:
-
It uses the SMTC winrt API to check which apps were playing before suspending and will try to restart playback of these apps after resuming from suspend.
-
If your favourite media app doesn't support SMTC, it won't work. You may be able to sort this out with a plugin for your app (see this Modern Flyouts page for some hints, but unfortunately some older players just won't work.
-
The resume playback function is a bit brute force to work around player and Windows issues. Specifically, it waits a short period after resuming from suspend (
resume_playback_delaysetting) to ensure the system is up and running properly, and then performs the following actions for each app that was playing before suspend:- pauses the app because some media players have a status of "Playing" after resuming from suspend even though the stream is paused!
- Waits a short period.
- Restarts playback.
Please raise an issues if you have a media player that a) supports SMTC and b) does not resume playback correctly and I'll see what I can do to help.
-
The default settings work fine for my main player (Deezer), but may fail for apps that buffer significantly. For instance, youtube in Firefox may have a 10+ second buffer. With the default settings on my system, the player ignores the media commands until the buffer runs out (yeah, not great really!) and the player then stops/pauses. The work around is to increase
resume_playback_delayso that it is larger than the buffer, at which point the pause/wait/play action works correctly. For my system, a delay of 15-20 seconds works (irritating, but at least it works).
If you need to force suspend frequently for testing or other reasons, you can enable
a Suspend now(-ish)! button on the interface by editing the config.toml file and
setting suspend_button=true (this option is not available from the UI). When you hit
the button, the system will suspend at the end of the next check_interval (see
Configuration file).
There are a few other configuration parameters, but these only be changed by editing the configuration file - exit the service before editing.
(I'm assuming most of the parameters will be changed infrequently, so not worth including in the tray interface - Please raise an issue if you would prefer more parameters in the UI.)
Configuration file
The config.toml file provides manual configuration for sleeper_service. The location
of the file is determined in the following priority order.
- If the command line option
--config <file path>specifies a file, e service will use the named file. - If the command line option
--config <folder path>specifies a folder, the service will look forconfig.tomlin the specified folder path. - If the service is run from the pyinstaller bundle, it will look for
config.tomlin the same folder as the service executable. - If the service is run as a normal python routine, it will look for the fi
config.tomlin the current working directory.
If the file does not exist, it will be created.
The configuration file options are:
enabled:trueorfalse. Enable or disable the sleeper service. Switchable from the system tray interface. Useful if you want to turn it off for a while.user_system_timer:trueorfalse. Iftrue, the suspend timer and suspend state are read from the users Windows Power plan (Sleep afterandHibernate aftervalues, with the shorter timer assumed to apply). Iffalse, manually specified values are taken from the configuration file. . Switchable from the system tray interface.manual_suspend_after: time in seconds to activate suspend ifuse_system_timerisfalse. Values less than 60 seconds will be increased to 60 seconds automatically.manual_suspend_state: The suspend state to apply ifuse_system_timerisfalse. Allowable case sensitive values are: "sleep", "hibernate" or "disabled".check_interval: time in seconds that sleeper_service will sleep between checks that the idle time has expired (I'm assuming most people will be happy checking once a minute at most).resume_playback:trueorfalse. If true, sleeper service will try to check which apps were playing media before suspending and will try to resume playback after resuming from suspend.resume_playback_delay: How long sleeper service will wait after resuming from suspension before trying to restart playback. May be useful for players with long buffers that do not resume correctly. See Installation and Usage.suspend_button: whentrue, the tray menu includes a "Suspend now(-ish)!" button that will suspend the system at the end of the nextcheck_interval. Great for testing! Suspend was immediate in v0.11.0, but from v0.20.0 it is included in the event loop to ensure it correctly triggers things like resuming media playback. The button is not displayed iffalse.[restarts]: See Beta: App/program Launch on Resume.
The default configuration file is:
enabled = true
use_system_timer = true
manual_suspend_after = 600
manual_suspend_state = "sleep"
check_interval = 60
resume_playback = false
resume_playback_delay = 1
suspend_button = false
[restarts]
Package Rationale
This utility deals with the brain dead Windows implementation that allows an audio stream to block sleep. (Truly. It's genuinely stupid.)
Typical symptoms of this problem are:
- A call to powercfg /requests will include the lines:
[SYSTEM] An audio stream is currently in use. [DRIVER] Legacy Kernel Caller - Windows ignores sleep settings in the power plan (yeah, it's really this stupid).
- There are no easy fixes or overrides to address the problem.
I've run into this problem with Elgato's Wave Link software (which is the trigger for writing this utility), and it has been a problem with Voicemeeter in the past (not sure if this has been resolved in more recent versions), and plenty of other software that creates an audio stream.
A quick search brings a vast range of complaints about Microsoft's bone headed implementation, but little in the way of effective, simple solutions to the problem. In particular:
- Using
powercfg /requestsoverrideshould allow users to prevent theLegacy Kernel Callerfrom blocking sleep. This flat out doesn't work. (Even if it did, Microsoft has decreed that this particular powercfg call requires elevated privileges. For a user space problem. Did I mention bone headed?). - There are various solutions using AutoHotKey, Visual Basic Scripts, and the Windows task manager. All are a bit opaque.
So this is yet another solution to the problem which is hopefully be relatively fire and forget, and also easy to suspend for the times you actually do want an audio stream to block sleep (rarely in my experience).
Development/testing
This section is a collection of information that may be useful in developing/testing future functionality.
Powercfg Options
Some of these commands may require an elevated shell:
powercfg /hibernate on/offto enable or disable hibernate.powercfg /alists available sleep states for system (and also sleep states that are not available/enabled).
Sleep and Requests
Forcing sleep from the Windows menu or programmatically will clear sleep blocking
requests (powercfg /requests). Restarting audio streams seems to repair this when
required, so I'm not going to worry about this. (Ideally, Microsoft would fix the
underlying problem that audio streams should not have special privileges that block
sleep states).
PyInstaller Builds
If you are building your own binary, I suggest starting with a clean environment and install only sleeper_service and pyinstaller to minimise by-catch in the pyinstaller bundle.
TODO/In Progress
This section contains informal notes on pending implementation details and possible future fixes/extensions.
Implementation:
- Update module docs as development progresses.
- Maybe add option too keep awake if audio stream detected on specific devices.
- Make/ask for help with better icon. Best described as a bit rubbish at the moment.
Right now, wave link breaks things badly on resume from sleep. If Elgato don't fix this, each time we resume, we may need to:
- (best case) restart wave link. Currently in beta for the beta. Not ideal, as Wave Link does not restart minimised.
- check if wave link is active, kill and restart.
For finding and restarting Wave Link:
- Can get more info with get-appxpackage -Name Elgato.Wavelink and get-startapps
- If the final release doesn't fix problems in the beta, may need to kill the wave link process and restart - kill+psutils or taskkill?
- Finally, restart wave link with either qualified app name. subprocess.run("explorer shell:appsfolder\Elgato.WaveLink_g54w8ztgkx496!App")
- Or, even better: Wave Link has an app execution alias: "Elgato.WaveLink.exe", so
no need to find UWP name if this is active!
- So far, it looks like the easiest method to start this is with:
subprocess.Popen("Elgato.Wavelink.exe")
- So far, it looks like the easiest method to start this is with:
Other:
- Look into using pycaw to enable/disable microphones/inputs as a way to kill sleep blocking by powercfg requests. Specifically, using privacy & security setting for microphone. Maybe disabling device works as well. Neither sound like good solutions though.
- Assuming Elgato fix the resume problem, it may be enough to simply pause/play to reset audio. Or maybe trigger a Stream Deck call to enable/disable channel/mix connections?
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sleeper_service-0.20.1.tar.gz.
File metadata
- Download URL: sleeper_service-0.20.1.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d0926ecaf2bfb5b65dea924994177f322e75d1ff2059501135c156e361fb191
|
|
| MD5 |
666802ce055a49a94cddfbf18405c5e1
|
|
| BLAKE2b-256 |
24ef1af0039519052a11d5db1a12b33028885943b258fc38bb75c291cdb90bda
|
File details
Details for the file sleeper_service-0.20.1-py3-none-any.whl.
File metadata
- Download URL: sleeper_service-0.20.1-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1735fc7a47a13d55024cadd457e57b3ca184f75fcd6f0f6b795a1506d2a8aa05
|
|
| MD5 |
16766e67e88f0e5bec4d82715902000d
|
|
| BLAKE2b-256 |
ed2ed79e5b82a4be0841d53bbd5891c3d087da57afd2fa09e82ca3194f706999
|