diff --git a/README.md b/README.md index 9dd5b87..05e6c70 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 파일을 직접 읽습니다. 상태패널과 팬패널은 120ms 간격으로 갱신하고, 그래프는 500ms 간격으로 샘플링합니다. 왼쪽 `DISK I/O`, `WAN`, `LAN`, `2.4G`, `5G` 표시등은 장식용 heartbeat가 아니라 실제 커널 카운터 증가에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드는 초록, 쓰기/다운로드는 주황, 오류는 빨강으로 표시합니다. 활동이 없으면 초록/주황은 회색입니다. `DISK I/O`의 값은 `/dev/sda` Samsung T7을 `smartctl -d sntasmedia`로 1초마다 읽은 디스크 자체 온도입니다. 네트워크 상태값은 정상, 드롭 누적, 꺼짐으로 표시합니다. 상태패널 최하단의 `PC` 타일은 `192.168.50.73`에 1초마다 ping을 보내 켜짐 여부를 표시하고, 꺼져 있을 때 누르면 `74:56:3C:CD:CD:79`로 WOL magic packet을 보냅니다. PC 타일의 주황은 터치/WOL 전송 시도 표시, 빨강은 magic packet 전송 실패 표시입니다. WOL은 한 번 누르면 30초 동안 추가 전송을 막습니다. +패널은 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분 표시입니다. 오른쪽에는 팬 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 6c05ea6..8865f99 100755 --- a/touch_panel/panel.py +++ b/touch_panel/panel.py @@ -230,26 +230,52 @@ class PcWakeButton(StatusTile): super().__init__("PC") self.online = False self.last_wake_at = 0.0 + self.wait_until = 0.0 + self.error_until = 0.0 + self.blink_timer = QTimer(self) + self.blink_timer.timeout.connect(self.tick_waiting) + self.blink_timer.start(250) def set_online(self, online): self.online = online self.read_dot.set_steady(online) - self.error_dot.set_steady(False) + now = time.monotonic() + self.error_dot.set_steady(now < self.error_until) if online: + self.wait_until = 0.0 self.detail.setText("켜짐") - elif time.monotonic() - self.last_wake_at < 30: - remaining = int(30 - (time.monotonic() - self.last_wake_at)) + elif now < self.wait_until: + remaining = int(self.wait_until - now) self.detail.setText(f"대기 {remaining}s") else: self.detail.setText("꺼짐") + def tick_waiting(self): + now = time.monotonic() + if not self.online and now < self.wait_until: + self.write_dot.blink() + if not self.online and self.wait_until > 0 and now >= self.wait_until: + self.wait_until = 0.0 + self.error_until = now + 60 + self.error_dot.set_steady(True) + self.detail.setText("실패") + if self.error_until > 0 and now >= self.error_until: + self.error_until = 0.0 + self.error_dot.set_steady(False) + def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.write_dot.blink() - if not self.online and time.monotonic() - self.last_wake_at >= 30: - self.last_wake_at = time.monotonic() + now = time.monotonic() + if not self.online and now >= self.wait_until: + self.last_wake_at = now + self.wait_until = now + 60 + self.error_until = 0.0 + self.error_dot.set_steady(False) self.detail.setText("깨우는 중") if not send_magic_packet(PC_MAC): + self.wait_until = 0.0 + self.error_until = now + 5 self.error_dot.set_steady(True) super().mousePressEvent(event) @@ -385,7 +411,7 @@ class TouchPanel(QMainWindow): self.sample_timer = QTimer(self) self.sample_timer.timeout.connect(self.sample) - self.sample_timer.start(120) + self.sample_timer.start(50) self.graph_timer = QTimer(self) self.graph_timer.timeout.connect(self.update_graphs) @@ -405,7 +431,7 @@ class TouchPanel(QMainWindow): self.pulse_timer = QTimer(self) self.pulse_timer.timeout.connect(self.tick_pulses) - self.pulse_timer.start(70) + self.pulse_timer.start(25) self.sample() self.ping_pc() self.update_disk_temp() @@ -557,7 +583,7 @@ class TouchPanel(QMainWindow): def update_disk_temp(self): if self.disk_temp_proc.state() != QProcess.NotRunning: return - self.disk_temp_proc.start("/usr/sbin/smartctl", ["-A", "-d", "sntasmedia", "/dev/sda"]) + self.disk_temp_proc.start("/usr/bin/sudo", ["-n", "/usr/sbin/smartctl", "-A", "-d", "sntasmedia", "/dev/sda"]) def disk_temp_finished(self, exit_code, exit_status): del exit_code, exit_status