Created
December 11, 2020 21:48
-
-
Save plredmond/96473cdcdff5e7b6d0cf497dab17a102 to your computer and use it in GitHub Desktop.
easily adjust sources of wakeup from sleep in linux using a list of devices to enable/disable and an allow-list
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import csv,io | |
import argparse | |
import collections | |
class Wakeups: | |
status_prop = 'Status' | |
def __init__(self, path): | |
self.path = path | |
def parse(self): | |
with open(self.path, mode='r') as fd: | |
raw_lines = fd.readlines() | |
first, rest = raw_lines[0], raw_lines[1:] # uncons the header row | |
rest = list(map(str.split, rest)) # split each row into columns | |
cols = len(rest[0]) | |
assert all(cols == len(row) for row in rest), 'all rows have the same number of columns' | |
headers = collections.OrderedDict((key,index) for index, key in enumerate(first.strip().split(maxsplit=cols - 1))) # split header into correct number of columns | |
devices = collections.OrderedDict((row[headers['Device']],row) for row in rest) | |
return headers, devices | |
@property | |
def properties(self): | |
headers, _ = self.parse() | |
return list(headers.keys()) | |
@property | |
def devices(self): | |
_, devices = self.parse() | |
return list(devices.keys()) | |
def lookup(self, device, prop): | |
headers, devices = self.parse() | |
device_row = devices[device] | |
prop_offset = headers[prop] | |
return device_row[prop_offset] | |
def is_enabled(self, device): | |
return 'enabled' in self.lookup(device, self.status_prop).lower() | |
def is_disabled(self, device): | |
return 'disabled' in self.lookup(device, self.status_prop).lower() | |
def toggle(self, device): | |
assert device in self.devices, 'can only toggle existing devices' | |
with open(self.path, mode='w') as fd: | |
fd.write(device) | |
def enable(self, device): | |
self.is_disabled(device) and self.toggle(device) | |
def disable(self, device): | |
self.is_enabled(device) and self.toggle(device) | |
def pprint(self): | |
headers, devices = self.parse() | |
strfd = io.StringIO() | |
formatter = csv.DictWriter(strfd, fieldnames=headers.keys(), dialect=csv.excel_tab) | |
formatter.writeheader() | |
for dev in devices.values(): | |
formatter.writerow(collections.OrderedDict(zip(headers.keys(), dev))) | |
return strfd.getvalue() | |
def parse(argv): | |
ap = argparse.ArgumentParser(description='set kernel wakeup devices to a known state') | |
default = dict(wakeup='/proc/acpi/wakeup') | |
ap.add_argument('-w', '--wakeup', metavar='PATH', default=default['wakeup'], help=f'path to kernel wakeup file (default: {default["wakeup"]})') | |
ap.add_argument('-e', '--enable', nargs='+', metavar='DEV', default=list(), help='enable each device listed') | |
ap.add_argument('-d', '--disable', nargs='+', metavar='DEV', default=list(), help='disable each device listed') | |
ap.add_argument('--allow-list', nargs='+', metavar='DEV', default=list(), help='disable each device NOT listed (default: all devices except those in -d/--disable)', dest='allow') | |
return ap.parse_args(argv) | |
def main(opts): | |
wakeups = Wakeups(opts.wakeup) | |
all_devices = set(wakeups.devices) | |
opts.enable = set(opts.enable) | |
opts.disable = set(opts.disable) | |
opts.allow = set(opts.allow) or all_devices - opts.disable | |
print(opts) | |
# check error conditions | |
assert opts.enable.isdisjoint(opts.disable), f'devices in both --enable and --disable: {opts.enable & opts.disable}' | |
assert opts.allow.isdisjoint(opts.disable), f'devices in both --allow-list and --disable: {opts.allow & opts.disable}' | |
assert opts.enable <= opts.allow, f'devices in --enable but not in --allow-list: {opts.enable - opts.allow}' | |
# check more error conditions | |
assert opts.enable <= all_devices, f'devices in --enable do not exist: {opts.enable - set(wakeups.devices)}' | |
assert opts.disable <= all_devices, f'devices in --disable do not exist: {opts.disable - set(wakeups.devices)}' | |
# do things | |
for dev in opts.enable: | |
wakeups.enable(dev) | |
for dev in opts.disable | (all_devices - opts.allow): | |
wakeups.disable(dev) | |
print(wakeups.pprint()) | |
if __name__ == '__main__': | |
sys.exit(main(parse(sys.argv[1:]))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is an alternative to
echo LID0 | sudo tee /proc/acpi/wakeup
for use in scripting, because thetee
style adjustment only supports toggling. This script allows you to specify desired state and it will take care of parsing and setting things correctly.