팬 판단 온도 계산 보강

This commit is contained in:
seo
2026-07-03 10:58:38 +09:00
parent a824d3bcda
commit 6fceae0c01
3 changed files with 47 additions and 7 deletions
+10 -1
View File
@@ -108,7 +108,7 @@ WebSocket 장기 실행 프로세스에서는 1분 단위 단기 집계 결과
설정 가능한 항목은 다음 범위입니다.
- 팬 자동 제어: 팬 시작 온도, 최대 온도, 즉시 최대 PWM 온도, 자동 상승/하강 PWM step
- 팬 자동 제어: 팬 시작 온도, 최대 온도, 즉시 최대 PWM 온도, RP1 온도 반영 비율, 팬 판단 온도 여유, 자동 상승/하강 PWM step
- 보안 정책: 자동 로그인 유지 기간, remember 쿠키 Secure/SameSite, CSRF 길이, remember 토큰 길이, User-Agent/IP 접두사 검증, 로그인 실패 잠금, 재부팅 허용 여부, 재부팅 확인 문구, 명령 timeout, WiFi 조작 허용 여부
- 화면/진단 표시: 프로세스 후보 수, 사용자 서비스 로그 줄 수, 사용자 서비스 캐시 시간, 팬 이상 이력 수
- 저전압/스로틀링: 최근 판정창, 복구 중 유지 시간, 반복 발생 기준 횟수
@@ -186,6 +186,14 @@ control-wifi-observe.service
16. System Notice 조건이 맞으면 Control이 `system_notice_logs`에 이력을 저장합니다.
17. 대시보드 첫 화면에는 팬/전원/스로틀링/WiFi/핵심 차트를 우선 배치하고, 상세 차트, 프로세스 후보, 사용자 서비스, dmesg는 접힘 영역으로 분리합니다.
## 팬 판단 온도
화면의 CPU 온도 표시는 기존처럼 CPU 센서 값을 보여줍니다. 자동 팬 제어는 CPU만 보지 않고 RP1 온도도 함께 반영한 `fan_control_temp()` 값을 사용합니다.
계산은 CPU 온도와 RP1 온도를 설정된 `RP1 온도 반영 비율`로 섞은 뒤 `팬 판단 온도 여유`를 더하고, 이 값과 CPU 온도 중 더 높은 값을 팬 판단 온도로 삼습니다. 기본값은 RP1 35%, 여유 1.5도입니다. RP1 값이 없으면 CPU 온도만 사용합니다.
이 구조는 팬 하나가 CPU와 RP1 주변 열을 같이 빼는 현실을 반영하되, 화면의 CPU 표기와 차트 의미는 흐리지 않도록 팬 제어 내부 값만 따로 둡니다. API 응답에는 `fan.control_temp_c``system.fan_control_temp_c`가 함께 내려갑니다.
## 주요 함수/모듈
- `collect_snapshot()`: 센서와 fan 상태 snapshot 생성
@@ -195,6 +203,7 @@ control-wifi-observe.service
- `throttled_event_status()`: 저전압/스로틀링 episode 이력, 복구 중/반복 발생 판정, 최근 10분 통계를 계산
- `throttled_statuses()`: 라즈베리파이 throttled flag를 읽고 저전압/스로틀링 감지 이력을 상태 파일로 추적
- `apply_fan_policy()`: 팬 목표값 계산과 적용
- `fan_control_temp()`: CPU/RP1 혼합 팬 판단 온도 계산
- `json_out()`: API JSON 응답 표준화
- `apply_observed_wifi_connected_time()`: 5G WiFi 연결 시간이 없는 client에 서버 관측 경과 시간 적용
- `wifi_client_aliases()`, `save_wifi_client_alias()`: MAC별 WiFi 호스트명 조회와 저장
+2
View File
@@ -151,6 +151,8 @@ function setting_definitions(): array
'fan.auto_min_temp' => ['group' => 'fan', 'label' => '팬 시작 온도', 'type' => 'number', 'default' => 50, 'min' => 30, 'max' => 90, 'step' => 0.5, 'unit' => 'C'],
'fan.auto_max_temp' => ['group' => 'fan', 'label' => '팬 최대 온도', 'type' => 'number', 'default' => 80, 'min' => 45, 'max' => 100, 'step' => 0.5, 'unit' => 'C'],
'fan.full_temp' => ['group' => 'fan', 'label' => '즉시 최대 PWM 온도', 'type' => 'number', 'default' => 80, 'min' => 45, 'max' => 100, 'step' => 0.5, 'unit' => 'C'],
'fan.rp1_temp_weight' => ['group' => 'fan', 'label' => 'RP1 온도 반영 비율', 'type' => 'number', 'default' => 0.35, 'min' => 0, 'max' => 1, 'step' => 0.01, 'unit' => 'x'],
'fan.control_temp_headroom' => ['group' => 'fan', 'label' => '팬 판단 온도 여유', 'type' => 'number', 'default' => 1.5, 'min' => 0, 'max' => 8, 'step' => 0.1, 'unit' => 'C'],
'fan.ramp_up_step' => ['group' => 'fan', 'label' => '자동 상승 PWM step', 'type' => 'number', 'default' => 2, 'min' => 1, 'max' => 80, 'step' => 1, 'unit' => 'PWM'],
'fan.ramp_down_step' => ['group' => 'fan', 'label' => '자동 하강 PWM step', 'type' => 'number', 'default' => 2, 'min' => 1, 'max' => 80, 'step' => 1, 'unit' => 'PWM'],
'event.recent_window_seconds' => ['group' => 'event', 'label' => '저전압/스로틀링 최근 판정창', 'type' => 'number', 'default' => 600, 'min' => 60, 'max' => 7200, 'step' => 30, 'unit' => '초'],
+35 -6
View File
@@ -398,6 +398,22 @@ function cpu_temp(): float
return 0.0;
}
function fan_control_temp(float $cpuTemp, ?float $rp1Temp): float
{
if ($cpuTemp <= 0) {
return $rp1Temp !== null ? round($rp1Temp, 2) : 0.0;
}
if ($rp1Temp === null || $rp1Temp <= 0) {
return round($cpuTemp, 2);
}
$rp1Weight = clamp_float((float)setting_value('fan.rp1_temp_weight'), 0.0, 1.0);
$mixed = ($cpuTemp * (1.0 - $rp1Weight)) + ($rp1Temp * $rp1Weight);
$headroom = (float)setting_value('fan.control_temp_headroom');
return round(max($cpuTemp, $mixed + $headroom), 2);
}
function fan_target_pwm(float $temp): int
{
$minTemp = (float)setting_value('fan.auto_min_temp');
@@ -455,7 +471,9 @@ function apply_fan_policy(): array
$state = get_control_state();
$paths = fan_paths();
$temp = cpu_temp();
$cpuTemp = cpu_temp();
$rp1Temp = rp1_temp_c();
$controlTemp = fan_control_temp($cpuTemp, $rp1Temp);
$mode = (string)($state['mode'] ?? 'auto');
if (!in_array($mode, ['auto', 'manual', 'off'], true)) {
@@ -468,10 +486,10 @@ function apply_fan_policy(): array
$desired = match ($mode) {
'manual' => $manualPwm,
'off' => 0,
default => fan_target_pwm($temp),
default => fan_target_pwm($controlTemp),
};
$target = $mode === 'auto'
? fan_ramped_pwm($currentPwm, $desired, $temp)
? fan_ramped_pwm($currentPwm, $desired, $controlTemp)
: $desired;
$enableOk = write_sys_value($paths['enable'], $mode === 'off' ? 0 : 1);
@@ -487,7 +505,9 @@ function apply_fan_policy(): array
'mode' => $mode,
'target_pwm' => $target,
'actual_pwm' => $actualPwm,
'temp_c' => $temp,
'temp_c' => $cpuTemp,
'rp1_temp_c' => $rp1Temp,
'control_temp_c' => $controlTemp,
'rpm' => $rpm,
'ok' => $enableOk && $pwmOk,
'paths' => $paths,
@@ -3182,6 +3202,12 @@ function collect_snapshot(bool $applyFan = true): array
if ($temp <= 0) {
$temp = (float)$policy['temp_c'];
}
$rp1Temp = isset($policy['rp1_temp_c']) && is_numeric($policy['rp1_temp_c'])
? (float)$policy['rp1_temp_c']
: rp1_temp_c();
$controlTemp = isset($policy['control_temp_c']) && is_numeric($policy['control_temp_c'])
? (float)$policy['control_temp_c']
: fan_control_temp($temp, $rp1Temp);
$load = sys_getloadavg() ?: [0, 0, 0];
$mem = mem_info();
@@ -3202,7 +3228,7 @@ function collect_snapshot(bool $applyFan = true): array
'cpu_temp_c' => $temp,
'fan_rpm' => $rpm,
'fan_efficiency' => fan_efficiency($rpm, $temp, $cpuPower['watts'] ?? null),
'rp1_temp_c' => rp1_temp_c(),
'rp1_temp_c' => $rp1Temp,
'cpu_voltage' => $cpuPower['voltage'],
'cpu_watts' => $cpuPower['watts'],
'battery_voltage' => $battery['voltage'],
@@ -3231,12 +3257,15 @@ function collect_snapshot(bool $applyFan = true): array
'rpm' => $rpm,
'enable' => $policy['enable_value'],
'target_pwm' => $policy['target_pwm'],
'control_temp_c' => $controlTemp,
'policy_ok' => $policy['ok'],
'paths' => $policy['paths'],
];
$system = array_merge($os, [
'temp_c' => $temp,
'rp1_temp_c' => $rp1Temp,
'fan_control_temp_c' => $controlTemp,
'load' => [
round((float)$load[0], 2),
round((float)$load[1], 2),
@@ -3258,7 +3287,7 @@ function collect_snapshot(bool $applyFan = true): array
'temp_c' => $temp,
'fan_rpm' => $rpm,
'fan_efficiency' => fan_efficiency($rpm, $temp, $cpuPower['watts'] ?? null),
'rp1_temp_c' => rp1_temp_c(),
'rp1_temp_c' => $rp1Temp,
'cpu_voltage' => $cpuPower['voltage'],
'cpu_watts' => $cpuPower['watts'],
'battery_voltage' => $battery['voltage'],