feat: add configurable normal RGB effects

This commit is contained in:
way
2026-09-27 10:36:32 +08:00
parent 419d27b570
commit a8ca071b56
7 changed files with 122 additions and 19 deletions
+51 -4
View File
@@ -253,6 +253,20 @@ RGB_WRITE_DELAY_MS=max(1,cf("led","write_delay_ms",10,int))
WARNING_FLASH=(max(50,cf("led","warning_flash_on_ms",1500,int)),max(50,cf("led","warning_flash_off_ms",1500,int)))
CRITICAL_FLASH=(max(50,cf("led","critical_flash_on_ms",750,int)),max(50,cf("led","critical_flash_off_ms",750,int)))
EMERGENCY_FLASH=(max(50,cf("led","emergency_flash_on_ms",300,int)),max(50,cf("led","emergency_flash_off_ms",300,int)))
NORMAL_MODE=cf("led","normal_mode","off",str).strip().lower()
NORMAL_MODES={"off","solid","flash","flow","breathe","marquee","rainbow","colorful"}
if NORMAL_MODE not in NORMAL_MODES: NORMAL_MODE="off"
NORMAL_COLOR=tuple(max(0,min(255,cf("led",f"normal_{channel}",value,int)))
for channel,value in zip(("r","g","b"),(0,0,0)))
NORMAL_FLASH=(max(50,cf("led","normal_flash_on_ms",1000,int)),
max(50,cf("led","normal_flash_off_ms",1000,int)))
NORMAL_EFFECT_SPEED=max(1,min(3,cf("led","normal_effect_speed",2,int)))
NORMAL_EFFECT_COLOR=cf("led","normal_effect_color","green",str).strip().lower()
RGB_EFFECT_COLORS={"red":0,"green":1,"blue":2,"yellow":3,"purple":4,"cyan":5,"white":6}
if NORMAL_EFFECT_COLOR not in RGB_EFFECT_COLORS: NORMAL_EFFECT_COLOR="green"
RGB_EFFECTS={"flow":0,"breathe":1,"marquee":2,"rainbow":3,"colorful":4}
NORMAL_RGB_MODE={"off":"OFF","solid":"NORMAL_SOLID","flash":"NORMAL_FLASH",
**{name:f"NORMAL_{name.upper()}" for name in RGB_EFFECTS}}[NORMAL_MODE]
def rgb_cfg(name,default):
return tuple(max(0,min(255,cf("led",f"{name}_{channel}",value,int)))
@@ -441,6 +455,30 @@ def rgb_flash(mode,on):
mcu(0x03,channels[2])
_last_rgb=state
def rgb_static(channels,state_name):
global _last_rgb
state=(state_name,channels)
if _last_rgb==state: return
mcu(0x07,0x00); time.sleep(RGB_WRITE_DELAY_MS/1000.0)
mcu(0x00,0xff); time.sleep(RGB_WRITE_DELAY_MS/1000.0)
mcu(0x01,channels[0]); time.sleep(RGB_WRITE_DELAY_MS/1000.0)
mcu(0x02,channels[1]); time.sleep(RGB_WRITE_DELAY_MS/1000.0)
mcu(0x03,channels[2])
_last_rgb=state
def rgb_normal_effect(mode):
global _last_rgb
effect_name=mode.removeprefix("NORMAL_").lower()
state=("effect",effect_name,NORMAL_EFFECT_SPEED,NORMAL_EFFECT_COLOR)
if _last_rgb==state: return
# Seller protocol: close the previous RGB state, then set effect, speed and
# the limited built-in palette. Write this sequence once per mode change.
mcu(0x07,0x00); time.sleep(0.001)
mcu(0x04,RGB_EFFECTS[effect_name]); time.sleep(0.001)
mcu(0x05,NORMAL_EFFECT_SPEED); time.sleep(0.001)
mcu(0x06,RGB_EFFECT_COLORS[NORMAL_EFFECT_COLOR])
_last_rgb=state
def render_home(cpu,temp,mem,disk):
# 128x32 fixed columns. Both columns are LEFT-aligned.
# Seller 5x7 font has 6px character pitch; right column starts at x=72.
@@ -485,7 +523,7 @@ class DisplayController:
now=time.monotonic()
self.lock=threading.RLock()
self.requests={"NORMAL_HOME":{
"id":"NORMAL_HOME","priority":0,"severity":0,"rgb_mode":"OFF",
"id":"NORMAL_HOME","priority":0,"severity":0,"rgb_mode":NORMAL_RGB_MODE,
"title":"","l2":"","l3":"","l4":"","active":True,
"first_seen":now,"last_changed":now,"metadata":{"home":(0.0,0.0,0.0,0.0)},
}}
@@ -637,18 +675,27 @@ class DisplayController:
if wanted_mode!=applied_mode:
with bus_lock:
if wanted_mode=="OFF": rgb_off()
elif wanted_flash: rgb_flash(wanted_mode,True)
elif wanted_mode=="NORMAL_SOLID": rgb_static(NORMAL_COLOR,"normal_solid")
elif wanted_mode=="NORMAL_FLASH": rgb_static(NORMAL_COLOR,"normal_flash_on")
elif wanted_mode.startswith("NORMAL_"): rgb_normal_effect(wanted_mode)
elif wanted_flash:
rgb_off()
rgb_flash(wanted_mode,True)
else: raise ValueError(f"unsupported RGB mode: {wanted_mode}")
log("INFO","RGB_MODE",old=applied_mode,new=wanted_mode)
applied_mode=wanted_mode; animation_started=time.monotonic()
applied_flash=applied_mode.endswith("_FLASH")
if applied_flash:
elapsed_ms=(time.monotonic()-animation_started)*1000.0
if "_EMERGENCY_" in applied_mode: on_ms,off_ms=EMERGENCY_FLASH
if applied_mode=="NORMAL_FLASH": on_ms,off_ms=NORMAL_FLASH
elif "_EMERGENCY_" in applied_mode: on_ms,off_ms=EMERGENCY_FLASH
elif "_CRITICAL_" in applied_mode: on_ms,off_ms=CRITICAL_FLASH
else: on_ms,off_ms=WARNING_FLASH
on=elapsed_ms%(on_ms+off_ms)<on_ms
with bus_lock: rgb_flash(applied_mode,on)
with bus_lock:
if applied_mode=="NORMAL_FLASH":
rgb_static(NORMAL_COLOR,"normal_flash_on") if on else rgb_off()
else: rgb_flash(applied_mode,on)
if previous_error is not None: log("INFO","RGB_RECOVERED")
previous_error=None
except Exception as e: