터치 패널 온도 경고 점멸 적용
This commit is contained in:
1 parent
3eda77c741
commit
33851e0189
2 files changed
+15
-6
No files matched your search
@@ -146,7 +146,7 @@ cd /var/www/control
|
|||||||
/usr/bin/python3 touch_panel/panel.py
|
/usr/bin/python3 touch_panel/panel.py
|
||||||
```
|
```
|
||||||
|
|
||||||
패널은 Control PHP/API/DB snapshot을 호출하지 않는 standalone 방식입니다. Python이 `/sys/class/net`, `/proc/diskstats`, `/sys/class/thermal`, 팬 hwmon 파일을 직접 읽습니다. 상태패널, 팬패널, 오른쪽 대시보드 카드/그래프는 50ms 간격으로 갱신합니다. 왼쪽 상태패널은 `RASPBERRY`, `SYNOLOGY`, `CHECK` 3열이며, 라즈베리파이 순서는 `DISK I/O`, `LOCAL`, `UPLINK`, `ETH1`, `5G`, `2.4G`입니다. 시놀로지 열은 정상 디스크 `SATA1`, `SATA2`, `SATA4`를 개별 카드로 표시한 뒤 `LOCAL`, `UPLINK`를 표시합니다. `CHECK` 열은 `RPI TEMP`, `RPI FAN`, `SYNO TEMP`, `SYNO FAN`을 표시합니다. `SYNO TEMP`는 시놀로지 CPU 온도 기준이고, 팬 카드는 RPM 0 또는 7000 초과를 빨강, 4500 초과를 주황으로 표시합니다. `LOCAL`은 `lo`, `UPLINK`는 기본 라우트 인터페이스 기준입니다. 라즈베리파이 `ETH1`은 컴퓨터와 연결된 물리 포트 단독 카운터이며 `br0`는 합산하지 않습니다. 시놀로지는 SSH를 유지한 채 50ms마다 디스크별 sector I/O, `LOCAL`, `UPLINK` 카운터를 스트림으로 가져오고, 각 SATA 카드 값에는 SMART 온도를 표시합니다. 왼쪽 표시등은 장식용 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분 표시입니다.
|
패널은 Control PHP/API/DB snapshot을 호출하지 않는 standalone 방식입니다. Python이 `/sys/class/net`, `/proc/diskstats`, `/sys/class/thermal`, 팬 hwmon 파일을 직접 읽습니다. 상태패널, 팬패널, 오른쪽 대시보드 카드/그래프는 50ms 간격으로 갱신합니다. 왼쪽 상태패널은 `RASPBERRY`, `SYNOLOGY`, `CHECK` 3열이며, 라즈베리파이 순서는 `DISK I/O`, `LOCAL`, `UPLINK`, `ETH1`, `5G`, `2.4G`입니다. 시놀로지 열은 정상 디스크 `SATA1`, `SATA2`, `SATA4`를 개별 카드로 표시한 뒤 `LOCAL`, `UPLINK`를 표시합니다. `CHECK` 열은 `RPI TEMP`, `RPI FAN`, `SYNO TEMP`, `SYNO FAN`을 표시합니다. `RPI TEMP`와 `SYNO TEMP`는 80도 이상부터 빨간 표시등을 500ms 간격으로 점멸하고, 팬 카드는 RPM 0 또는 7000 초과를 빨강, 4500 초과를 주황으로 표시합니다. `LOCAL`은 `lo`, `UPLINK`는 기본 라우트 인터페이스 기준입니다. 라즈베리파이 `ETH1`은 컴퓨터와 연결된 물리 포트 단독 카운터이며 `br0`는 합산하지 않습니다. 시놀로지는 SSH를 유지한 채 50ms마다 디스크별 sector I/O, `LOCAL`, `UPLINK` 카운터를 스트림으로 가져오고, 각 SATA 카드 값에는 SMART 온도를 표시합니다. 왼쪽 표시등은 장식용 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 퍼센트, 메모리 사용률을 표시합니다. 아래에는 최근 30초 기준 온도/RPM 그래프와 WAN 트래픽 그래프를 표시합니다. WAN 속도와 그래프 Y축은 byte/sec 기준으로 `B/s`, `KB/s`, `MB/s`, `GB/s` 중 자동 변환하고, 그래프 우측 상단 현재값은 고정폭으로 표시합니다. 위 그래프는 좌측 Y축에 온도, 우측 Y축에 RPM 단위를 표시하고, 아래 WAN 그래프는 기존 형태를 유지합니다. 팬 auto/manual/off 버튼은 없고 PWM 슬라이더는 현재값 위치만 보여 주며 터치 제어는 받지 않습니다.
|
오른쪽 상단 카드는 팬 RPM, CPU 온도, PWM 퍼센트, 메모리 사용률을 표시합니다. 아래에는 최근 30초 기준 온도/RPM 그래프와 WAN 트래픽 그래프를 표시합니다. WAN 속도와 그래프 Y축은 byte/sec 기준으로 `B/s`, `KB/s`, `MB/s`, `GB/s` 중 자동 변환하고, 그래프 우측 상단 현재값은 고정폭으로 표시합니다. 위 그래프는 좌측 Y축에 온도, 우측 Y축에 RPM 단위를 표시하고, 아래 WAN 그래프는 기존 형태를 유지합니다. 팬 auto/manual/off 버튼은 없고 PWM 슬라이더는 현재값 위치만 보여 주며 터치 제어는 받지 않습니다.
|
||||||
|
|
||||||
|
|||||||
+14
-5
@@ -308,6 +308,7 @@ class StatusDot(QWidget):
|
|||||||
class StatusTile(QFrame):
|
class StatusTile(QFrame):
|
||||||
ACTIVITY_HOLD_SECONDS = 0.12
|
ACTIVITY_HOLD_SECONDS = 0.12
|
||||||
ERROR_HOLD_SECONDS = 2.0
|
ERROR_HOLD_SECONDS = 2.0
|
||||||
|
ERROR_BLINK_SECONDS = 0.5
|
||||||
|
|
||||||
def __init__(self, title):
|
def __init__(self, title):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -320,6 +321,7 @@ class StatusTile(QFrame):
|
|||||||
self.read_steady = None
|
self.read_steady = None
|
||||||
self.write_steady = None
|
self.write_steady = None
|
||||||
self.error_steady = None
|
self.error_steady = None
|
||||||
|
self.error_blink = False
|
||||||
self.title = QLabel(title)
|
self.title = QLabel(title)
|
||||||
self.title.setObjectName("statusTitle")
|
self.title.setObjectName("statusTitle")
|
||||||
self.detail = QLabel("-")
|
self.detail = QLabel("-")
|
||||||
@@ -356,11 +358,13 @@ class StatusTile(QFrame):
|
|||||||
read_steady=None,
|
read_steady=None,
|
||||||
write_steady=None,
|
write_steady=None,
|
||||||
error_steady=None,
|
error_steady=None,
|
||||||
|
error_blink=False,
|
||||||
):
|
):
|
||||||
now = time.monotonic()
|
now = time.monotonic()
|
||||||
self.read_steady = read_steady
|
self.read_steady = read_steady
|
||||||
self.write_steady = write_steady
|
self.write_steady = write_steady
|
||||||
self.error_steady = error_steady
|
self.error_steady = error_steady
|
||||||
|
self.error_blink = error_blink
|
||||||
if read_activity:
|
if read_activity:
|
||||||
self.last_read_at = now
|
self.last_read_at = now
|
||||||
if write_activity:
|
if write_activity:
|
||||||
@@ -376,6 +380,9 @@ class StatusTile(QFrame):
|
|||||||
def update_dots(self, now):
|
def update_dots(self, now):
|
||||||
read_on = self.read_steady if self.read_steady is not None else now - self.last_read_at <= self.ACTIVITY_HOLD_SECONDS
|
read_on = self.read_steady if self.read_steady is not None else now - self.last_read_at <= self.ACTIVITY_HOLD_SECONDS
|
||||||
write_on = self.write_steady if self.write_steady is not None else now - self.last_write_at <= self.ACTIVITY_HOLD_SECONDS
|
write_on = self.write_steady if self.write_steady is not None else now - self.last_write_at <= self.ACTIVITY_HOLD_SECONDS
|
||||||
|
if self.error_blink:
|
||||||
|
error_on = int(now / self.ERROR_BLINK_SECONDS) % 2 == 0
|
||||||
|
else:
|
||||||
error_on = self.error_steady if self.error_steady is not None else now - self.last_error_at <= self.ERROR_HOLD_SECONDS
|
error_on = self.error_steady if self.error_steady is not None else now - self.last_error_at <= self.ERROR_HOLD_SECONDS
|
||||||
self.read_dot.set_steady(read_on)
|
self.read_dot.set_steady(read_on)
|
||||||
self.write_dot.set_steady(write_on)
|
self.write_dot.set_steady(write_on)
|
||||||
@@ -984,8 +991,9 @@ class TouchPanel(QMainWindow):
|
|||||||
self.rows["rpi_temp"].set_state(
|
self.rows["rpi_temp"].set_state(
|
||||||
detail,
|
detail,
|
||||||
read_steady=0 < hottest < 60,
|
read_steady=0 < hottest < 60,
|
||||||
write_steady=60 <= hottest < 70,
|
write_steady=60 <= hottest < 80,
|
||||||
error_steady=hottest >= 70,
|
error_steady=False,
|
||||||
|
error_blink=hottest >= 80,
|
||||||
)
|
)
|
||||||
|
|
||||||
def render_rpi_fan(self, rpm):
|
def render_rpi_fan(self, rpm):
|
||||||
@@ -996,9 +1004,10 @@ class TouchPanel(QMainWindow):
|
|||||||
detail = f"{temp:.0f} C" if temp > 0 else "- C"
|
detail = f"{temp:.0f} C" if temp > 0 else "- C"
|
||||||
self.rows["synology_temp"].set_state(
|
self.rows["synology_temp"].set_state(
|
||||||
detail,
|
detail,
|
||||||
read_steady=0 < temp < 75,
|
read_steady=0 < temp < 60,
|
||||||
write_steady=75 <= temp < 90,
|
write_steady=60 <= temp < 80,
|
||||||
error_steady=temp >= 90,
|
error_steady=False,
|
||||||
|
error_blink=temp >= 80,
|
||||||
)
|
)
|
||||||
|
|
||||||
def render_synology_fan(self):
|
def render_synology_fan(self):
|
||||||
|
|||||||
Reference in new issue
Block a user