From 0075d5f38e97c7486e3109bc7fa079d18d0eda6e Mon Sep 17 00:00:00 2001 From: seo Date: Thu, 30 Jul 2026 13:22:16 +0900 Subject: [PATCH] =?UTF-8?q?=ED=84=B0=EC=B9=98=20=ED=8C=A8=EB=84=90=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EB=93=B1=EC=9D=84=20=ED=98=84=EC=9E=AC=20?= =?UTF-8?q?=EC=A6=9D=EA=B0=80=EB=9F=89=20=EA=B8=B0=EC=A4=80=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- touch_panel/panel.py | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 05e6c70..0877d18 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가 아니라 실제 커널 카운터 증가에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드는 초록, 쓰기/다운로드는 주황, 오류는 빨강으로 표시합니다. 활동이 없으면 초록/주황은 회색입니다. `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 초과인지에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드은 초록, 쓰기/다운로드는 주황, 오류/드롭 증가는 빨강으로 표시합니다. 해당 증가량이 없으면 각 표시등은 회색입니다. `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 8865f99..8a44e65 100755 --- a/touch_panel/panel.py +++ b/touch_panel/panel.py @@ -213,10 +213,8 @@ class StatusTile(QFrame): def set_state(self, detail, error=False, read_activity=False, write_activity=False): self.error_dot.set_steady(error) - if read_activity: - self.read_dot.blink() - if write_activity: - self.write_dot.blink() + self.read_dot.set_steady(read_activity) + self.write_dot.set_steady(write_activity) self.detail.setText(detail) def tick(self): @@ -532,10 +530,20 @@ class TouchPanel(QMainWindow): activity = {} for key, row in groups.items(): previous = self.last_net.get(key) - current = (row["rx_bytes"], row["tx_bytes"], row["rx_packets"], row["tx_packets"]) + current = ( + row["rx_bytes"], + row["tx_bytes"], + row["rx_packets"], + row["tx_packets"], + row["rx_errors"], + row["tx_errors"], + row["rx_dropped"], + row["tx_dropped"], + ) activity[key] = { - "read": previous is not None and current[1] != previous[1], - "write": previous is not None and current[0] != previous[0], + "read": previous is not None and (current[1] > previous[1] or current[3] > previous[3]), + "write": previous is not None and (current[0] > previous[0] or current[2] > previous[2]), + "error": previous is not None and any(current[index] > previous[index] for index in [4, 5, 6, 7]), } if previous: rates[key] = { @@ -552,10 +560,10 @@ class TouchPanel(QMainWindow): def render(self, temp, rpm, pwm, percent, enable, groups, rates, activity, io_read_activity, io_write_activity, disk_error): disk_temp_text = f"{self.disk_temp:.1f} C" if self.disk_temp is not None else "- C" self.rows["io"].set_state(disk_temp_text, disk_error, io_read_activity, io_write_activity) - self.rows["wan"].set_state(self.iface_detail(groups["wan"]), self.iface_warn(groups["wan"]), activity["wan"]["read"], activity["wan"]["write"]) - self.rows["lan"].set_state(self.iface_detail(groups["lan"]), self.iface_warn(groups["lan"]), activity["lan"]["read"], activity["lan"]["write"]) - self.rows["wifi24"].set_state(self.iface_detail(groups["wifi24"]), self.iface_warn(groups["wifi24"]), activity["wifi24"]["read"], activity["wifi24"]["write"]) - self.rows["wifi5"].set_state(self.iface_detail(groups["wifi5"]), self.iface_warn(groups["wifi5"]), activity["wifi5"]["read"], activity["wifi5"]["write"]) + self.rows["wan"].set_state(self.iface_detail(groups["wan"]), activity["wan"]["error"], activity["wan"]["read"], activity["wan"]["write"]) + self.rows["lan"].set_state(self.iface_detail(groups["lan"]), activity["lan"]["error"], activity["lan"]["read"], activity["lan"]["write"]) + self.rows["wifi24"].set_state(self.iface_detail(groups["wifi24"]), activity["wifi24"]["error"], activity["wifi24"]["read"], activity["wifi24"]["write"]) + self.rows["wifi5"].set_state(self.iface_detail(groups["wifi5"]), activity["wifi5"]["error"], activity["wifi5"]["read"], activity["wifi5"]["write"]) self.metrics["rpm"].set_value(f"{rpm:,}") self.metrics["temp"].set_value(f"{temp:.1f} C")