diff --git a/sleepwalk b/sleepwalk index eb4071c..a87fb41 100644 --- a/sleepwalk +++ b/sleepwalk @@ -1,121 +1,191 @@ #!/bin/bash -SLEEP_SECS=600 -WAKE_SECS=30 +SLEEP_SECS_INIT=30 +SLEEP_SECS=$SLEEP_SECS_INIT +SLEEP_STEP=180 +SLEEP_MAX_SECS=600 +WAKE_SECS=35 LOCK_DIR="/tmp/sleepwalk" +CPU_STATE=1 + +set_cpu_offline() { + if [ $CPU_STATE -eq 1 ]; then + echo "Powering off all CPU cores except cpu0" + for i in $(seq 2); do + echo 0 > /sys/devices/system/cpu/cpu$i/online + done + CPU_STATE=0 + fi +} + +set_cpu_online() { + SLEEP_SECS=$SLEEP_SECS_INIT + if [ $CPU_STATE -eq 0 ]; then + echo "Powering on all CPU cores except cpu0" + for i in $(seq 2); do + echo 1 > /sys/devices/system/cpu/cpu$i/online + done + CPU_STATE=1 + fi +} start_deep_sleep() { - led_sleep - echo mem > /sys/power/state 2>/dev/null - return $? + led_sleep + + if [ $((SLEEP_SECS + $SLEEP_STEP)) -lt $SLEEP_MAX_SECS ]; then + SLEEP_SECS=$((SLEEP_SECS + SLEEP_STEP)) + else + SLEEP_SECS=$SLEEP_MAX_SECS + fi + + sleep 5 # Give some extra time for pending output data + + if [ can_suspend ]; then + echo mem > /sys/power/state 2>/dev/null + fi + + return $? } wait_for_notifications() { - secs=$WAKE_SECS - is_led_on=0 - while [ $secs -ge 0 ]; do - sleep 1 - if [ $is_led_on == 0 ]; then - led_wake - is_led_on=1 - else - led_disable - is_led_on=0 - fi + secs=$WAKE_SECS + is_led_on=0 + while [ $secs -ge 0 ]; do + sleep 1 + if [ $is_led_on == 0 ]; then + led_wake + is_led_on=1 + else + led_disable + is_led_on=0 + fi - if is_screen_on_or_inhibitor_active; then - break - fi - secs=$(($secs-1)) - done - led_disable + if is_screen_on; then + if is_charging; then + cpufreq-set -g conservative + else + cpufreq-set -g powersave + fi + set_cpu_online + break + fi + set_cpu_offline + secs=$(($secs-1)) + done + led_disable } schedule_wake_time() { - rtcwake -m no --date "+${SLEEP_SECS}s" 2>&1 >/dev/null + echo "Sleeping for ${SLEEP_SECS}s" + rtcwake -m no --date "+${SLEEP_SECS}s" 2>&1 >/dev/null } reset_wake_time() { - led_wake - > /sys/class/rtc/rtc0/wakealarm + led_wake + > /sys/class/rtc/rtc0/wakealarm } -is_screen_on_or_inhibitor_active() { - INHIBITORS=$(systemd-inhibit --list --no-legend \ - | grep -e '[[:space:]]sleep[[:space:]]' \ - | grep -e 'lock$') +is_charging() { + [ "$(cat /sys/class/power_supply/axp20x-usb/online)" = "1" ] +} - if [ "$INHIBITORS" != "" ]; then - return 0 - fi +is_inhibitor_active() { + # INHIBITORS=$(sudo -u "$(cat /proc/$(pidof -s gnome-session-ctl)/environ | grep -z USER | sed 's,\x0,,;s,USER=,,')" DBUS_SESSION_BUS_ADDRESS=$(cat /proc/$(pidof -s gnome-session-ctl)/environ | grep -z DBUS_SESSION_BUS_ADDRESS | sed "s,\x0,,;s,DBUS_SESSION_BUS_ADDRESS=,,") gnome-session-inhibit --list) + # printf "%s\n" "$INHIBITORS" + INHIBITORS=$(systemd-inhibit --list --what=sleep --mode=block --no-legend \ + | grep -e 'sleep') - return "$(cat /sys/class/backlight/backlight/bl_power)" + [ -n "$INHIBITORS" ] + # if [ "$INHIBITORS" = "No inhibitors" ]; then + # return 1 + # fi + + # return 0 +} + +is_screen_on() { + return "$(cat /sys/class/backlight/backlight/bl_power)" +} + +can_suspend() { + ! ( is_inhibitor_active || is_screen_on || is_charging ) } led_sleep() { - echo 1 > /sys/class/leds/green\:indicator/brightness - echo 0 > /sys/class/leds/red\:indicator/brightness - echo 0 > /sys/class/leds/blue\:indicator/brightness + : + # echo 1 > /sys/class/leds/green\:indicator/brightness + # echo 0 > /sys/class/leds/red\:indicator/brightness + # echo 0 > /sys/class/leds/blue\:indicator/brightness } led_wake() { - echo 0 > /sys/class/leds/green\:indicator/brightness - echo 1 > /sys/class/leds/red\:indicator/brightness - echo 0 > /sys/class/leds/blue\:indicator/brightness + : + # echo 0 > /sys/class/leds/green\:indicator/brightness + # echo 1 > /sys/class/leds/red\:indicator/brightness + # echo 0 > /sys/class/leds/blue\:indicator/brightness } led_disable() { - echo 0 > /sys/class/leds/green\:indicator/brightness - echo 0 > /sys/class/leds/red\:indicator/brightness - echo 0 > /sys/class/leds/blue\:indicator/brightness + : + # echo 0 > /sys/class/leds/green\:indicator/brightness + # echo 0 > /sys/class/leds/red\:indicator/brightness + # echo 0 > /sys/class/leds/blue\:indicator/brightness } if [ $EUID -ne 0 ]; then - echo "Needs root" >&2 - exit 1 + echo "Needs root" >&2 + exit 1 fi if [ -z "$1" ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then - cat <<-EOF >&2 - Usage: sleepwalk [start/stop] - Commands: - start Start sleep cycle - stop Stop sleep cycle - EOF - exit + cat <<-EOF >&2 + Usage: sleepwalk [start/stop] + Commands: + start Start sleep cycle + stop Stop sleep cycle +EOF + exit fi if [ "$1" == "start" ]; then - if [ -d "$LOCK_DIR" ] || ! mkdir "$LOCK_DIR"; then - echo "sleepwalk is already running - run 'sleepwalk stop' to stop it" >&2 - exit 1 - fi - trap "$0 stop" EXIT + if [ -d "$LOCK_DIR" ] || ! mkdir "$LOCK_DIR"; then + echo "sleepwalk is already running - run 'sleepwalk stop' to stop it" >&2 + exit 1 + fi + trap "$0 stop" EXIT - while [ -d "$LOCK_DIR" ]; do - while is_screen_on_or_inhibitor_active; do - sleep 60 - done + while [ -d "$LOCK_DIR" ]; do + while ! can_suspend; do + set_cpu_online - reset_wake_time - schedule_wake_time - - while ! start_deep_sleep; do - reset_wake_time - echo "Failed going to sleep, try again in $WAKE_SECS seconds ..." >&2 - wait_for_notifications - schedule_wake_time - if is_screen_on_or_inhibitor_active; then - break + if is_charging && is_screen_on; then + cpufreq-set -g conservative + else + cpufreq-set -g powersave fi - done - wait_for_notifications - done + + sleep 10 + done + + reset_wake_time + schedule_wake_time + + while ! start_deep_sleep; do + reset_wake_time + echo "Failed going to sleep, try again in $WAKE_SECS seconds ..." >&2 + wait_for_notifications + schedule_wake_time + if ! can_suspend; then + break + fi + done + wait_for_notifications + done elif [ "$1" == "stop" ]; then - reset_wake_time - led_disable - rmdir "$LOCK_DIR" 2>/dev/null + reset_wake_time + led_disable + rmdir "$LOCK_DIR" 2>/dev/null else - echo "Unknown command: $1" >&2 - exit 1 + echo "Unknown command: $1" >&2 + exit 1 fi