Last active
July 22, 2024 21:00
-
-
Save ranisalt/d83db5ecda9c6738e182ad34e259f7ef to your computer and use it in GitHub Desktop.
Cerberus, a Hades Canyon companion
This file contains hidden or 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
import logging | |
import sys | |
from argparse import ArgumentParser, ArgumentTypeError | |
from string import hexdigits | |
from typing import Tuple | |
# CSS3 COLORS | |
COLOR_NAMES = { | |
'aliceblue': '#f0f8ff', | |
'antiquewhite': '#faebd7', | |
'aqua': '#00ffff', | |
'aquamarine': '#7fffd4', | |
'azure': '#f0ffff', | |
'beige': '#f5f5dc', | |
'bisque': '#ffe4c4', | |
'black': '#000000', | |
'blanchedalmond': '#ffebcd', | |
'blue': '#0000ff', | |
'blueviolet': '#8a2be2', | |
'brown': '#a52a2a', | |
'burlywood': '#deb887', | |
'cadetblue': '#5f9ea0', | |
'chartreuse': '#7fff00', | |
'chocolate': '#d2691e', | |
'coral': '#ff7f50', | |
'cornflowerblue': '#6495ed', | |
'cornsilk': '#fff8dc', | |
'crimson': '#dc143c', | |
'cyan': '#00ffff', | |
'darkblue': '#00008b', | |
'darkcyan': '#008b8b', | |
'darkgoldenrod': '#b8860b', | |
'darkgray': '#a9a9a9', | |
'darkgrey': '#a9a9a9', | |
'darkgreen': '#006400', | |
'darkkhaki': '#bdb76b', | |
'darkmagenta': '#8b008b', | |
'darkolivegreen': '#556b2f', | |
'darkorange': '#ff8c00', | |
'darkorchid': '#9932cc', | |
'darkred': '#8b0000', | |
'darksalmon': '#e9967a', | |
'darkseagreen': '#8fbc8f', | |
'darkslateblue': '#483d8b', | |
'darkslategray': '#2f4f4f', | |
'darkslategrey': '#2f4f4f', | |
'darkturquoise': '#00ced1', | |
'darkviolet': '#9400d3', | |
'deeppink': '#ff1493', | |
'deepskyblue': '#00bfff', | |
'dimgray': '#696969', | |
'dimgrey': '#696969', | |
'dodgerblue': '#1e90ff', | |
'firebrick': '#b22222', | |
'floralwhite': '#fffaf0', | |
'forestgreen': '#228b22', | |
'fuchsia': '#ff00ff', | |
'gainsboro': '#dcdcdc', | |
'ghostwhite': '#f8f8ff', | |
'gold': '#ffd700', | |
'goldenrod': '#daa520', | |
'gray': '#808080', | |
'grey': '#808080', | |
'green': '#008000', | |
'greenyellow': '#adff2f', | |
'honeydew': '#f0fff0', | |
'hotpink': '#ff69b4', | |
'indianred': '#cd5c5c', | |
'indigo': '#4b0082', | |
'ivory': '#fffff0', | |
'khaki': '#f0e68c', | |
'lavender': '#e6e6fa', | |
'lavenderblush': '#fff0f5', | |
'lawngreen': '#7cfc00', | |
'lemonchiffon': '#fffacd', | |
'lightblue': '#add8e6', | |
'lightcoral': '#f08080', | |
'lightcyan': '#e0ffff', | |
'lightgoldenrodyellow': '#fafad2', | |
'lightgray': '#d3d3d3', | |
'lightgrey': '#d3d3d3', | |
'lightgreen': '#90ee90', | |
'lightpink': '#ffb6c1', | |
'lightsalmon': '#ffa07a', | |
'lightseagreen': '#20b2aa', | |
'lightskyblue': '#87cefa', | |
'lightslategray': '#778899', | |
'lightslategrey': '#778899', | |
'lightsteelblue': '#b0c4de', | |
'lightyellow': '#ffffe0', | |
'lime': '#00ff00', | |
'limegreen': '#32cd32', | |
'linen': '#faf0e6', | |
'magenta': '#ff00ff', | |
'maroon': '#800000', | |
'mediumaquamarine': '#66cdaa', | |
'mediumblue': '#0000cd', | |
'mediumorchid': '#ba55d3', | |
'mediumpurple': '#9370db', | |
'mediumseagreen': '#3cb371', | |
'mediumslateblue': '#7b68ee', | |
'mediumspringgreen': '#00fa9a', | |
'mediumturquoise': '#48d1cc', | |
'mediumvioletred': '#c71585', | |
'midnightblue': '#191970', | |
'mintcream': '#f5fffa', | |
'mistyrose': '#ffe4e1', | |
'moccasin': '#ffe4b5', | |
'navajowhite': '#ffdead', | |
'navy': '#000080', | |
'oldlace': '#fdf5e6', | |
'olive': '#808000', | |
'olivedrab': '#6b8e23', | |
'orange': '#ffa500', | |
'orangered': '#ff4500', | |
'orchid': '#da70d6', | |
'palegoldenrod': '#eee8aa', | |
'palegreen': '#98fb98', | |
'paleturquoise': '#afeeee', | |
'palevioletred': '#db7093', | |
'papayawhip': '#ffefd5', | |
'peachpuff': '#ffdab9', | |
'per': '#cd853f', | |
'pink': '#ffc0cb', | |
'plum': '#dda0dd', | |
'powderblue': '#b0e0e6', | |
'purple': '#800080', | |
'red': '#ff0000', | |
'rosybrown': '#bc8f8f', | |
'royalblue': '#4169e1', | |
'saddlebrown': '#8b4513', | |
'salmon': '#fa8072', | |
'sandybrown': '#f4a460', | |
'seagreen': '#2e8b57', | |
'seashell': '#fff5ee', | |
'sienna': '#a0522d', | |
'silver': '#c0c0c0', | |
'skyblue': '#87ceeb', | |
'slateblue': '#6a5acd', | |
'slategray': '#708090', | |
'slategrey': '#708090', | |
'snow': '#fffafa', | |
'springgreen': '#00ff7f', | |
'steelblue': '#4682b4', | |
'tan': '#d2b48c', | |
'teal': '#008080', | |
'thistle': '#d8bfd8', | |
'tomato': '#ff6347', | |
'turquoise': '#40e0d0', | |
'violet': '#ee82ee', | |
'wheat': '#f5deb3', | |
'white': '#ffffff', | |
'whitesmoke': '#f5f5f5', | |
'yellow': '#ffff00', | |
'yellowgreen': '#9acd32', | |
} | |
def hex2rgb(value: str) -> Tuple[int, int, int]: | |
value = COLOR_NAMES.get(value, value).lstrip('#') | |
if len(value) == 3: | |
value = ''.join(s * 2 for s in value) | |
if len(value) != 6 or any(c not in hexdigits for c in value): | |
raise ArgumentTypeError(f'{value} is not a valid hex color value') | |
rgb = int(value, 16) | |
return (rgb >> 16, rgb >> 8 & 0xff, rgb & 0xff) | |
PROCFILE = '/proc/acpi/nuc_led' | |
HDD_BEHAVIORS = { | |
'off': 0, | |
'on': 1, | |
} | |
INDICATION_SCHEMES = { | |
'gradient': 0, | |
'fixed': 1, | |
} | |
BLINKING_BEHAVIORS = { | |
'solid': 0, | |
'breathing': 1, | |
'pulsing': 2, | |
'strobing': 3, | |
} | |
INDICATORS = { | |
'power', | |
'hdd', | |
'ethernet', | |
'wifi', | |
'software', | |
'powerlimit', | |
# 'disable', | |
} | |
POWER_STATES = { | |
's0': 0, | |
's3': 1, | |
's4': 2, | |
's5': 3, | |
} | |
TYPES = { | |
'power': 0, | |
'hdd': 1, | |
'skull': 2, | |
'eyes': 3, | |
'front1': 4, | |
'front2': 5, | |
'front3': 6, | |
} | |
def main(): | |
parser = ArgumentParser() | |
parser.add_argument('-d', '--dry-run', action='store_true') | |
parser.add_argument('--indicator', choices=INDICATORS, required=True) | |
parser.add_argument('--power-state', choices=POWER_STATES, default='s0') | |
parser.add_argument('--type', choices=TYPES, required=True) | |
power = parser.add_mutually_exclusive_group() | |
power.add_argument('--brightness', choices=range(100), | |
type=int, metavar='[0-100]') | |
power.add_argument('--behavior', choices=[ | |
*HDD_BEHAVIORS.keys(), *BLINKING_BEHAVIORS.keys(), | |
]) | |
power.add_argument('--frequency', choices=range(10), | |
type=int, metavar='[1-10]') | |
power.add_argument( | |
'--color', metavar='#rrggbb or color name', type=hex2rgb) | |
power.add_argument('--scheme', choices=INDICATION_SCHEMES) | |
args = parser.parse_args() | |
type_ = TYPES[args.type] | |
with sys.stdout if args.dry_run else open(PROCFILE, 'w', 1) as proc: | |
def set_indicator_value(indicator: int, control: int, value: int): | |
cmd = f'set_indicator_value,{type_},{indicator},{control},{value}\n' | |
proc.write(cmd) | |
if args.indicator == 'power': | |
offset = POWER_STATES[args.power_state] * 6 | |
if args.brightness is not None: | |
set_indicator_value(0, offset, args.brightness) | |
elif args.behavior: | |
set_indicator_value( | |
0, offset + 1, BLINKING_BEHAVIORS[args.behavior]) | |
elif args.frequency is not None: | |
set_indicator_value(0, offset + 2, args.frequency) | |
elif args.color is not None: | |
red, green, blue = args.color | |
set_indicator_value(0, offset + 3, red) | |
set_indicator_value(0, offset + 4, green) | |
set_indicator_value(0, offset + 5, blue) | |
else: | |
logging.warning('No valid action for power indicator!') | |
elif args.indicator == 'hdd': | |
if args.brightness is not None: | |
set_indicator_value(1, 0, args.brightness) | |
elif args.color: | |
red, green, blue = args.color | |
set_indicator_value(1, 1, red) | |
set_indicator_value(1, 2, green) | |
set_indicator_value(1, 3, blue) | |
elif args.behavior: | |
set_indicator_value(1, 4, HDD_BEHAVIORS[args.behavior]) | |
else: | |
logging.warning('No valid action for hdd indicator!') | |
elif args.indicator == 'ethernet': | |
if args.brightness is not None: | |
set_indicator_value(2, 0, args.brightness) | |
elif args.color: | |
red, green, blue = args.color | |
set_indicator_value(2, 1, red) | |
set_indicator_value(2, 2, green) | |
set_indicator_value(2, 3, blue) | |
elif args.behavior: | |
set_indicator_value(2, 4, HDD_BEHAVIORS[args.behavior]) | |
else: | |
logging.warning('No valid action for ethernet indicator!') | |
elif args.indicator == 'wifi': | |
if args.brightness is not None: | |
set_indicator_value(3, 0, args.brightness) | |
elif args.color: | |
red, green, blue = args.color | |
set_indicator_value(3, 1, red) | |
set_indicator_value(3, 2, green) | |
set_indicator_value(3, 3, blue) | |
else: | |
logging.warning('No valid action for wifi indicator!') | |
elif args.indicator == 'software': | |
if args.brightness is not None: | |
set_indicator_value(4, 0, args.brightness) | |
elif args.behavior: | |
set_indicator_value(4, 1, BLINKING_BEHAVIORS[args.behavior]) | |
elif args.frequency is not None: | |
set_indicator_value(4, 2, args.frequency) | |
elif args.color: | |
red, green, blue = args.color | |
set_indicator_value(4, 3, red) | |
set_indicator_value(4, 4, green) | |
set_indicator_value(4, 5, blue) | |
else: | |
logging.warning('No valid action for software indicator!') | |
elif args.indicator == 'powerlimit': | |
if args.scheme: | |
set_indicator_value(5, 0, INDICATION_SCHEMES[args.scheme]) | |
elif args.brightness is not None: | |
set_indicator_value(5, 1, args.brightness) | |
elif args.color: | |
red, green, blue = args.color | |
set_indicator_value(5, 2, red) | |
set_indicator_value(5, 3, green) | |
set_indicator_value(5, 4, blue) | |
else: | |
logging.warning('No valid action for powerlimit indicator!') | |
# elif args.indicator == 'disable': | |
# set_indicator_value(6, 0, 1) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@docop I don't have the device for 4+ years now, but you should be able to get usage information by running
python <script.py> --help
It can control all the leds, including the skull on top