From b6d12f9a0e44928112eb0b884b900c2d4afe0439 Mon Sep 17 00:00:00 2001 From: seo Date: Thu, 18 Jun 2026 04:28:12 +0900 Subject: [PATCH] Fix throttled status web access --- README.md | 6 ++++-- public/api.php | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9343169..b3d8a8d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 - PWM slider 기반 수동 팬 제어 - CPU/RP1 온도, 팬 RPM, 팬 효율, CPU 전력, 배터리 상태 차트 - 배터리 잔여 시간은 1S8P 병렬팩 `2200mAh x 8 = 17600mAh`, nominal `3.7V`, 총 `65.12Wh` 기준으로 계산 -- 라즈베리파이 저전압/스로틀링 현재 상태, 최근 감지 시각, 지속시간 표시 +- 라즈베리파이 저전압/스로틀링 현재 상태, 부팅 후 이력, 최근 감지 시각, 지속시간 표시 - WiFi client 목록과 2.4G/5G client 수 표시 - WiFi client 상태 표시 - 5G 외부 WiFi 모듈이 연결 시간을 제공하지 않는 경우 서버 관측 기반 연결 시간 보정 @@ -155,12 +155,13 @@ control-wifi-observe.service 9. Reboot 버튼은 `재부팅` 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다. 확인 단어 입력창에서 Enter를 눌러도 같은 Reboot 흐름이 다시 열리지 않도록 키 이벤트 기본 동작과 중복 실행을 차단합니다. 10. Translate 버튼은 최초 접속 시 디바이스 언어를 기본값으로 사용하고, 변경값은 `localStorage`의 `controlLang`에 저장합니다. 라벨은 `Translate` 또는 `번역`으로만 표시합니다. 11. Theme 버튼은 기본값 `dark`로 시작하고, 변경값은 `localStorage`의 `controlTheme`에 저장합니다. 라벨은 `Theme` 또는 `테마`로만 표시합니다. -12. 시스템 상태는 `vcgencmd get_throttled`를 읽어 현재 저전압/스로틀링 여부와 부팅 후 이력, 최근 감지 시각, 현재/최근 지속시간을 표시합니다. +12. 시스템 상태는 `vcgencmd get_throttled`를 읽어 현재 저전압/스로틀링 여부와 부팅 후 이력, 최근 감지 시각, 현재/최근 지속시간을 표시합니다. 웹 서버 실행 계정이 `/dev/vcio`를 직접 읽지 못하면 기존 sudo 실행 경로로 한 번 더 조회합니다. 13. Push 발송, 수신, 표시, 클릭 이벤트를 기록하고 구독 DB의 건강 상태를 갱신합니다. ## 주요 함수/모듈 - `collect_snapshot()`: 센서와 fan 상태 snapshot 생성 +- `read_throttled_flags()`: `vcgencmd get_throttled`를 직접 조회하고, 권한 문제로 실패하면 sudo 경유 조회를 시도 - `throttled_statuses()`: 라즈베리파이 throttled flag를 읽고 저전압/스로틀링 감지 이력을 상태 파일로 추적 - `low_voltage_status()`: 기존 호출 호환을 위한 저전압 상태 wrapper - `apply_fan_policy()`: 팬 목표값 계산과 적용 @@ -199,4 +200,5 @@ control-wifi-observe.service - Push 헬스체크 timer 상태는 `systemctl list-timers --all control-push-healthcheck.timer`로 확인합니다. - `failed`, `stale` 기기는 알림 권한, 브라우저 데이터 삭제, PWA 재설치 여부를 확인합니다. - Reboot API 사용 전 웹 서버 실행 계정의 sudoers에 `/usr/sbin/reboot` 비밀번호 없는 실행 권한이 제한적으로 설정되어 있는지 확인합니다. +- 저전압/스로틀링이 `N/A`로 보이면 웹 서버 실행 계정의 `/dev/vcio` 접근 권한과 `/usr/bin/vcgencmd get_throttled` sudoers 허용 여부를 확인합니다. - 언어/테마 표시가 예상과 다르면 브라우저 localStorage의 `controlLang`, `controlTheme` 값을 확인합니다. diff --git a/public/api.php b/public/api.php index 95ee532..57e3763 100644 --- a/public/api.php +++ b/public/api.php @@ -204,22 +204,51 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s ]; } -function throttled_statuses(): array +function read_throttled_flags(): array { $result = sh(['/usr/bin/vcgencmd', 'get_throttled'], false, 3); $raw = trim((string)$result['out']); $flags = null; + $source = 'direct'; if ((int)$result['code'] === 0 && preg_match('/throttled=0x([0-9a-f]+)/i', $raw, $m)) { $flags = hexdec($m[1]); } + if ($flags === null) { + $sudoResult = sh(['/usr/bin/vcgencmd', 'get_throttled'], true, 3); + $sudoRaw = trim((string)$sudoResult['out']); + if ((int)$sudoResult['code'] === 0 && preg_match('/throttled=0x([0-9a-f]+)/i', $sudoRaw, $m)) { + $result = $sudoResult; + $raw = $sudoRaw; + $flags = hexdec($m[1]); + $source = 'sudo'; + } + } + + return [ + 'result' => $result, + 'raw' => $raw, + 'flags' => $flags, + 'source' => $source, + ]; +} + +function throttled_statuses(): array +{ + $read = read_throttled_flags(); + $raw = (string)$read['raw']; + $flags = $read['flags']; + $source = (string)$read['source']; + $lowVoltage = throttled_event_status($flags, $raw, 0x1, 0x10000, '/tmp/control-low-voltage-state.json'); $throttling = throttled_event_status($flags, $raw, 0x4, 0x40000, '/tmp/control-throttling-state.json'); + $lowVoltage['source'] = $source; $lowVoltage['freq_capped'] = $flags !== null && (bool)($flags & 0x2); $lowVoltage['throttled'] = $flags !== null && (bool)($flags & 0x4); $lowVoltage['soft_temp_limit'] = $flags !== null && (bool)($flags & 0x8); + $throttling['source'] = $source; $throttling['low_voltage'] = $flags !== null && (bool)($flags & 0x1); $throttling['freq_capped'] = $flags !== null && (bool)($flags & 0x2); $throttling['soft_temp_limit'] = $flags !== null && (bool)($flags & 0x8);