Control WiFi 관측값 유지와 스크롤 보존

This commit is contained in:
seo
2026-06-26 18:26:46 +09:00
parent 0acb193690
commit 4f6b8c8ebb
5 changed files with 260 additions and 24 deletions
+173 -13
View File
@@ -2860,6 +2860,171 @@ function wifi_scan_failure_reason(int $code, string $out): string
return '스캔 결과가 비어 있습니다. AP 모드, 드라이버 제한, 권한 문제 중 하나일 수 있습니다.';
}
function save_wifi_scan_observations(array $networks): void
{
if ($networks === []) {
return;
}
try {
$stmt = db()->prepare("
INSERT INTO wifi_scan_observations
(bssid, iface, band, ssid, freq, channel, signal_dbm, signal_text, security_text, capability_text, rates_text, channel_width, ht, vht, he, first_seen_at, last_seen_at)
VALUES
(:bssid, :iface, :band, :ssid, :freq, :channel, :signal_dbm, :signal_text, :security_text, :capability_text, :rates_text, :channel_width, :ht, :vht, :he, NOW(), NOW())
ON DUPLICATE KEY UPDATE
iface = VALUES(iface),
band = VALUES(band),
ssid = VALUES(ssid),
freq = VALUES(freq),
channel = VALUES(channel),
signal_dbm = VALUES(signal_dbm),
signal_text = VALUES(signal_text),
security_text = VALUES(security_text),
capability_text = VALUES(capability_text),
rates_text = VALUES(rates_text),
channel_width = VALUES(channel_width),
ht = VALUES(ht),
vht = VALUES(vht),
he = VALUES(he),
last_seen_at = NOW()
");
foreach ($networks as $network) {
$bssid = strtolower((string)($network['bssid'] ?? ''));
if (!wifi_valid_mac($bssid)) {
continue;
}
$stmt->execute([
':bssid' => $bssid,
':iface' => mb_substr((string)($network['iface'] ?? ''), 0, 32),
':band' => mb_substr((string)($network['band'] ?? ''), 0, 16),
':ssid' => mb_substr((string)($network['ssid'] ?? ''), 0, 255),
':freq' => is_numeric($network['freq'] ?? null) ? (int)$network['freq'] : null,
':channel' => is_numeric($network['channel'] ?? null) ? (int)$network['channel'] : null,
':signal_dbm' => is_numeric($network['signal_dbm'] ?? null) ? (float)$network['signal_dbm'] : null,
':signal_text' => mb_substr((string)($network['signal'] ?? ''), 0, 32),
':security_text' => mb_substr((string)($network['security'] ?? ''), 0, 255),
':capability_text' => mb_substr((string)($network['capability'] ?? ''), 0, 255),
':rates_text' => mb_substr((string)($network['rates'] ?? ''), 0, 255),
':channel_width' => mb_substr((string)($network['channel_width'] ?? ''), 0, 64),
':ht' => !empty($network['ht']) ? 1 : 0,
':vht' => !empty($network['vht']) ? 1 : 0,
':he' => !empty($network['he']) ? 1 : 0,
]);
}
} catch (Throwable) {
return;
}
}
function wifi_scan_observed_networks(int $hours, int $limit): array
{
try {
$hours = max(1, min(720, $hours));
$limit = max(1, min(500, $limit));
$stmt = db()->query("
SELECT
bssid,
iface,
band,
ssid,
freq,
channel,
signal_dbm,
signal_text,
security_text,
capability_text,
rates_text,
channel_width,
ht,
vht,
he,
first_seen_at,
last_seen_at,
TIMESTAMPDIFF(SECOND, last_seen_at, NOW()) AS observed_age_seconds
FROM wifi_scan_observations
WHERE last_seen_at >= DATE_SUB(NOW(), INTERVAL {$hours} HOUR)
ORDER BY
FIELD(band, '2.4G', '5G', '6G', '기타'),
signal_dbm DESC,
last_seen_at DESC
LIMIT {$limit}
");
} catch (Throwable) {
return [];
}
$rows = [];
foreach ($stmt->fetchAll() as $row) {
$signalDbm = is_numeric($row['signal_dbm'] ?? null) ? (float)$row['signal_dbm'] : null;
$rows[] = [
'bssid' => (string)($row['bssid'] ?? ''),
'iface' => (string)($row['iface'] ?? ''),
'band' => (string)($row['band'] ?? ''),
'ssid' => (string)($row['ssid'] ?? ''),
'freq' => is_numeric($row['freq'] ?? null) ? (int)$row['freq'] : null,
'channel' => is_numeric($row['channel'] ?? null) ? (int)$row['channel'] : null,
'signal_dbm' => $signalDbm,
'signal' => (string)($row['signal_text'] ?? ($signalDbm === null ? 'N/A' : number_format($signalDbm, 1) . ' dBm')),
'security' => (string)($row['security_text'] ?? ''),
'capability' => (string)($row['capability_text'] ?? ''),
'rates' => (string)($row['rates_text'] ?? ''),
'channel_width' => (string)($row['channel_width'] ?? ''),
'ht' => !empty($row['ht']),
'vht' => !empty($row['vht']),
'he' => !empty($row['he']),
'first_seen_at' => (string)($row['first_seen_at'] ?? ''),
'last_seen_at' => (string)($row['last_seen_at'] ?? ''),
'observed_age_seconds' => is_numeric($row['observed_age_seconds'] ?? null) ? (int)$row['observed_age_seconds'] : null,
'observed_source' => 'db',
];
}
return $rows;
}
function merge_wifi_scan_networks(array $freshNetworks, array $observedNetworks): array
{
$merged = [];
foreach ($observedNetworks as $network) {
$bssid = strtolower((string)($network['bssid'] ?? ''));
if ($bssid !== '') {
$merged[$bssid] = $network;
}
}
foreach ($freshNetworks as $network) {
$bssid = strtolower((string)($network['bssid'] ?? ''));
if ($bssid === '') {
continue;
}
$network['observed_source'] = 'live';
$network['last_seen_at'] = date('Y-m-d H:i:s');
$network['observed_age_seconds'] = 0;
$merged[$bssid] = $network;
}
$rows = array_values($merged);
usort($rows, static function (array $a, array $b): int {
$bandOrder = ['2.4G' => 0, '5G' => 1, '6G' => 2, '기타' => 3];
$bandCompare = ($bandOrder[$a['band'] ?? '기타'] ?? 9) <=> ($bandOrder[$b['band'] ?? '기타'] ?? 9);
if ($bandCompare !== 0) {
return $bandCompare;
}
$sourceCompare = (($a['observed_source'] ?? '') === 'live' ? 0 : 1) <=> (($b['observed_source'] ?? '') === 'live' ? 0 : 1);
if ($sourceCompare !== 0) {
return $sourceCompare;
}
return (float)($b['signal_dbm'] ?? -999) <=> (float)($a['signal_dbm'] ?? -999);
});
return $rows;
}
function wifi_scan_data(): array
{
if (!(bool)setting_value('wifi.scan_enabled')) {
@@ -2868,7 +3033,7 @@ function wifi_scan_data(): array
'cached' => false,
'generated_at' => null,
'interfaces' => [],
'networks' => [],
'networks' => wifi_scan_observed_networks((int)setting_value('wifi.scan_observed_hours'), (int)setting_value('wifi.scan_max_networks')),
'errors' => [],
];
}
@@ -2908,24 +3073,19 @@ function wifi_scan_data(): array
}
}
usort($networks, static function (array $a, array $b): int {
$bandOrder = ['2.4G' => 0, '5G' => 1, '6G' => 2, '기타' => 3];
$bandCompare = ($bandOrder[$a['band'] ?? '기타'] ?? 9) <=> ($bandOrder[$b['band'] ?? '기타'] ?? 9);
if ($bandCompare !== 0) {
return $bandCompare;
}
return (float)($b['signal_dbm'] ?? -999) <=> (float)($a['signal_dbm'] ?? -999);
});
$max = (int)setting_value('wifi.scan_max_networks');
save_wifi_scan_observations($networks);
$observedNetworks = wifi_scan_observed_networks((int)setting_value('wifi.scan_observed_hours'), $max);
$mergedNetworks = merge_wifi_scan_networks($networks, $observedNetworks);
$payload = [
'enabled' => true,
'cached' => false,
'generated_at' => date('Y-m-d H:i:s'),
'interfaces' => array_values($interfaces),
'networks' => array_slice($networks, 0, $max),
'total_found' => count($networks),
'networks' => array_slice($mergedNetworks, 0, $max),
'live_found' => count($networks),
'total_found' => count($mergedNetworks),
'observed_hours' => (int)setting_value('wifi.scan_observed_hours'),
'errors' => $errors,
];