WiFi 표시값과 잔여 시간 설명 강화

This commit is contained in:
seo
2026-06-26 02:36:30 +09:00
parent a4d8c775e9
commit 4f102efc4b
5 changed files with 316 additions and 20 deletions
+185 -7
View File
@@ -1982,6 +1982,56 @@ function dnsmasq_leases(): array
return $map;
}
function wifi_client_aliases(): array
{
try {
$rows = db()->query("SELECT mac, hostname FROM wifi_client_aliases")->fetchAll();
} catch (Throwable) {
return [];
}
$aliases = [];
foreach ($rows as $row) {
$mac = strtolower((string)($row['mac'] ?? ''));
$hostname = trim((string)($row['hostname'] ?? ''));
if (wifi_valid_mac($mac) && $hostname !== '') {
$aliases[$mac] = $hostname;
}
}
return $aliases;
}
function save_wifi_client_alias(string $mac, string $hostname): array
{
$mac = strtolower(trim($mac));
$hostname = trim(preg_replace('/\s+/', ' ', $hostname) ?? '');
if (!wifi_valid_mac($mac)) {
throw new InvalidArgumentException('bad_mac');
}
if ($hostname === '' || mb_strlen($hostname) > 80) {
throw new InvalidArgumentException('bad_hostname');
}
$stmt = db()->prepare("
INSERT INTO wifi_client_aliases (mac, hostname)
VALUES (:mac, :hostname)
ON DUPLICATE KEY UPDATE
hostname = VALUES(hostname),
updated_at = CURRENT_TIMESTAMP
");
$stmt->execute([
':mac' => $mac,
':hostname' => $hostname,
]);
return [
'mac' => $mac,
'hostname' => $hostname,
];
}
function iw_station_dump(string $iface): string
{
if (!preg_match('/^[A-Za-z0-9_.:-]+$/', $iface)) {
@@ -1991,7 +2041,7 @@ function iw_station_dump(string $iface): string
return sh(['/usr/sbin/iw', 'dev', $iface, 'station', 'dump'], true, 4)['out'];
}
function parse_live_wifi_rows(string $iface, string $band, string $text, array $leases): array
function parse_live_wifi_rows(string $iface, string $band, string $text, array $leases, array $aliases): array
{
$rows = [];
$cur = null;
@@ -2006,16 +2056,24 @@ function parse_live_wifi_rows(string $iface, string $band, string $text, array $
$mac = strtolower($m[1]);
$lease = $leases[$mac] ?? [];
$leaseHostname = (string)($lease['hostname'] ?? 'N/A');
$aliasHostname = $aliases[$mac] ?? null;
$hostname = $aliasHostname ?: $leaseHostname;
$hostnameSource = $aliasHostname ? 'alias' : ($leaseHostname === 'N/A' ? 'generated' : 'lease');
$cur = [
'band' => $band,
'iface' => $iface,
'mac' => $mac,
'ip' => $lease['ip'] ?? 'N/A',
'hostname' => $lease['hostname'] ?? 'N/A',
'name' => $lease['hostname'] ?? $mac,
'hostname' => $hostname === 'N/A' ? '기기-' . strtoupper(substr(str_replace(':', '', $mac), -6)) : $hostname,
'hostname_source' => $hostnameSource,
'name' => $hostname === 'N/A' ? $mac : $hostname,
'signal' => 'N/A',
'tx_bitrate' => 'N/A',
'rx_bitrate' => 'N/A',
'signal_source' => 'missing',
'tx_bitrate_source' => 'missing',
'rx_bitrate_source' => 'missing',
'connected_time' => 'N/A',
'inactive_time' => 'N/A',
'rx_bytes' => 0,
@@ -2031,9 +2089,16 @@ function parse_live_wifi_rows(string $iface, string $band, string $text, array $
continue;
}
if (preg_match('/^signal:\s+(.+)/', $t, $m)) $cur['signal'] = $m[1];
elseif (preg_match('/^tx bitrate:\s+(.+)/', $t, $m)) $cur['tx_bitrate'] = $m[1];
elseif (preg_match('/^rx bitrate:\s+(.+)/', $t, $m)) $cur['rx_bitrate'] = $m[1];
if (preg_match('/^signal:\s+(.+)/', $t, $m)) {
$cur['signal'] = $m[1];
$cur['signal_source'] = 'iw';
} elseif (preg_match('/^tx bitrate:\s+(.+)/', $t, $m)) {
$cur['tx_bitrate'] = $m[1];
$cur['tx_bitrate_source'] = 'iw';
} elseif (preg_match('/^rx bitrate:\s+(.+)/', $t, $m)) {
$cur['rx_bitrate'] = $m[1];
$cur['rx_bitrate_source'] = 'iw';
}
elseif (preg_match('/^connected time:\s+(.+)/', $t, $m)) $cur['connected_time'] = $m[1];
elseif (preg_match('/^inactive time:\s+(.+)/', $t, $m)) $cur['inactive_time'] = $m[1];
elseif (preg_match('/^rx bytes:\s+(\d+)/', $t, $m)) $cur['rx_bytes'] = (int)$m[1];
@@ -2059,6 +2124,21 @@ function wifi_time_ms(string $value): int
return PHP_INT_MAX;
}
function wifi_unknown(mixed $value): bool
{
$text = strtoupper(trim((string)$value));
return $text === '' || $text === 'N/A' || $text === '-';
}
function wifi_bitrate_mbps(mixed $value): ?float
{
if (preg_match('/([0-9]+(?:\.[0-9]+)?)/', (string)$value, $m)) {
return (float)$m[1];
}
return null;
}
function wifi_signal_dbm(string $value): int
{
if (preg_match('/-?\d+/', $value, $m)) {
@@ -2068,6 +2148,87 @@ function wifi_signal_dbm(string $value): int
return -999;
}
function estimate_wifi_rate_from_signal(string $band, int $dbm): float
{
if ($band === '5G') {
if ($dbm >= -50) return 1300.0;
if ($dbm >= -58) return 866.7;
if ($dbm >= -66) return 585.0;
if ($dbm >= -73) return 390.0;
if ($dbm >= -80) return 173.3;
return 54.0;
}
if ($dbm >= -50) return 300.0;
if ($dbm >= -58) return 144.4;
if ($dbm >= -66) return 72.2;
if ($dbm >= -73) return 39.0;
if ($dbm >= -80) return 19.5;
return 6.5;
}
function estimate_wifi_signal_from_rate(string $band, float $mbps): int
{
if ($band === '5G') {
if ($mbps >= 900) return -48;
if ($mbps >= 600) return -55;
if ($mbps >= 350) return -63;
if ($mbps >= 150) return -71;
if ($mbps >= 54) return -79;
return -84;
}
if ($mbps >= 250) return -48;
if ($mbps >= 120) return -56;
if ($mbps >= 65) return -64;
if ($mbps >= 30) return -72;
if ($mbps >= 10) return -80;
return -86;
}
function format_estimated_mbps(float $mbps): string
{
$value = abs($mbps - round($mbps)) < 0.05
? (string)(int)round($mbps)
: number_format($mbps, 1);
return $value . ' MBit/s (추정)';
}
function apply_wifi_estimates(array $clients): array
{
foreach ($clients as &$client) {
$band = (string)($client['band'] ?? '2.4G');
$signalDbm = wifi_signal_dbm((string)($client['signal'] ?? ''));
$txMbps = wifi_bitrate_mbps($client['tx_bitrate'] ?? null);
$rxMbps = wifi_bitrate_mbps($client['rx_bitrate'] ?? null);
if (wifi_unknown($client['signal'] ?? null)) {
$sourceRate = max($txMbps ?? 0.0, $rxMbps ?? 0.0);
$signalDbm = $sourceRate > 0
? estimate_wifi_signal_from_rate($band, $sourceRate)
: ($band === '5G' ? -67 : -70);
$client['signal'] = $signalDbm . ' dBm (추정)';
$client['signal_source'] = $sourceRate > 0 ? 'estimated_from_rate' : 'estimated_default';
}
if (wifi_unknown($client['tx_bitrate'] ?? null)) {
$base = $rxMbps ?? estimate_wifi_rate_from_signal($band, $signalDbm);
$client['tx_bitrate'] = format_estimated_mbps($base);
$client['tx_bitrate_source'] = $rxMbps === null ? 'estimated_from_signal' : 'estimated_from_rx';
}
if (wifi_unknown($client['rx_bitrate'] ?? null)) {
$base = $txMbps ?? estimate_wifi_rate_from_signal($band, $signalDbm);
$client['rx_bitrate'] = format_estimated_mbps($base);
$client['rx_bitrate_source'] = $txMbps === null ? 'estimated_from_signal' : 'estimated_from_tx';
}
}
unset($client);
return $clients;
}
function dedupe_wifi_clients(array $clients): array
{
$deduped = [];
@@ -2246,16 +2407,18 @@ function apply_observed_wifi_connected_time(array $clients): array
function wifi_data(): array
{
$leases = dnsmasq_leases();
$aliases = wifi_client_aliases();
$clients = [];
foreach (['wlan0' => '2.4G', 'wlan1' => '5G'] as $iface => $band) {
$clients = array_merge(
$clients,
parse_live_wifi_rows($iface, $band, iw_station_dump($iface), $leases)
parse_live_wifi_rows($iface, $band, iw_station_dump($iface), $leases, $aliases)
);
}
$clients = dedupe_wifi_clients($clients);
$clients = apply_wifi_estimates($clients);
$clients = apply_observed_wifi_connected_time($clients);
return [
@@ -2723,6 +2886,21 @@ function control_api_dispatch(): void
]);
}
if ($action === 'wifi_alias') {
$alias = save_wifi_client_alias(
(string)($_POST['mac'] ?? ''),
(string)($_POST['hostname'] ?? '')
);
json_out([
'ok' => true,
'data' => [
'alias' => $alias,
'status' => collect_snapshot(false),
],
]);
}
if ($action === 'collect') {
json_out([
'ok' => true,