Add background WiFi observation timer

This commit is contained in:
seo
2026-06-08 02:06:37 +09:00
parent 547f29aa16
commit e5885b5a9d
4 changed files with 88 additions and 6 deletions
+31 -6
View File
@@ -52,6 +52,8 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를
- `apply_policy.php`: CLI/cron 팬 정책 적용
- `bin/control_ws.php`: WebSocket 서버. 핵심 PHP 파일 변경 감지 시 종료되고 systemd가 재시작해 새 코드를 로드
- `bin/push_healthcheck.php`: 작업스케줄러용 Push 헬스체크 CLI
- `bin/wifi_observe.php`: 5G WiFi 연결 시간 보정을 위한 시스템단 관측 CLI
- `systemd/control-wifi-observe.*`: WiFi 관측 CLI를 주기적으로 실행하는 systemd unit 예시
## 데이터/저장소
@@ -115,6 +117,25 @@ control-push-healthcheck.service
`silent: true`는 소리와 진동을 줄이는 옵션이며 완전히 보이지 않는 알림이 아닙니다. Web Push는 사용자에게 보이는 알림을 전제로 운영합니다.
## WiFi 관측 자동화
5G 외부 WiFi 모듈은 `iw station dump``connected time`을 제공하지 않는 경우가 있어, 서버가 MAC별 최초 감지 시각을 DB에 저장하고 경과 시간을 계산합니다.
기존 대시보드 조회만으로도 보정은 가능하지만, 사용자가 접속하지 않은 시간에는 최초 감지가 늦어질 수 있습니다. 이를 막기 위해 다음 systemd timer가 10초마다 관측 CLI를 실행합니다.
```bash
control-wifi-observe.timer
control-wifi-observe.service
```
실행 명령은 다음과 같습니다.
```bash
/usr/bin/php /var/www/control/bin/wifi_observe.php
```
이 작업은 팬 정책, 차트 로그 저장, Push 발송과 분리되어 있으며 WiFi client 목록 확인과 `wifi_observed_sessions` 갱신만 수행합니다.
## 처리 흐름
1. 화면 진입 시 로그인 세션과 remember token을 확인합니다.
@@ -122,12 +143,13 @@ control-push-healthcheck.service
3. WebSocket 연결이 성공하면 `status` 메시지로 갱신하고, 실패하면 HTTP fallback을 사용합니다.
4. 팬 조작은 상태 저장, 정책 적용, 로그 저장 순서로 처리합니다.
5. WiFi client 목록은 `iw station dump`와 dnsmasq lease를 조합하고, 5G 연결 시간이 `N/A`이면 MAC 기준 최초 감지 시간을 DB에 저장해 경과 시간을 계산합니다.
6. Push 등록은 권한 요청과 구독 저장이 끝나면 즉시 상태를 갱신합니다.
7. WakeLock 버튼은 활성 상태를 초록색 버튼으로 표시합니다.
8. Reboot 버튼은 `재부팅` 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다.
9. Translate 버튼은 최초 접속 시 디바이스 언어를 기본값으로 사용하고, 변경값은 `localStorage``controlLang`에 저장합니다. 라벨은 `Translate` 또는 `번역`으로만 표시합니다.
10. Theme 버튼은 기본값 `dark`로 시작하고, 변경값은 `localStorage``controlTheme`에 저장합니다. 라벨은 `Theme` 또는 `테마`로만 표시합니다.
11. Push 발송, 수신, 표시, 클릭 이벤트를 기록하고 구독 DB의 건강 상태를 갱신합니다.
6. `control-wifi-observe.timer`는 사용자 접속과 무관하게 10초마다 5G 관측 세션을 갱신합니다.
7. Push 등록은 권한 요청과 구독 저장이 끝나면 즉시 상태를 갱신합니다.
8. WakeLock 버튼은 활성 상태를 초록색 버튼으로 표시합니다.
9. Reboot 버튼은 `재부팅` 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다.
10. Translate 버튼은 최초 접속 시 디바이스 언어를 기본값으로 사용하고, 변경값은 `localStorage``controlLang`에 저장합니다. 라벨은 `Translate` 또는 `번역`로만 표시합니다.
11. Theme 버튼은 기본값 `dark`로 시작하고, 변경값은 `localStorage``controlTheme`에 저장합니다. 라벨은 `Theme` 또는 `테마`로만 표시합니다.
12. Push 발송, 수신, 표시, 클릭 이벤트를 기록하고 구독 DB의 건강 상태를 갱신합니다.
## 주요 함수/모듈
@@ -135,6 +157,7 @@ control-push-healthcheck.service
- `apply_fan_policy()`: 팬 목표값 계산과 적용
- `json_out()`: API JSON 응답 표준화
- `apply_observed_wifi_connected_time()`: 5G WiFi 연결 시간이 없는 client에 서버 관측 경과 시간 적용
- `bin/wifi_observe.php`: 화면 접속 없이 `wifi_data()`를 호출해 5G 관측 세션을 선제 갱신
- `push_subscribe.js`: Push 구독 등록과 복구
- `push_health_summary()`: 상태별 Push 기기 수 집계
- `send_push_healthcheck_if_due()`: 쿨다운 기반 헬스체크 알림 발송
@@ -156,7 +179,9 @@ control-push-healthcheck.service
- 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다.
- 2.4G 내장 WiFi는 `hostapd-24g.service` 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다.
- 2026-06-07 조사 기준 `disassoc_low_ack=1`은 로그에 직접 원인으로 남지 않았고, 채널 변경 후 단말이 안정적으로 붙은 상태에서는 제거하지 않고 관찰합니다. 동일 단말이 짧게 재연결을 반복하면 그때 `disassoc_low_ack` 비활성화를 검토합니다.
- 2.4G WiFi 연결 시간은 내장 AP가 제공하는 `connected time`을 그대로 사용합니다. 2026-06-08 확인 기준 2.4G 연결 시간 누락은 없습니다.
- 5G WiFi 연결 시간은 외부 모듈이 값을 제공하지 않을 때 서버가 처음 감지한 시각 기준으로 계산합니다. 현재 5G 목록에서 MAC이 사라지면 관측 세션을 즉시 종료하므로 재연결 시 0부터 다시 누적됩니다.
- `control-wifi-observe.timer`는 10초마다 `/var/www/control/bin/wifi_observe.php`를 실행해 사용자가 대시보드에 접속하지 않아도 5G 연결 시간 카운터를 시작하고 유지합니다. 상태는 `systemctl status control-wifi-observe.timer``/var/log/control-wifi-observe.log`에서 확인합니다.
- WebSocket은 장기 실행 프로세스이므로 `public/api.php`, `config/config.php`, `bin/control_ws.php` 변경을 감지하면 15초 안에 종료되고 `control-websocket.service`가 새 프로세스로 재시작합니다.
- WebSocket 장기 실행 중 DB 연결이 끊길 수 있으므로 reconnect 로그를 확인합니다.
- Push 구독 자동 복구가 과도한 반복 등록을 만들지 않는지 확인합니다.
+33
View File
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
define('CONTROL_API_LIBRARY', true);
require_once __DIR__ . '/../public/api.php';
$data = wifi_data();
$clients = is_array($data['clients'] ?? null) ? $data['clients'] : [];
$missing5g = 0;
$missing24 = 0;
foreach ($clients as $client) {
$band = (string)($client['band'] ?? '');
if (!wifi_connected_time_missing($client['connected_time'] ?? null)) {
continue;
}
if ($band === '5G') {
$missing5g++;
} elseif ($band === '2.4G') {
$missing24++;
}
}
echo json_encode([
'ok' => true,
'generated_at' => date('Y-m-d H:i:s'),
'count24' => (int)($data['count24'] ?? 0),
'count5' => (int)($data['count5'] ?? 0),
'missing_connected_time_24g' => $missing24,
'missing_connected_time_5g' => $missing5g,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=Control WiFi observed session refresh
Documentation=file:/var/www/control/bin/wifi_observe.php
[Service]
Type=oneshot
User=root
Group=root
WorkingDirectory=/var/www/control
ExecStart=/usr/bin/php /var/www/control/bin/wifi_observe.php
StandardOutput=append:/var/log/control-wifi-observe.log
StandardError=append:/var/log/control-wifi-observe.log
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=Refresh Control WiFi observed sessions every 10 seconds
[Timer]
OnBootSec=20s
OnUnitActiveSec=10s
AccuracySec=1s
Persistent=true
Unit=control-wifi-observe.service
[Install]
WantedBy=timers.target