Refine DHCP client display
This commit is contained in:
+87
-4
@@ -2713,9 +2713,29 @@ function lan_fdb_macs(string $iface = 'eth1'): array
|
||||
return array_keys($macs);
|
||||
}
|
||||
|
||||
function lan_link_speed_label(string $iface = 'eth1'): string
|
||||
{
|
||||
$speed = trim((string)@file_get_contents('/sys/class/net/' . $iface . '/speed'));
|
||||
if ($speed === '' || !ctype_digit($speed) || (int)$speed <= 0) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$mbps = (int)$speed;
|
||||
if ($mbps >= 1000 && $mbps % 1000 === 0) {
|
||||
return (int)($mbps / 1000) . ' Gbps';
|
||||
}
|
||||
|
||||
if ($mbps >= 1000) {
|
||||
return rtrim(rtrim(number_format($mbps / 1000, 1), '0'), '.') . ' Gbps';
|
||||
}
|
||||
|
||||
return $mbps . ' Mbps';
|
||||
}
|
||||
|
||||
function lan_client_rows(array $leases, array $aliases, string $iface = 'eth1'): array
|
||||
{
|
||||
$rows = [];
|
||||
$linkSpeed = lan_link_speed_label($iface);
|
||||
|
||||
foreach (lan_fdb_macs($iface) as $mac) {
|
||||
$lease = $leases[$mac] ?? [];
|
||||
@@ -2733,10 +2753,10 @@ function lan_client_rows(array $leases, array $aliases, string $iface = 'eth1'):
|
||||
'hostname_source' => $hostnameSource,
|
||||
'name' => $hostname === 'N/A' ? $mac : $hostname,
|
||||
'signal' => '-',
|
||||
'tx_bitrate' => '-',
|
||||
'tx_bitrate' => $linkSpeed,
|
||||
'rx_bitrate' => '-',
|
||||
'signal_source' => 'lan',
|
||||
'tx_bitrate_source' => 'lan',
|
||||
'tx_bitrate_source' => 'lan_link',
|
||||
'rx_bitrate_source' => 'lan',
|
||||
'connected_time' => 'N/A',
|
||||
'inactive_time' => '-',
|
||||
@@ -2903,6 +2923,42 @@ function wifi_connected_time_missing(mixed $value): bool
|
||||
return $text === '' || $text === 'N/A' || $text === '-';
|
||||
}
|
||||
|
||||
function wifi_connected_seconds(mixed $value): ?float
|
||||
{
|
||||
$text = strtolower(trim((string)$value));
|
||||
if ($text === '' || $text === 'n/a' || $text === '-') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_numeric($text)) {
|
||||
return (float)$text;
|
||||
}
|
||||
|
||||
$total = 0.0;
|
||||
$matched = false;
|
||||
if (preg_match_all('/([0-9]+(?:\.[0-9]+)?)\s*(days?|d|hours?|hrs?|h|minutes?|mins?|min|m|seconds?|secs?|sec|s|milliseconds?|msecs?|msec|ms)\b/i', $text, $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$amount = (float)$match[1];
|
||||
$unit = strtolower($match[2]);
|
||||
$matched = true;
|
||||
|
||||
if ($unit === 'd' || str_starts_with($unit, 'day')) {
|
||||
$total += $amount * 86400;
|
||||
} elseif ($unit === 'h' || str_starts_with($unit, 'hour') || str_starts_with($unit, 'hr')) {
|
||||
$total += $amount * 3600;
|
||||
} elseif ($unit === 'm' || str_starts_with($unit, 'min')) {
|
||||
$total += $amount * 60;
|
||||
} elseif ($unit === 'ms' || str_starts_with($unit, 'msec') || str_starts_with($unit, 'millisecond')) {
|
||||
$total += $amount / 1000;
|
||||
} else {
|
||||
$total += $amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $matched ? $total : null;
|
||||
}
|
||||
|
||||
function wifi_valid_mac(string $mac): bool
|
||||
{
|
||||
return preg_match('/^[0-9a-f]{2}(?::[0-9a-f]{2}){5}$/', strtolower($mac)) === 1;
|
||||
@@ -2996,7 +3052,8 @@ function observed_wifi_duration_seconds(array $clients): array
|
||||
]);
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($targets), '?'));
|
||||
$targetMacs = array_values(array_unique(array_column($targets, 'mac')));
|
||||
$placeholders = implode(',', array_fill(0, count($targetMacs), '?'));
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
mac,
|
||||
@@ -3004,7 +3061,7 @@ function observed_wifi_duration_seconds(array $clients): array
|
||||
FROM wifi_observed_sessions
|
||||
WHERE mac IN ($placeholders)
|
||||
");
|
||||
$stmt->execute(array_values(array_unique(array_column($targets, 'mac'))));
|
||||
$stmt->execute($targetMacs);
|
||||
$rows = $stmt->fetchAll();
|
||||
|
||||
$pdo->commit();
|
||||
@@ -3050,6 +3107,31 @@ function apply_observed_wifi_connected_time(array $clients): array
|
||||
return $clients;
|
||||
}
|
||||
|
||||
function sort_clients_by_connected_time(array $clients): array
|
||||
{
|
||||
usort($clients, static function (array $a, array $b): int {
|
||||
$aSeconds = wifi_connected_seconds($a['connected_time'] ?? null);
|
||||
$bSeconds = wifi_connected_seconds($b['connected_time'] ?? null);
|
||||
|
||||
if ($aSeconds === null && $bSeconds === null) {
|
||||
return strcmp((string)($a['band'] ?? ''), (string)($b['band'] ?? ''))
|
||||
?: strcmp((string)($a['hostname'] ?? ''), (string)($b['hostname'] ?? ''));
|
||||
}
|
||||
|
||||
if ($aSeconds === null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($bSeconds === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return $bSeconds <=> $aSeconds;
|
||||
});
|
||||
|
||||
return $clients;
|
||||
}
|
||||
|
||||
function wifi_data(): array
|
||||
{
|
||||
$leases = dnsmasq_leases();
|
||||
@@ -3072,6 +3154,7 @@ function wifi_data(): array
|
||||
$clients = dedupe_wifi_clients($clients);
|
||||
$clients = apply_wifi_estimates($clients);
|
||||
$clients = apply_observed_wifi_connected_time($clients);
|
||||
$clients = sort_clients_by_connected_time($clients);
|
||||
|
||||
return [
|
||||
'clients' => $clients,
|
||||
|
||||
+21
-14
@@ -108,10 +108,10 @@
|
||||
fanStatus: 'Fan Status',
|
||||
cpuTemp: 'CPU Temp',
|
||||
fanRpm: 'Fan RPM',
|
||||
wifiStatus: 'WiFi Status',
|
||||
clients24: '2.4G Clients',
|
||||
clients5: '5G Clients',
|
||||
clientsLan: 'LAN Clients',
|
||||
wifiStatus: 'DHCP Status',
|
||||
clients24: '2.4G DHCP',
|
||||
clients5: '5G DHCP',
|
||||
clientsLan: 'LAN DHCP',
|
||||
systemStatus: 'System Status',
|
||||
loadAvg: 'Load Avg',
|
||||
activeUsers: 'Active Users',
|
||||
@@ -152,7 +152,7 @@
|
||||
cpuWatt: 'CPU Watt',
|
||||
remaining: 'Remaining',
|
||||
batteryVoltage: 'Battery Voltage',
|
||||
wifiClients: 'WiFi Clients',
|
||||
wifiClients: 'DHCP Clients',
|
||||
deviceName: 'Device',
|
||||
address: 'Address',
|
||||
paired: 'Paired',
|
||||
@@ -201,7 +201,7 @@
|
||||
dialogInput: 'Input',
|
||||
dialogOk: 'OK',
|
||||
dialogCancel: 'Cancel',
|
||||
noWifiClients: 'No connected WiFi clients',
|
||||
noWifiClients: 'No connected DHCP clients',
|
||||
noProcessActivity: 'No process activity',
|
||||
noCause: 'No candidate',
|
||||
recordedReason: 'Recorded reason',
|
||||
@@ -256,10 +256,10 @@
|
||||
fanStatus: '팬 상태',
|
||||
cpuTemp: 'CPU 온도',
|
||||
fanRpm: '팬 RPM',
|
||||
wifiStatus: 'WiFi 상태',
|
||||
clients24: '2.4G 접속',
|
||||
clients5: '5G 접속',
|
||||
clientsLan: 'LAN 접속',
|
||||
wifiStatus: 'DHCP 상태',
|
||||
clients24: '2.4G DHCP',
|
||||
clients5: '5G DHCP',
|
||||
clientsLan: 'LAN DHCP',
|
||||
systemStatus: '시스템 상태',
|
||||
loadAvg: '부하 평균',
|
||||
activeUsers: '활성 사용자',
|
||||
@@ -300,7 +300,7 @@
|
||||
cpuWatt: 'CPU 전력',
|
||||
remaining: '잔여 시간',
|
||||
batteryVoltage: '배터리 전압',
|
||||
wifiClients: 'WiFi 클라이언트',
|
||||
wifiClients: 'DHCP 클라이언트',
|
||||
deviceName: '장치',
|
||||
address: '주소',
|
||||
paired: '페어링',
|
||||
@@ -349,7 +349,7 @@
|
||||
dialogInput: '입력',
|
||||
dialogOk: '확인',
|
||||
dialogCancel: '취소',
|
||||
noWifiClients: '연결된 WiFi 클라이언트 없음',
|
||||
noWifiClients: '연결된 DHCP 클라이언트 없음',
|
||||
noProcessActivity: '프로세스 활동 없음',
|
||||
noCause: '원인 후보 없음',
|
||||
recordedReason: '기록된 이유',
|
||||
@@ -1224,6 +1224,14 @@
|
||||
return `<td>${signalBadgeHtml(dbm, row[key] || '', `client:${row.mac || row.ip || row.hostname || ''}`)}</td>`;
|
||||
}
|
||||
|
||||
function wifiRateCells(row) {
|
||||
if (row?.band === 'LAN') {
|
||||
return `<td colspan="2">${escapeHtml(wifiCellValue(row, 'tx_bitrate'))}</td>`;
|
||||
}
|
||||
|
||||
return `${wifiMetricCell(row, 'tx_bitrate')}${wifiMetricCell(row, 'rx_bitrate')}`;
|
||||
}
|
||||
|
||||
function wifiSignalDbm(value) {
|
||||
const match = String(value ?? '').match(/-?\d+(?:\.\d+)?/);
|
||||
return match ? Number(match[0]) : null;
|
||||
@@ -1430,8 +1438,7 @@
|
||||
${td(row.ip)}
|
||||
${td(row.mac)}
|
||||
${wifiMetricCell(row, 'signal')}
|
||||
${wifiMetricCell(row, 'tx_bitrate')}
|
||||
${wifiMetricCell(row, 'rx_bitrate')}
|
||||
${wifiRateCells(row)}
|
||||
${td(wifiConnectedCellValue(row))}
|
||||
${td(wifiCellValue(row, 'inactive_time'))}
|
||||
</tr>
|
||||
|
||||
+5
-5
@@ -199,11 +199,11 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2 data-i18n="wifiStatus">WiFi Status</h2>
|
||||
<h2 data-i18n="wifiStatus">DHCP Status</h2>
|
||||
<div class="stat-grid">
|
||||
<div class="stat"><div class="stat-label" data-i18n="clients24">2.4G Clients</div><div class="stat-value" id="wifi24">-</div></div>
|
||||
<div class="stat"><div class="stat-label" data-i18n="clients5">5G Clients</div><div class="stat-value" id="wifi5">-</div></div>
|
||||
<div class="stat"><div class="stat-label" data-i18n="clientsLan">LAN Clients</div><div class="stat-value" id="wifiLan">-</div></div>
|
||||
<div class="stat"><div class="stat-label" data-i18n="clients24">2.4G DHCP</div><div class="stat-value" id="wifi24">-</div></div>
|
||||
<div class="stat"><div class="stat-label" data-i18n="clients5">5G DHCP</div><div class="stat-value" id="wifi5">-</div></div>
|
||||
<div class="stat"><div class="stat-label" data-i18n="clientsLan">LAN DHCP</div><div class="stat-value" id="wifiLan">-</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -249,7 +249,7 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2 data-i18n="wifiClients">WiFi Clients</h2>
|
||||
<h2 data-i18n="wifiClients">DHCP Clients</h2>
|
||||
<div class="table-wrap">
|
||||
<table class="wifi-table">
|
||||
<colgroup>
|
||||
|
||||
Reference in New Issue
Block a user