SLEEP support development for CM4

Make a file shutdown.sh I have the file in ~/documents/ with the following

#!/bin/bash
shutdown now

Make shutdown.sh executable.


Then in the start menu select preferences, then main menu editor. On the right side select new item and point it to the script, name it, and select an icon if you want.

1 Like

Thank you! Didn’t know it can be done via GUI

1 Like

At the risk of exposing my lack of understanding, but how does one escape qsleep.sh once initiated? I did not want to replace the shutdown command so I tried just running qsleep.sh from the cli and was then unable to wake up the system.

The script works by cycle execute -> sleep - execute -> wake, so you need to find any way (like mapping any button/combo) to execute qsleep.sh, and it will sleep and wake up.

1 Like

Thank you! So, I guess the power button is the easiest way, then.

First post here. Just wanted to say thanks for starting the script. This has helped my workflow tremendously!

As for how to bind the script directly to power button, there are different instructions depending on which manager you’re on. For Wayfire:

mousepad $WAYFIRE_CONFIG_FILE

Then add the following 2 lines:

binding_power=KEY_POWER
command_power=%INSERT_PATH_TO_YOUR_QSLEEP_SCRIPT_HERE%

So for example, mine is:

binding_power=KEY_POWER
command_power=~/.config/qsleep.sh

Don’t touch lxde-pi-shutdown-helper and your logout menu should still be functional.

For labwc, the instructions will be different. I have not upgraded yet so I have not looked into it, but according to documentation, they mentioned creating a file at ~/.config/labwc/rc.xml and then adding a <keybind> entry to it like so:

<?xml version="1.0" ?>
<labwc_config>

  <keyboard>
    <default />
    <keybind key="W-d"><action name="Execute" command="sakura" /></keybind>
    <keybind key="W-z"><action name="Execute" command="wofi --show drun" /></keybind>
  </keyboard>

</labwc_config>

So if you are on labwc, I would start there.

If you would like to map to something other than power key, running this in a terminal will tell you what code to use with Wayfire so it’s very straightforward:

libinput debug-events --show-keycodes
1 Like

My pondering on this while I await my uConsole arrival to experiment on is… is there a way to map a long press = shutdown menu, short press = enter sleep? I suspect it will have to be done in the script that is called in response to the power button press as I am assuming there are not different software events generated for short vs long press, noting there is of course the firmware response to a very long press!

So I guess I figured out how to map Power button in labwc, too. Just did the upgrade this morning.

Edit ~/.config/labwc/rc.xml and make sure the content is something like…:

<?xml version='1.0' encoding='UTF-8'?>
<labwc_config>
  <keyboard>
    ...other key bindings may exist for say the volume/brightness OSD
    <keybind key="XF86_PowerOff">
      <action name="Execute" command="~/.config/qsleep.sh" />
    </keybind>
  </keyboard>
</labwc_config>

So no need to replace lxde-pi-shutdown-helper on labwc. This will bind the power button directly to qsleep.sh.

Also I added one small thing to qsleep.sh script:

# Stop all current running processes except for vital ones
# any other process that needs to be whitelisted can be put in this list
ps -U $USER | egrep -v "systemd|pipewire|wireplumber|wayfire|labwc|ssh|qsleep" | awk '{print $1}' | while read pid
do
  kill -STOP $pid
done

# And then add this to wakeup block
kill -CONT -1

The above modification will allow any currently running process like say… a video, music, some game, an emulator, etc… to pause execution until qsleep.sh is executed again. Thus it makes qsleep.sh basically indistinguishable from real sleep to me since it does pause a video I’m looking at and resumes right away. But be careful with turning off display/GPU since that may cause some processes to crash upon resume.

Didn’t seem to improve “sleep” time by much but it does mean I can pause a running game and pick up right where I left off. Also has the added benefit of basically locking the current foreground process so keyboard/mouse inputs won’t do much.

1 Like

Works as advertised. Now I have lxde-pi-shutdown-helper back and don’t need two extra menu entries.

Could you post your final qsleep.sh? I wasn’t sure which part to replace from the original.

Here you go. I have tested this extensively the past day or so (while playing games/emulators/music/Youtube, etc…) to make sure. It includes all of the above and I simplified some extra steps since we can make some assumptions:

#!/bin/bash
# sudo apt install cpulimit sysstat wlr-randr procps

# Add any process that needs to run in background during "sleep"
EXCLUDED_PROCS="systemd|pipewire|wireplumber|wayfire|labwc|ssh|qsleep"
# Governor to use after waking up
CPU_GOVERNOR="performance" # make sure this is set on startup elsewhere

if [ "$(cat /sys/class/drm/card1-DSI-1/enabled)" = "enabled" ]

# Display being off assumes device is sleeping
then
  # Put CPU into powersave
  echo "powersave" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
  
  # Turn off display
  wlr-randr --output DSI-1 --off
  
  # Stop all current running processes
  ps -U $USER | egrep -v $EXCLUDED_PROCS | awk '{print $1}' | while read pid
  do
    kill -STOP $pid
  done
  
  # Put all CPU-heavy processes to sleep, progressively re-checking every 60 seconds
  nohup bash -c '
  while true;
  do 
    for pid in $(pidstat 1 1 | grep "^Average:" | awk "BEGIN {FS=\"[[:space:]]+\"} \$8 > 5 {print \$3}");
    do 
      cpulimit -z -b -l 1 --pid=$pid; 
    done; 
    exec -a qsleep_bg sleep 60; 
  done' > /dev/null 2>&1 &
  disown
  
# Otherwise display being on means device needs to be put to sleep
else
  # Wake up CPU first to make process more responsive
  echo $CPU_GOVERNOR | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
  
  # Turn on display and apply rotation (needed by Wayfire)
  wlr-randr --output DSI-1 --on --transform 270

  # Resume all stopped processes
  kill -CONT -1
  
  # Clean up previous scripts
  killall pidstat
  killall cpulimit
  pkill -f qsleep_bg
  killall qsleep.sh
  
fi

exit 1

This is usable either with wayfire or labwc. I would recommend wayfire if your workflow involves fullscreen applications, as the current version of labwc shipped with Bookworm does not seem to work well with fullscreen applications. I think we will see an improvement once we upgrade labwc to latest version, which does support fullscreen applications properly.

To use with wayfire, edit ~/.config/wayfire.ini and add the following under [command] block:

binding_power=KEY_POWER
command_power=~/.config/qsleep.sh

I put my qsleep.sh script under ~/.config but it doesn’t have to be there specifically.

To use with labwc, edit ~/.config/labwc/rc.xml and add the <keybind> block below. Please note that you may want to keep to a similar structure if your file is empty:

<?xml version='1.0' encoding='UTF-8'?>
<labwc_config>
  <keyboard>
    ...other key bindings may exist for say the volume/brightness OSD
    <keybind key="XF86_PowerOff">
      <action name="Execute" command="~/.config/qsleep.sh" />
    </keybind>
  </keyboard>
</labwc_config>

Both of the above configurations can exist at the same time and you can freely switch between wayfire and labwc easily using raspi-config, so just pick whichever one fits your needs.

2 Likes

Thanks for this! I was thinking about stopping, but never got to create a comprehensive list of apps that better be stopped vs. throttle’d, and I got particularly stuck at having gmail open and another tab playing youtube and wanting to stop youtube but not gmail

Otherwise, we should maintain a list of essential apps

Long press will be tricky. As far as I understand, current pipeline does not support separation between power button keyup and down. Also, if we want to retain the smartphoney-feel, we need to react to keydown, and then cancel and invoke power menu if keyup was delayed.

This had crossed my mind but TBH I don’t think my smartphone reacts to power button key down to invoke sleep state. The separation between short and long press feels to be very short, maybe 250ms to a max 500ms. It is so short it could be making me feel it is reacting to key down while in truth reacting to key up to invoke sleep!. It certainly doesn’t start to sleep between pressing the power key and the shutdown menu appearing. They could all be different of course!

When I get my uConsole I will have a play and see if I can get something functioning that tests if the power button key down is still active/down, if that is a possibility?. If after a window, let’s say 250ms but a configurable parameter would be best here, the power button key is still down it brings up the shutdown menu, else sleeps.

I was thinking to test multiple times for absence of power button key up within the window to make the reaction feel even more natural/snappy and like a reaction to power button key up.

Might I ask if there is a smooth way of mapping the power button in X.org/lxde? I tried replacing “Logout=lxde-pi-shutdown-helper” with “Logout=qsleep.sh” but pressing PWR still brought up the shutdown helper.

I’m reading limitcpu is the successor to cpulimit. Thoughts?

We need to check if cgroups are usable on shipped kernels. Because if they are, none of cpulimit* are required, and having the modern kernel to limit process will be significantly smoother and use even less energy than a userspace app. Otherwise, there is really nothing to fix or maintain in cpulimit as it is using a UNIX process sleep (SIGSTOP) method from 1970’s.

1 Like

Guess there is a good reason to request for updated kernels, then. Or modded ones.