feat: configure RGB colors and flash timing
This commit is contained in:
@@ -73,7 +73,7 @@ CHECK STORAGE
|
||||
|
||||
### 5. RGB 告警引擎
|
||||
|
||||
RGB 模式由当前 OLED 告警页决定;OLED 位于主页时则使用最高优先级 active owner。颜色表示故障对象:CPU负载、频率、throttling、温度与散热相关为红色,供电/欠压为橙色,内存为紫色,存储为白色,网络/Wi-Fi 为蓝色,服务/进程为青色。频率表示严重等级:Warning 为1500ms亮/1500ms灭,Critical 为750ms亮/750ms灭,Emergency 为300ms亮/300ms灭;没有 active alert 时 OFF。每次点亮使用 v3.2.0 已验证的完整 selector/R/G/B 写入顺序,只在亮/灭边沿写 MCU,不做高频软件 PWM。相邻页面 RGB mode 相同时不关闭、不重启节奏。动画不写循环日志,owner 变化记录 `DISPLAY_OWNER`,实际模式变化才记录 `RGB_MODE`。
|
||||
RGB 模式由当前 OLED 告警页决定;OLED 位于主页时则使用最高优先级 active owner。颜色表示故障对象:CPU负载、频率、throttling、温度与散热相关为红色,供电/欠压为橙色,内存为紫色,存储为白色,网络/Wi-Fi 为蓝色,服务/进程为青色。频率表示严重等级:默认 Warning 为1500ms亮/1500ms灭,Critical 为750ms亮/750ms灭,Emergency 为300ms亮/300ms灭;没有 active alert 时 OFF。`[led]` 可分别配置六类对象的 R/G/B 值,以及三个严重等级的亮灯和灭灯时长,非法颜色值会限制到0..255,间隔最小为50ms。每次点亮使用 v3.2.0 已验证的完整 selector/R/G/B 写入顺序,只在亮/灭边沿写 MCU,不做高频软件 PWM。相邻页面 RGB mode 相同时不关闭、不重启节奏。动画不写循环日志,owner 变化记录 `DISPLAY_OWNER`,实际模式变化才记录 `RGB_MODE`。
|
||||
|
||||
### 6. 结构化事件日志
|
||||
|
||||
@@ -122,7 +122,7 @@ sudo /usr/local/sbin/pigway-pi-control --diagnose
|
||||
|
||||
诊断使用与运行时相同的配置和检查函数;仅以 I²C receive-byte 读取探测 MCU 0x0D / OLED 0x3C,失败显示 MISSING/ERROR,不初始化或写入风扇、RGB、OLED。独立诊断进程无法获取正在运行的服务的内存计数,故 loop_errors / i2c_errors 明确标记 UNAVAILABLE;服务退出的 STOP 事件包含该次运行计数。
|
||||
|
||||
RGB 保留卖家 MCU 0x0D 寄存器协议。实机校准确认呼吸应使用 MCU 内置效果,模式切换间隔默认 10ms,并由正常 OLED 刷新保持共享总线活动。旧版 `brightness`、软件呼吸周期、更新频率和 R/G/B 配置继续允许保留在用户配置中,但硬件灯效引擎会忽略它们。
|
||||
RGB 保留卖家 MCU 0x0D 寄存器协议。实机校准确认静态自定义颜色配合低频亮灭最稳定;每次点亮完整写入 selector/R/G/B,寄存器间隔默认10ms。旧版 `brightness`、呼吸周期和颜色选项可以继续留在用户配置中,但频闪引擎会忽略它们。
|
||||
|
||||
### 8. 关机收尾
|
||||
|
||||
@@ -165,7 +165,7 @@ sudo ./install.sh
|
||||
- 检查 I²C
|
||||
- 禁用旧 `temp-control.service`
|
||||
- 安装字体、程序、配置和 systemd unit
|
||||
- 完整保留用户现有配置(包括所有 section、用户值和注释),新选项使用运行时默认值
|
||||
- 完整保留用户现有配置(包括所有 section、用户值和注释),仅向 `[led]` 补入缺失的 RGB 颜色与频闪选项,已有用户值优先
|
||||
- 启动服务
|
||||
- 执行版本、OLED、UI、P0健康监控和诊断入口自检
|
||||
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
f3438c9868b0d7bd98c995908186ae21cd6580c1511265b6f7556961a4d78e30 README.md
|
||||
1b9aaee5c830cab22aa4791d47f45cb4afcc5b5b08854b6ea609d1edc59911c3 README.md
|
||||
72c46162c33f9587c6ccb01ad53fbaaf4ecec8cd21014b909e87e8707e253e36 app/oled_font_5x7.bin
|
||||
fd70b204dea22eb2f3c60345bc24ffcc286903603e02c7f708ccc301eba2cbc3 app/pigway_pi_control.py
|
||||
57602d3ad8f543c63504942c8fa726c61cf37beb95e58178a8f618ef35a6e51d config/pigway-pi-control.conf
|
||||
4c2816da08378f2927c746b70ecfa7d5312e1730c08727cd89e8c2801e707054 install.sh
|
||||
06c50cec0cc29e0e6acda3db3e5749b165c5f419dbd28fafddffcf6130fce531 app/pigway_pi_control.py
|
||||
1e5d079c31a250067e88962373a5d58f16f114a83db4a4125110b5a14bdf84a1 config/pigway-pi-control.conf
|
||||
c347333198a9e371e4441f416e247fd1bce542a3cff999947adfe11a0a7044e0 install.sh
|
||||
81aea0a89b298b2512fcb9bf6418618ba7a66474d425390cf95a0128c4093474 systemd/pigway-pi-control.service
|
||||
a3d74973cafbabaf58a660a8c83d28347d1c06d9fd2dab3ecfce5b7607f6fee2 uninstall.sh
|
||||
|
||||
+31
-23
@@ -249,23 +249,31 @@ ROW_Y=[cf("display","row1_y",0,int),cf("display","row2_y",8,int),cf("display","r
|
||||
DARK_PWR=cf("dark_mode","pi_pwr_led",True,lambda x: str(x).strip().lower() in ("off","0","false","no"))
|
||||
DARK_ACT=cf("dark_mode","pi_act_led",True,lambda x: str(x).strip().lower() in ("off","0","false","no"))
|
||||
RGB_WRITE_DELAY_MS=max(1,cf("led","write_delay_ms",10,int))
|
||||
WARNING_FLASH_MS=max(50,cf("led","warning_flash_ms",1500,int))
|
||||
CRITICAL_FLASH_MS=max(50,cf("led","critical_flash_ms",750,int))
|
||||
EMERGENCY_FLASH_MS=max(50,cf("led","emergency_flash_ms",300,int))
|
||||
RGB_STATIC_VALUES={
|
||||
"RED":(0xff,0x00,0x00),"GREEN":(0x00,0xff,0x00),"BLUE":(0x00,0x00,0xff),
|
||||
"YELLOW":(0xff,0xff,0x00),"PURPLE":(0xff,0x00,0xff),"CYAN":(0x00,0xff,0x60),
|
||||
"WHITE":(0xff,0xff,0xff),"ORANGE":(0xff,0x28,0x00),
|
||||
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)))
|
||||
|
||||
def rgb_cfg(name,default):
|
||||
return tuple(max(0,min(255,cf("led",f"{name}_{channel}",value,int)))
|
||||
for channel,value in zip(("r","g","b"),default))
|
||||
|
||||
RGB_GROUP_VALUES={
|
||||
"CPU":rgb_cfg("cpu",(255,0,0)),
|
||||
"POWER":rgb_cfg("power",(255,40,0)),
|
||||
"MEMORY":rgb_cfg("memory",(255,0,255)),
|
||||
"STORAGE":rgb_cfg("storage",(255,255,255)),
|
||||
"NETWORK":rgb_cfg("network",(0,0,255)),
|
||||
"SERVICE":rgb_cfg("service",(0,255,96)),
|
||||
}
|
||||
RGB_OBJECT_COLORS={
|
||||
"ROOT_READONLY":"WHITE",
|
||||
"TEMP_CRITICAL":"RED","TEMP_HIGH":"RED","SOFT_TEMP_LIMIT":"RED",
|
||||
"THROTTLED":"RED","FREQ_CAPPED":"RED","CPU_HIGH":"RED",
|
||||
"POWER_UNDERVOLT":"YELLOW",
|
||||
"MEMORY_HIGH":"PURPLE",
|
||||
"DISK_CRITICAL":"WHITE","DISK_HIGH":"WHITE",
|
||||
"NETWORK_DOWN":"BLUE","INTERNET_DOWN":"BLUE","WIFI_WEAK":"BLUE",
|
||||
"SERVICE_DOWN":"CYAN","PROCESS_DOWN":"CYAN",
|
||||
RGB_OBJECT_GROUPS={
|
||||
"ROOT_READONLY":"STORAGE",
|
||||
"TEMP_CRITICAL":"CPU","TEMP_HIGH":"CPU","SOFT_TEMP_LIMIT":"CPU",
|
||||
"THROTTLED":"CPU","FREQ_CAPPED":"CPU","CPU_HIGH":"CPU",
|
||||
"POWER_UNDERVOLT":"POWER",
|
||||
"MEMORY_HIGH":"MEMORY",
|
||||
"DISK_CRITICAL":"STORAGE","DISK_HIGH":"STORAGE",
|
||||
"NETWORK_DOWN":"NETWORK","INTERNET_DOWN":"NETWORK","WIFI_WEAK":"NETWORK",
|
||||
"SERVICE_DOWN":"SERVICE","PROCESS_DOWN":"SERVICE",
|
||||
}
|
||||
|
||||
def check_watch(w):
|
||||
@@ -413,14 +421,14 @@ def update_active_alerts(cpu,temp,mem,disk,sample_elapsed=0.0):
|
||||
def rgb_mode_for(request_id,severity):
|
||||
if severity<=0: return "OFF"
|
||||
alert_type=request_id.split("|",1)[0]
|
||||
color="ORANGE" if alert_type=="POWER_UNDERVOLT" else RGB_OBJECT_COLORS[alert_type]
|
||||
color=RGB_OBJECT_GROUPS[alert_type]
|
||||
level="EMERGENCY" if severity>=3 else "CRITICAL" if severity>=2 else "WARNING"
|
||||
return f"{color}_{level}_FLASH"
|
||||
|
||||
def rgb_flash(mode,on):
|
||||
global _last_rgb
|
||||
color=mode.split("_",1)[0]
|
||||
channels=RGB_STATIC_VALUES[color]
|
||||
channels=RGB_GROUP_VALUES[color]
|
||||
state=(mode,bool(on))
|
||||
if _last_rgb==state: return
|
||||
if not on:
|
||||
@@ -623,11 +631,11 @@ class DisplayController:
|
||||
applied_mode=wanted_mode; animation_started=time.monotonic()
|
||||
applied_flash=applied_mode.endswith("_FLASH")
|
||||
if applied_flash:
|
||||
elapsed=time.monotonic()-animation_started
|
||||
if "_EMERGENCY_" in applied_mode: interval=EMERGENCY_FLASH_MS
|
||||
elif "_CRITICAL_" in applied_mode: interval=CRITICAL_FLASH_MS
|
||||
else: interval=WARNING_FLASH_MS
|
||||
on=int(elapsed*1000/max(50,interval))%2==0
|
||||
elapsed_ms=(time.monotonic()-animation_started)*1000.0
|
||||
if "_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)
|
||||
if previous_error is not None: log("INFO","RGB_RECOVERED")
|
||||
previous_error=None
|
||||
|
||||
@@ -147,20 +147,43 @@ wifi_weak_seconds = 30
|
||||
# 磁盘 = 白色
|
||||
# 网络/Wi-Fi = 蓝色
|
||||
# 服务/进程 = 青色
|
||||
# Warning (1) = 1500ms 亮 / 1500ms 灭
|
||||
# Critical (2) = 750ms 亮 / 750ms 灭
|
||||
# Emergency (3) = 对象颜色快速频闪
|
||||
# 颜色通道范围为 0..255。以下是本机实测后的默认值。
|
||||
cpu_r = 255
|
||||
cpu_g = 0
|
||||
cpu_b = 0
|
||||
power_r = 255
|
||||
power_g = 40
|
||||
power_b = 0
|
||||
memory_r = 255
|
||||
memory_g = 0
|
||||
memory_b = 255
|
||||
storage_r = 255
|
||||
storage_g = 255
|
||||
storage_b = 255
|
||||
network_r = 0
|
||||
network_g = 0
|
||||
network_b = 255
|
||||
service_r = 0
|
||||
service_g = 255
|
||||
service_b = 96
|
||||
|
||||
# 各严重等级可分别设置亮灯和灭灯时长,单位:毫秒,最小值 50。
|
||||
# 默认完整周期:Warning 3秒、Critical 1.5秒、Emergency 0.6秒。
|
||||
warning_flash_on_ms = 1500
|
||||
warning_flash_off_ms = 1500
|
||||
critical_flash_on_ms = 750
|
||||
critical_flash_off_ms = 750
|
||||
emergency_flash_on_ms = 300
|
||||
emergency_flash_off_ms = 300
|
||||
# NORMAL_HOME 为 owner 时 RGB OFF。
|
||||
#
|
||||
# 每次点亮使用 v3.2.0 已验证的 selector -> R -> G -> B 完整写入顺序,
|
||||
# 只在亮/灭边沿访问 MCU,不做高频软件 PWM。
|
||||
write_delay_ms = 10
|
||||
warning_flash_ms = 1500
|
||||
critical_flash_ms = 750
|
||||
emergency_flash_ms = 300
|
||||
|
||||
# v3.3.0 之前的 brightness、*_breathe_seconds、rgb_update_ms、warning_color、
|
||||
# critical_color 和 *_r/g/b
|
||||
# v3.3.0 RC 期间使用过的 brightness、*_breathe_seconds、rgb_update_ms、
|
||||
# warning_color、critical_color、warning_flash_ms、critical_flash_ms 和
|
||||
# emergency_flash_ms
|
||||
# 可以继续留在现有配置中;硬件灯效引擎会安全忽略它们。
|
||||
|
||||
|
||||
|
||||
+34
@@ -47,6 +47,40 @@ if [ -f /etc/pigway-pi-control.conf ]; then
|
||||
else
|
||||
install -m 0644 config/pigway-pi-control.conf /etc/pigway-pi-control.conf
|
||||
fi
|
||||
|
||||
# Preserve the existing file verbatim while exposing newly configurable RGB
|
||||
# defaults. Missing keys are inserted into [led]; existing user values win.
|
||||
python3 - /etc/pigway-pi-control.conf <<'PY'
|
||||
import re,sys
|
||||
from pathlib import Path
|
||||
|
||||
path=Path(sys.argv[1])
|
||||
text=path.read_text()
|
||||
defaults=(
|
||||
("cpu_r",255),("cpu_g",0),("cpu_b",0),
|
||||
("power_r",255),("power_g",40),("power_b",0),
|
||||
("memory_r",255),("memory_g",0),("memory_b",255),
|
||||
("storage_r",255),("storage_g",255),("storage_b",255),
|
||||
("network_r",0),("network_g",0),("network_b",255),
|
||||
("service_r",0),("service_g",255),("service_b",96),
|
||||
("warning_flash_on_ms",1500),("warning_flash_off_ms",1500),
|
||||
("critical_flash_on_ms",750),("critical_flash_off_ms",750),
|
||||
("emergency_flash_on_ms",300),("emergency_flash_off_ms",300),
|
||||
)
|
||||
missing=[(key,value) for key,value in defaults
|
||||
if not re.search(rf"(?m)^\s*{re.escape(key)}\s*=",text)]
|
||||
if missing:
|
||||
block="\n# RGB object colors (0..255) and flash timing (milliseconds).\n"
|
||||
block+="".join(f"{key} = {value}\n" for key,value in missing)
|
||||
match=re.search(r"(?m)^\[led\]\s*$",text)
|
||||
if match:
|
||||
next_section=re.search(r"(?m)^\[.+\]\s*$",text[match.end():])
|
||||
pos=match.end()+(next_section.start() if next_section else len(text)-match.end())
|
||||
text=text[:pos].rstrip()+"\n"+block+"\n"+text[pos:].lstrip("\n")
|
||||
else:
|
||||
text=text.rstrip()+"\n\n[led]\n"+block
|
||||
path.write_text(text)
|
||||
PY
|
||||
install -m 0644 systemd/pigway-pi-control.service /etc/systemd/system/pigway-pi-control.service
|
||||
|
||||
echo "[6/8] 启用/重启服务..."
|
||||
|
||||
Reference in New Issue
Block a user