Skip to main content

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.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.toml settings.
  • 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:

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_delay setting) 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_delay so 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 for config.toml in the specified folder path.
  • If the service is run from the pyinstaller bundle, it will look for config.toml in the same folder as the service executable.
  • If the service is run as a normal python routine, it will look for the ficonfig.toml in the current working directory.

If the file does not exist, it will be created.

The configuration file options are:

  • enabled: true or false. 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: true or false. If true, the suspend timer and suspend state are read from the users Windows Power plan (Sleep after and Hibernate after values, with the shorter timer assumed to apply). If false, manually specified values are taken from the configuration file. . Switchable from the system tray interface.
  • manual_suspend_after: time in seconds to activate suspend if use_system_timer is false. Values less than 60 seconds will be increased to 60 seconds automatically.
  • manual_suspend_state: The suspend state to apply if use_system_timer is false. 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: true or false. 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: when true, the tray menu includes a "Suspend now(-ish)!" button that will suspend the system at the end of the next check_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 if false.
  • [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 /requestsoverride should allow users to prevent the Legacy Kernel Caller from 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/off to enable or disable hibernate.
  • powercfg /a lists 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")

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

sleeper_service-0.20.0.tar.gz (24.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sleeper_service-0.20.0-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file sleeper_service-0.20.0.tar.gz.

File metadata

  • Download URL: sleeper_service-0.20.0.tar.gz
  • Upload date:
  • Size: 24.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for sleeper_service-0.20.0.tar.gz
Algorithm Hash digest
SHA256 b0f702db991e46bf9810fdbdbc4fc2c74b18e09a1a93aaafaa19f66f0aecf271
MD5 9e88db1a5430c19e4e39a3c183303201
BLAKE2b-256 5ae61b37e1a78735b4c79638e319de367599b219a2842a34fcf65e6e3f03574d

See more details on using hashes here.

File details

Details for the file sleeper_service-0.20.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sleeper_service-0.20.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6031b3d510c58a69081864c989359f0310914d1616bfe83904dfa52b03331e14
MD5 45950fa44a2837a6570cbd6f21c0fa92
BLAKE2b-256 9f4166a5360482c5dcd776febca96c665deac3299fdce46bd803157b5c77f4ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page