You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
2.9 KiB
Python

from dataclasses import dataclass
from pathlib import Path
from typing import Optional, Union
from enum import Enum, auto
@dataclass
class LedState:
r: Optional[int]
g: Optional[int]
b: Optional[int]
brightness: Optional[int]
autonomous: Optional[bool]
class LED:
def __init__(self, alias):
self.alias = alias
self.name = unalias(alias)
self.dir = Path('/sys/class/leds/'+self.name+'/')
@property
def state(self): -> LedState
with open(self.path/'color') as f:
r, g, b = [int(x) for x in r.read().strip().split()]
with open(self.path/'brightness') as f:
brightness = int(f.read.strip())
with open(self.path/'autonomous') as f:
autonomous = bool(f.read.strip())
return LedState(r=r, g=g, b=b, brightness=brightness, autonomous=autonomous)
def set(self, state: LedState):
# TODO: sanity check: when autonomous, no color or warn
# None means do not change value
old_state = self.state
for attr in ['r', 'g', 'b', 'brightness', 'autonomous']:
if getattr(state, attr) == None:
old_value = getattr(old_state, attr)
setattr(state, attr, old_value)
# Set it
with open(self.path/'color', 'w') as f:
f.write(f'{state.r} {state.g} {state.b}\n')
with open(self.path/'brightness', 'w') as f:
f.write(str(state.brightness)+'\n')
with open(self.path/'autonomous', 'w') as f:
f.write(str(int(state.autonomous))+'\n')
def unalias(s):
return 'omnia-led:' + s
def alias(s):
return s.removeprefix('omnia-led:')
class PatternFitting(Enum):
Repeat = auto()
Nearest = auto()
Linear = auto()
class LedStrip:
"Represents a line of LEDs"
def __init__(self, leds: Union[list[str], list[LED]]):
if all(isinstance(x, str) for x in leds):
leds = [LED(x) for x in leds]
self.leds = leds
def __len__(self):
return len(self.leds)
def __iter__(self):
return self.leds.__iter__()
@property
def pattern(self): -> list[LedState]
return [x.state for x in self.leds]
def setpattern(self, pat: list[LedState]):
if len(pat) != len(self):
raise ValueError('The pattern must be a one-to-one matching to LEDs')
for led, st in zip(self.leds, pat):
led.set(st)
def apply(self, pat: list[LedState], fit: PatternFitting):
"""Sets the strip to given pattern, which will be fit using selected algorithm.
Unlike setpattern, this first / always modifies the pattern to somehow fit to the given strip
"""
patl = len(pat)
strl = len(self)
if False: pass
elif fit == fit.Repeat:
# Repeat and/or chop
new_pat = (pat * ((strl // patl) + 1))[:strl]
elif fit == fit.Nearest:
quantum = patl/strl
indices = [round(quantum * i) for i in range(strl)]
new_pat = [pat[i] for i in indices]
elif fit == fit.Linear:
# Too complex
raise NotImplementedError('Please submit a pull request :-)')
self.setpattern(new_pat)
omnia_led_order = [
'user1',
'user2',
'lan0',
'lan1',
'lan2',
'lan3',
'lan4',
'wan',
'pci1',
'pci2',
'pci3',
'power',
]
OmniaStrip = LedStrip(omnia_led_order)