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 팬 정책 적용 - `apply_policy.php`: CLI/cron 팬 정책 적용
- `bin/control_ws.php`: WebSocket 서버. 핵심 PHP 파일 변경 감지 시 종료되고 systemd가 재시작해 새 코드를 로드 - `bin/control_ws.php`: WebSocket 서버. 핵심 PHP 파일 변경 감지 시 종료되고 systemd가 재시작해 새 코드를 로드
- `bin/push_healthcheck.php`: 작업스케줄러용 Push 헬스체크 CLI - `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는 사용자에게 보이는 알림을 전제로 운영합니다. `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을 확인합니다. 1. 화면 진입 시 로그인 세션과 remember token을 확인합니다.
@@ -122,12 +143,13 @@ control-push-healthcheck.service
3. WebSocket 연결이 성공하면 `status` 메시지로 갱신하고, 실패하면 HTTP fallback을 사용합니다. 3. WebSocket 연결이 성공하면 `status` 메시지로 갱신하고, 실패하면 HTTP fallback을 사용합니다.
4. 팬 조작은 상태 저장, 정책 적용, 로그 저장 순서로 처리합니다. 4. 팬 조작은 상태 저장, 정책 적용, 로그 저장 순서로 처리합니다.
5. WiFi client 목록은 `iw station dump`와 dnsmasq lease를 조합하고, 5G 연결 시간이 `N/A`이면 MAC 기준 최초 감지 시간을 DB에 저장해 경과 시간을 계산합니다. 5. WiFi client 목록은 `iw station dump`와 dnsmasq lease를 조합하고, 5G 연결 시간이 `N/A`이면 MAC 기준 최초 감지 시간을 DB에 저장해 경과 시간을 계산합니다.
6. Push 등록은 권한 요청과 구독 저장이 끝나면 즉시 상태를 갱신합니다. 6. `control-wifi-observe.timer`는 사용자 접속과 무관하게 10초마다 5G 관측 세션을 갱신합니다.
7. WakeLock 버튼은 활성 상태를 초록색 버튼으로 표시합니다. 7. Push 등록은 권한 요청과 구독 저장이 끝나면 즉시 상태를 갱신합니다.
8. Reboot 버튼은 `재부팅` 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다. 8. WakeLock 버튼은 활성 상태를 초록색 버튼으로 표시합니다.
9. Translate 버튼은 최초 접속 시 디바이스 언어를 기본값으로 사용하고, 변경값은 `localStorage``controlLang`에 저장합니다. 라벨은 `Translate` 또는 `번역`으로만 표시합니다. 9. Reboot 버튼은 `재부팅` 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다.
10. Theme 버튼은 기본값 `dark`로 시작하고, 변경값은 `localStorage``controlTheme`에 저장합니다. 라벨은 `Theme` 또는 `테마`로만 표시합니다. 10. Translate 버튼은 최초 접속 시 디바이스 언어를 기본값으로 사용하고, 변경값은 `localStorage``controlLang`에 저장합니다. 라벨은 `Translate` 또는 `번역`로만 표시합니다.
11. Push 발송, 수신, 표시, 클릭 이벤트를 기록하고 구독 DB의 건강 상태를 갱신합니다. 11. Theme 버튼은 기본값 `dark`로 시작하고, 변경값은 `localStorage``controlTheme`에 저장합니다. 라벨은 `Theme` 또는 `테마`로만 표시합니다.
12. Push 발송, 수신, 표시, 클릭 이벤트를 기록하고 구독 DB의 건강 상태를 갱신합니다.
## 주요 함수/모듈 ## 주요 함수/모듈
@@ -135,6 +157,7 @@ control-push-healthcheck.service
- `apply_fan_policy()`: 팬 목표값 계산과 적용 - `apply_fan_policy()`: 팬 목표값 계산과 적용
- `json_out()`: API JSON 응답 표준화 - `json_out()`: API JSON 응답 표준화
- `apply_observed_wifi_connected_time()`: 5G WiFi 연결 시간이 없는 client에 서버 관측 경과 시간 적용 - `apply_observed_wifi_connected_time()`: 5G WiFi 연결 시간이 없는 client에 서버 관측 경과 시간 적용
- `bin/wifi_observe.php`: 화면 접속 없이 `wifi_data()`를 호출해 5G 관측 세션을 선제 갱신
- `push_subscribe.js`: Push 구독 등록과 복구 - `push_subscribe.js`: Push 구독 등록과 복구
- `push_health_summary()`: 상태별 Push 기기 수 집계 - `push_health_summary()`: 상태별 Push 기기 수 집계
- `send_push_healthcheck_if_due()`: 쿨다운 기반 헬스체크 알림 발송 - `send_push_healthcheck_if_due()`: 쿨다운 기반 헬스체크 알림 발송
@@ -156,7 +179,9 @@ control-push-healthcheck.service
- 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다. - 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다.
- 2.4G 내장 WiFi는 `hostapd-24g.service` 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다. - 2.4G 내장 WiFi는 `hostapd-24g.service` 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다.
- 2026-06-07 조사 기준 `disassoc_low_ack=1`은 로그에 직접 원인으로 남지 않았고, 채널 변경 후 단말이 안정적으로 붙은 상태에서는 제거하지 않고 관찰합니다. 동일 단말이 짧게 재연결을 반복하면 그때 `disassoc_low_ack` 비활성화를 검토합니다. - 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부터 다시 누적됩니다. - 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은 장기 실행 프로세스이므로 `public/api.php`, `config/config.php`, `bin/control_ws.php` 변경을 감지하면 15초 안에 종료되고 `control-websocket.service`가 새 프로세스로 재시작합니다.
- WebSocket 장기 실행 중 DB 연결이 끊길 수 있으므로 reconnect 로그를 확인합니다. - WebSocket 장기 실행 중 DB 연결이 끊길 수 있으므로 reconnect 로그를 확인합니다.
- Push 구독 자동 복구가 과도한 반복 등록을 만들지 않는지 확인합니다. - 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