diff --git a/README.md b/README.md index 0877d18..daf7cca 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ cd /var/www/control /usr/bin/python3 touch_panel/panel.py ``` -패널은 Control PHP/API/DB snapshot을 호출하지 않는 standalone 방식입니다. Python이 `/sys/class/net`, `/proc/diskstats`, `/sys/class/thermal`, 팬 hwmon 파일을 직접 읽습니다. 상태패널과 팬패널은 50ms 간격으로 커널 카운터를 따라가고, 그래프는 500ms 간격으로 샘플링합니다. 왼쪽 `DISK I/O`, `WAN`, `LAN`, `2.4G`, `5G` 표시등은 장식용 heartbeat가 아니라 직전 샘플 대비 현재 카운터 증가량이 0 초과인지에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드은 초록, 쓰기/다운로드는 주황, 오류/드롭 증가는 빨강으로 표시합니다. 해당 증가량이 없으면 각 표시등은 회색입니다. `DISK I/O`의 값은 `/dev/sda` Samsung T7을 `smartctl -d sntasmedia`로 1초마다 읽은 디스크 자체 온도입니다. GUI 사용자 `seo`는 `/etc/sudoers.d/control-touch-panel-smartctl`에서 해당 smartctl 명령만 NOPASSWD로 허용합니다. 네트워크 상태값은 정상, 드롭 누적, 꺼짐으로 표시합니다. 상태패널 최하단의 `PC` 타일은 `192.168.50.73`에 1초마다 ping을 보내 켜짐 여부를 표시하고, 꺼져 있을 때 누르면 `74:56:3C:CD:CD:79`로 WOL magic packet을 보냅니다. PC 타일의 주황은 WOL 후 최대 1분 동안 컴퓨터 응답 대기 표시, 빨강은 magic packet 전송 실패 시 5초 또는 1분 대기 후 응답 실패 시 1분 표시입니다. +패널은 Control PHP/API/DB snapshot을 호출하지 않는 standalone 방식입니다. Python이 `/sys/class/net`, `/proc/diskstats`, `/sys/class/thermal`, 팬 hwmon 파일을 직접 읽습니다. 상태패널과 팬패널은 50ms 간격으로 커널 카운터를 따라가고, 그래프는 500ms 간격으로 샘플링합니다. 왼쪽 `DISK I/O`, `WAN`, `LAN`, `2.4G`, `5G` 표시등은 장식용 heartbeat가 아니라 직전 샘플 대비 현재 카운터 증가량이 0 초과인지에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드은 초록, 쓰기/다운로드는 주황, 오류/드롭 증가는 빨강으로 표시합니다. 활동 표시등은 이벤트 감지 후 120ms 동안 유지하고, 오류 표시등은 2초 동안 유지해 너무 짧은 이벤트도 눈에 보이게 합니다. `DISK I/O`의 값은 `/dev/sda` Samsung T7을 `smartctl -d sntasmedia`로 1초마다 읽은 디스크 자체 온도입니다. GUI 사용자 `seo`는 `/etc/sudoers.d/control-touch-panel-smartctl`에서 해당 smartctl 명령만 NOPASSWD로 허용합니다. 네트워크 상태값은 정상, 드롭 누적, 꺼짐으로 표시합니다. 상태패널 최하단의 `PC` 타일은 `192.168.50.73`에 1초마다 ping을 보내 켜짐 여부를 표시하고, 꺼져 있을 때 누르면 `74:56:3C:CD:CD:79`로 WOL magic packet을 보냅니다. PC 타일의 주황은 WOL 후 최대 1분 동안 컴퓨터 응답 대기 표시, 빨강은 magic packet 전송 실패 시 5초 또는 1분 대기 후 응답 실패 시 1분 표시입니다. 오른쪽에는 팬 RPM, CPU 온도, PWM, WAN 실시간 속도와 온도/RPM, WAN 트래픽 그래프를 표시합니다. 위 그래프는 좌측 Y축에 온도, 우측 Y축에 RPM 단위를 표시하고, 아래 WAN 그래프는 기존 형태를 유지합니다. 팬 auto/manual/off 버튼은 없고 PWM 슬라이더는 현재값 위치만 보여 주며 터치 제어는 받지 않습니다. diff --git a/touch_panel/panel.py b/touch_panel/panel.py index 8a44e65..e07b41b 100755 --- a/touch_panel/panel.py +++ b/touch_panel/panel.py @@ -179,11 +179,17 @@ class StatusDot(QWidget): class StatusTile(QFrame): + ACTIVITY_HOLD_SECONDS = 0.12 + ERROR_HOLD_SECONDS = 2.0 + def __init__(self, title): super().__init__() self.read_dot = StatusDot("#16a34a") self.write_dot = StatusDot("#f97316") self.error_dot = StatusDot("#dc2626") + self.last_read_at = 0.0 + self.last_write_at = 0.0 + self.last_error_at = 0.0 self.title = QLabel(title) self.title.setObjectName("statusTitle") self.detail = QLabel("-") @@ -212,15 +218,23 @@ class StatusTile(QFrame): self.setObjectName("statusTile") def set_state(self, detail, error=False, read_activity=False, write_activity=False): - self.error_dot.set_steady(error) - self.read_dot.set_steady(read_activity) - self.write_dot.set_steady(write_activity) + now = time.monotonic() + if read_activity: + self.last_read_at = now + if write_activity: + self.last_write_at = now + if error: + self.last_error_at = now + self.update_dots(now) self.detail.setText(detail) def tick(self): - self.read_dot.tick() - self.write_dot.tick() - self.error_dot.tick() + self.update_dots(time.monotonic()) + + def update_dots(self, now): + self.read_dot.set_steady(now - self.last_read_at <= self.ACTIVITY_HOLD_SECONDS) + self.write_dot.set_steady(now - self.last_write_at <= self.ACTIVITY_HOLD_SECONDS) + self.error_dot.set_steady(now - self.last_error_at <= self.ERROR_HOLD_SECONDS) class PcWakeButton(StatusTile): @@ -277,6 +291,10 @@ class PcWakeButton(StatusTile): self.error_dot.set_steady(True) super().mousePressEvent(event) + def tick(self): + self.write_dot.tick() + self.error_dot.tick() + class MetricCard(QFrame): def __init__(self, title):