sxmo_suspend.sh: port to Python

This commit is contained in:
Colin 2023-10-22 09:36:08 +00:00
parent 3e8ad5b899
commit 88ea557cd5
2 changed files with 71 additions and 31 deletions

View File

@ -93,9 +93,9 @@ let
pkgs = [ "systemd" "xdg-user-dirs" ];
src = ./hooks;
};
suspend = pkgs.static-nix-shell.mkBash {
suspend = pkgs.static-nix-shell.mkPython3Bin {
pname = "sxmo_suspend.sh";
pkgs = [ "coreutils" "findutils" "gnugrep" "rtl8723cs-wowlan" "time" "util-linux" ];
pkgs = [ "rtl8723cs-wowlan" "util-linux" ];
src = ./hooks;
};
};

View File

@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p coreutils -p findutils -p gnugrep -p rtl8723cs-wowlan -p time -p util-linux
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p rtl8723cs-wowlan -p util-linux
# yeah, this isn't technically a hook, but the hook infrastructure isn't actually
# restricted to stuff that starts with sxmo_hook_ ...
@ -20,40 +20,80 @@
# common sources of wakelocks (which one may wish to reduce) include:
# - `sxmo_led.sh blink` (every 2s, by default)
suspend_time=300
import argparse
import logging
import subprocess
import time
# TODO: don't do this wowlan stuff every single time.
# - it's costly (can take like 1sec)
# - it seems to actually block suspension quite often
# - possibly rtl8723cs takes time to apply wowlan changes during which suspension is impossible
# alternative is to introduce some layer of cache:
# - do so in a way such that WiFi connection state changes invalidate the cache
# - because wowlan enable w/o connection may well behave differently than w/ connection
# - calculating IP addr from link, and then caching on the args we call our helper with may well suffice
doas rtl8723cs-wowlan enable-clean
# wake on ssh
doas rtl8723cs-wowlan tcp --dest-port 22 --dest-ip SELF
# wake on notification (ntfy/Universal Push)
doas rtl8723cs-wowlan tcp --source-port 2587 --dest-ip SELF
# wake if someone doesn't know how to route to us, because that could obstruct the above
# doas rtl8723cs-wowlan arp --dest-ip SELF
# specifically wake upon ARP request via the broadcast address.
# should in theory by covered by the above (TODO: remove this!), but for now hopefully helps wake-on-lan be more reliable?
doas rtl8723cs-wowlan arp --dest-ip SELF --dest-mac ff:ff:ff:ff:ff:ff
logger = logging.getLogger(__name__)
# TODO: wake for Dino (call) traffic
SUSPEND_TIME=300
echo "calling suspend for duration: $suspend_time"
class Executor:
def __init__(self, dry_run: bool = False):
self.dry_run = dry_run
time_start="$(date "+%s")"
irq_start="$(cat /proc/interrupts | grep 'rtw_wifi_gpio_wakeup' | tr -s ' ' | xargs echo | cut -d' ' -f 2)"
def exec(self, cmd: list[str], sudo: bool = False, check: bool = True):
if sudo:
cmd = [ 'doas' ] + cmd
rtcwake -m mem -s "$suspend_time" || exit 1
logger.debug(" ".join(cmd))
if self.dry_run:
return
irq_end="$(cat /proc/interrupts | grep 'rtw_wifi_gpio_wakeup' | tr -s ' ' | xargs echo | cut -d' ' -f 2)"
time_spent="$(( $(date "+%s") - time_start ))"
res = subprocess.run(cmd, capture_output=True)
logger.debug(res.stdout)
if res.stderr:
logger.warning(res.stderr)
if check:
res.check_returncode()
echo "suspended for $time_spent seconds. wifi IRQ count: ${irq_start} -> ${irq_end}"
def main():
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO)
sxmo_hook_postwake.sh
parser = argparse.ArgumentParser(description="suspend the pinephone to RAM, and configure wake triggers to make that appear more transparent")
parser.add_argument("--dry-run", action='store_true', help="print commands instead of executing them")
parser.add_argument("--verbose", action='store_true', help="log each command before executing")
args = parser.parse_args()
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG)
executor = Executor(dry_run=args.dry_run)
# TODO: don't do this wowlan stuff every single time.
# - it's costly (can take like 1sec)
# alternative is to introduce some layer of cache:
# - do so in a way such that WiFi connection state changes invalidate the cache
# - because wowlan enable w/o connection may well behave differently than w/ connection
# - calculating IP addr from link, and then caching on the args we call our helper with may well suffice
# and no need to invoke a subprocess here, when it's just python code calling other python code!
executor.exec(['rtl8723cs-wowlan', 'enable-clean'], sudo=True)
# wake on ssh
executor.exec(['rtl8723cs-wowlan', 'tcp', '--dest-port', '22', '--dest-ip', 'SELF'], sudo=True)
# wake on notification (ntfy/Universal Push)
# executor.exec(['rtl8723cs-wowlan', 'tcp', '--source-port', '2587', '--dest-ip', 'SELF'], sudo=True)
# wake if someone doesn't know how to route to us, because that could obstruct the above
# executor.exec(['rtl8723cs-wowlan', 'arp', '--dest-ip', 'SELF'], sudo=True)
# specifically wake upon ARP request via the broadcast address.
# should in theory by covered by the above (TODO: remove this!), but for now hopefully helps wake-on-lan be more reliable?
executor.exec(['rtl8723cs-wowlan', 'arp', '--dest-ip', 'SELF', '--dest-mac', 'ff:ff:ff:ff:ff:ff'], sudo=True)
logger.info(f"calling suspend for duration: {SUSPEND_TIME}")
time_start = time.time()
# irq_start="$(cat /proc/interrupts | grep 'rtw_wifi_gpio_wakeup' | tr -s ' ' | xargs echo | cut -d' ' -f 2)"
#
executor.exec(['rtcwake', '-m', 'mem', '-s', str(SUSPEND_TIME)], check=False)
# irq_end="$(cat /proc/interrupts | grep 'rtw_wifi_gpio_wakeup' | tr -s ' ' | xargs echo | cut -d' ' -f 2)"
time_spent = time.time() - time_start
logger.info(f"suspended for {time_spent:.0f} seconds")
executor.exec(['sxmo_hook_postwake.sh'], check=False)
if __name__ == '__main__':
main()