diff --git a/README.md b/README.md index b194fa5..74ea02d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 - `/etc/systemd/system/*.service` 기준 사용자 생성 서비스의 서비스명, 현재 상태, enable 상태, PID, restart 횟수, 최근 journal 로그를 진단 접힘 영역에서 표시 - 사용자 서비스 로그는 서비스별 최근 500줄까지 조회하고, 사용자가 서비스 목록을 스크롤하는 동안에는 자동 갱신이 화면 위치를 되돌리지 않습니다. - 영구 journal과 커널 크래시 보존 상태를 진단 접힘 영역에서 표시 -- 시놀로지에서 라즈베리파이로 들어온 원격 로그와 dmesg 로그는 진단 접힘 영역에서 필요할 때 열람 +- dmesg 로그는 진단 접힘 영역에서 필요할 때 열람 - WakeLock 버튼으로 대시보드 화면 꺼짐 방지 - Reboot 버튼으로 2단계 확인 후 시스템 재부팅 요청 - 기본 브라우저 alert/confirm/prompt 대신 대시보드 디자인에 맞춘 custom dialog 사용 @@ -145,7 +145,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 간격으로 갱신합니다. 왼쪽 상태패널은 `RASPBERRY`, `SYNOLOGY`, `CHECK` 3열이며, 라즈베리파이 순서는 `SSD I/O`, `LOCAL`, `UPLINK`, `ETH1`, `5G`, `2.4G`입니다. 시놀로지 열은 `PING`, 정상 디스크 `SATA1 I/O`, `SATA2 I/O`, `SATA4 I/O`, `LOCAL`, `UPLINK`를 표시합니다. `CHECK` 열은 `RPI TEMP`, `RPI FAN`, `RPI THROT`, `SYNO TEMP`, `SYNO FAN`, `SYNO GUARD`를 표시합니다. `RPI TEMP`와 `SYNO TEMP`는 80도 이상부터 빨간 표시등을 500ms 간격으로 점멸하고, 팬 카드는 RPM 0 또는 7000 초과를 빨강, 4500 초과를 주황으로 표시합니다. 시놀로지 `PING`은 장기 실행 `ping -i 0.05` 출력 파싱으로 읽고, 15ms 이하 초록, 30ms 이하 주황, 50ms 이하 빨강, 50ms 초과 빨강 500ms 점멸입니다. `RPI THROT`은 정상 초록, 부팅 후 이력 주황, 현재 언더볼트 빨강, 현재 스로틀 빨강 500ms 점멸, 현재 언더볼트와 스로틀 동시 발생 빨강 100ms 점멸로 표시합니다. `SYNO GUARD`는 `synology-fan-guard.service`가 active이고 DSM 자동제어면 초록 `AUTO`, 고온으로 PWM 최대 강제 중이면 주황 `FULL`, 서비스 실패나 팬 RPM 0이면 빨강 `FAIL`로 표시합니다. `LOCAL`은 `lo`, `UPLINK`는 기본 라우트 인터페이스 기준입니다. 라즈베리파이 `ETH1`은 컴퓨터와 연결된 물리 포트 단독 카운터이며 `br0`는 합산하지 않습니다. 시놀로지는 SSH를 유지한 채 50ms마다 디스크별 sector I/O, `LOCAL`, `UPLINK` 카운터를 스트림으로 가져오고, 각 SATA 카드 값에는 SMART 온도를 표시합니다. 라즈베리파이 CPU/SSD 온도, 시놀로지 CPU 온도/FAN RPM, 시놀로지 SATA SMART 온도는 1초 간격으로 캐시해 표시합니다. 왼쪽 표시등은 장식용 heartbeat가 아니라 직전 샘플 대비 현재 카운터 증가량이 0 초과인지에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드은 초록, 쓰기/다운로드는 주황, 오류/드롭 증가는 빨강으로 표시합니다. 활동 표시등은 이벤트 감지 후 120ms 동안 유지하고, 오류 표시등은 2초 동안 유지해 너무 짧은 이벤트도 눈에 보이게 합니다. 네트워크 카드 오른쪽 값은 항상 `D n`으로 드롭 누적을 표시합니다. `SSD I/O`의 값은 `/dev/sda` Samsung T7을 `smartctl -d sntasmedia`로 읽은 디스크 자체 온도입니다. 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 파일을 직접 읽습니다. 상태패널의 네트워크/I/O 표시는 50ms 간격으로 갱신하고, 팬 카드와 오른쪽 대시보드 카드/그래프는 500ms 간격으로 갱신합니다. 왼쪽 상태패널은 `RASPBERRY`, `SYNOLOGY`, `CHECK` 3열이며, 라즈베리파이 순서는 `SSD I/O`, `LOCAL`, `UPLINK`, `ETH1`, `5G`, `2.4G`입니다. 시놀로지 열은 `PING`, 정상 디스크 `SATA1 I/O`, `SATA2 I/O`, `SATA4 I/O`, `LOCAL`, `UPLINK`를 표시합니다. `CHECK` 열은 `RPI TEMP`, `RPI FAN`, `RPI THROT`, `SYNO TEMP`, `SYNO FAN`, `SYNO GUARD`를 표시합니다. `RPI TEMP`와 `SYNO TEMP`는 80도 이상부터 빨간 표시등을 500ms 간격으로 점멸하고, 팬 카드는 RPM 0 또는 7000 초과를 빨강, 4500 초과를 주황으로 표시합니다. 시놀로지 `PING`은 장기 실행 `ping -i 0.5` 출력 파싱으로 읽고, 15ms 이하 초록, 30ms 이하 주황, 50ms 이하 빨강, 50ms 초과 빨강 500ms 점멸입니다. `RPI THROT`은 정상 초록, 부팅 후 이력 주황, 현재 언더볼트 빨강, 현재 스로틀 빨강 500ms 점멸, 현재 언더볼트와 스로틀 동시 발생 빨강 100ms 점멸로 표시합니다. `SYNO GUARD`는 `synology-fan-guard.service`가 active이고 DSM 자동제어면 초록 `AUTO`, 고온으로 PWM 최대 강제 중이면 주황 `FULL`, 서비스 실패나 팬 RPM 0이면 빨강 `FAIL`로 표시합니다. `LOCAL`은 `lo`, `UPLINK`는 기본 라우트 인터페이스 기준입니다. 라즈베리파이 `ETH1`은 컴퓨터와 연결된 물리 포트 단독 카운터이며 `br0`는 합산하지 않습니다. 시놀로지는 SSH를 유지한 채 50ms마다 디스크별 sector I/O, `LOCAL`, `UPLINK` 카운터를 스트림으로 가져오고, 각 SATA 카드 값에는 SMART 온도를 표시합니다. 라즈베리파이 CPU/SSD 온도, 시놀로지 CPU 온도/FAN RPM, 시놀로지 SATA SMART 온도는 500ms 간격으로 캐시해 표시합니다. 왼쪽 표시등은 장식용 heartbeat가 아니라 직전 샘플 대비 현재 카운터 증가량이 0 초과인지에 반응합니다. 각 타일에는 글자 아래에 세 개의 작은 표시등을 두며 읽기/업로드은 초록, 쓰기/다운로드는 주황, 오류/드롭 증가는 빨강으로 표시합니다. 활동 표시등은 이벤트 감지 후 120ms 동안 유지하고, 오류 표시등은 2초 동안 유지해 너무 짧은 이벤트도 눈에 보이게 합니다. 네트워크 카드 오른쪽 값은 항상 `D n`으로 드롭 누적을 표시합니다. `SSD I/O`의 값은 `/dev/sda` Samsung T7을 `smartctl -d sntasmedia`로 읽은 디스크 자체 온도입니다. 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 퍼센트, 메모리 사용률을 표시합니다. 아래에는 최근 10초 기준 온도/RPM 그래프와 WAN 트래픽 그래프를 표시합니다. WAN 속도와 그래프 Y축은 byte/sec 기준으로 `B/s`, `KB/s`, `MB/s`, `GB/s` 중 자동 변환하고, 다운로드 주황/업로드 초록 두 선을 같은 축 범위에 맞춰 그립니다. 그래프 우측 상단 현재값은 고정폭으로 표시합니다. 위 그래프는 좌측 Y축에 온도, 우측 Y축에 RPM 단위를 표시하고, 아래 WAN 그래프는 기존 형태를 유지합니다. 팬 auto/manual/off 버튼은 없고 PWM 슬라이더는 현재값 위치만 보여 주며 터치 제어는 받지 않습니다. @@ -165,7 +165,7 @@ systemd 방식이 필요하면 `systemd/control-touch-panel.service`를 `/etc/sy - WebSocket 끊김 시 HTTP fallback 상태 갱신: 2초마다 - 탭 복귀: 즉시 1회 상태 갱신 - UPS/배터리 잔여 시간: 현재 운영 구성에서는 표시하지 않음 -- 시놀로지 원격 로그/dmesg: 진단 패널에서 열었을 때만 1초마다 갱신, 닫으면 중지 +- dmesg: 진단 패널에서 열었을 때만 1초마다 갱신, 닫으면 중지 - WiFi 관측 보정 timer: 10초마다 `bin/wifi_observe.php` 실행 - 외출/귀가 팬 정책: 팬 정책 적용 루프에서 기본 30초마다 서울 HA의 휴대폰 device tracker를 확인 - WebSocket 소스 변경 감지: 15초마다 확인 후 재시작 @@ -226,7 +226,7 @@ control-wifi-observe.service 13. 저전압/스로틀링 상태 파일에는 최근 episode 시작/종료를 보관하고, 최근 10분 발생 횟수, 감지 누적시간, 감지 비율을 계산합니다. 14. UPS/배터리 장치가 제거되어 배터리 센서 조회와 잔여 시간 학습 계산은 기본적으로 돌리지 않습니다. 15. System Notice 조건이 맞으면 Control이 `system_notice_logs`에 이력을 저장합니다. -16. 대시보드 첫 화면에는 팬/전원/스로틀링/WiFi/핵심 차트를 우선 배치하고, 상세 차트, 프로세스 후보, 사용자 서비스, 시놀로지 원격 로그, dmesg는 접힘 영역으로 분리합니다. +16. 대시보드 첫 화면에는 팬/전원/스로틀링/WiFi/핵심 차트를 우선 배치하고, 상세 차트, 프로세스 후보, 사용자 서비스, dmesg는 접힘 영역으로 분리합니다. ## 팬 판단 온도 diff --git a/public/api.php b/public/api.php index aea4402..f6cf8d5 100644 --- a/public/api.php +++ b/public/api.php @@ -188,7 +188,7 @@ function command_first_line(array $cmd, bool $root = false, int $timeout = 3): s return (int)$result['code'] === 0 && $lines ? (string)$lines[0] : ''; } -function remote_log_status(): array +function log_retention_status(): array { $journalDir = '/var/log/journal'; $journalDisk = command_first_line(['/usr/bin/journalctl', '--disk-usage', '--no-pager'], false, 3); @@ -4681,7 +4681,7 @@ function collect_snapshot(bool $applyFan = true): array 'history' => $history, 'processes' => $processes, 'custom_services' => custom_systemd_services(), - 'remote_logs' => remote_log_status(), + 'log_status' => log_retention_status(), 'touch_display' => touch_display_status(), 'fan_spike' => $fanSpike, 'fan_spike_history' => fan_spike_history((int)setting_value('display.fan_notice_history_limit')), diff --git a/public/assets/app.js b/public/assets/app.js index 893dc2c..7f23237 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -37,7 +37,7 @@ statusBatteryRemaining: $('#statusBatteryRemaining'), batteryRuntimeTooltip: $('#batteryRuntimeTooltip'), spikeLogList: $('#spikeLogList'), - remoteLogList: $('#remoteLogList'), + logStatusList: $('#logStatusList'), customServiceList: $('#customServiceList'), noticeBaseline: $('#noticeBaseline'), rebootBtn: $('#rebootBtn'), @@ -203,22 +203,14 @@ noNoticeHistory: 'No system notice history.', customServices: 'Custom Services', noCustomServices: 'No custom services.', - remoteLogs: 'Remote Logs', - remoteLogsLoading: 'Remote log status loading...', - remotePiToSynology: 'Raspberry -> Synology', - remoteSynologyToPi: 'Synology -> Raspberry', - remotePersistentJournal: 'Persistent Journal', - remoteCrashLogs: 'Crash Logs', - remoteOk: 'OK', - remoteWarn: 'Check', - remoteTarget: 'Target', - remoteTransport: 'Transport', - remoteQueue: 'Queue', - remoteListener: 'Listener', - remoteLatest: 'Latest', - remoteFiles: 'Files', - remoteUsage: 'Usage', - remoteBoots: 'Boots', + logStatus: 'Log Status', + logStatusLoading: 'Log status loading...', + logPersistentJournal: 'Persistent Journal', + logCrashLogs: 'Crash Logs', + logOk: 'OK', + logWarn: 'Check', + logUsage: 'Usage', + logBoots: 'Boots', logFilterAll: 'All', logFilterImportant: 'Important', logFilterError: 'Error', @@ -230,8 +222,8 @@ qualityOk: 'OK', qualityWarn: 'Increasing', qualityBad: 'Attention', - remoteSaved: 'Saved', - remotePending: 'Pending', + logSaved: 'Saved', + logPending: 'Pending', serviceLogs: 'Logs', serviceEnabled: 'enabled', servicePid: 'pid', @@ -435,22 +427,14 @@ noNoticeHistory: '시스템 알림 이력이 없습니다.', customServices: '사용자 서비스', noCustomServices: '사용자 생성 서비스가 없습니다.', - remoteLogs: '원격 로그', - remoteLogsLoading: '원격 로그 상태 확인 중...', - remotePiToSynology: '라즈베리파이 -> 시놀로지', - remoteSynologyToPi: '시놀로지 -> 라즈베리파이', - remotePersistentJournal: '영구 저널', - remoteCrashLogs: '커널 크래시', - remoteOk: '정상', - remoteWarn: '확인', - remoteTarget: '대상', - remoteTransport: '전송', - remoteQueue: '대기열', - remoteListener: '수신', - remoteLatest: '최근', - remoteFiles: '파일', - remoteUsage: '사용량', - remoteBoots: '부팅 이력', + logStatus: '로그 보존', + logStatusLoading: '로그 보존 상태 확인 중...', + logPersistentJournal: '영구 저널', + logCrashLogs: '커널 크래시', + logOk: '정상', + logWarn: '확인', + logUsage: '사용량', + logBoots: '부팅 이력', logFilterAll: '전체', logFilterImportant: '중요', logFilterError: '오류', @@ -462,8 +446,8 @@ qualityOk: '정상', qualityWarn: '증가', qualityBad: '주의', - remoteSaved: '저장', - remotePending: '대기', + logSaved: '저장', + logPending: '대기', serviceLogs: '로그', serviceEnabled: '활성화', servicePid: 'PID', @@ -2086,56 +2070,56 @@ : `