Add airtime math and per-minute packets-over-uptime display for repeaters. Closes #194.

This commit is contained in:
Jack Kingsman
2026-04-16 13:26:49 -07:00
parent 1437e8e48a
commit 8efbbd97bd
2 changed files with 52 additions and 5 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "remoteterm-meshcore-frontend",
"version": "3.11.0",
"version": "3.11.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "remoteterm-meshcore-frontend",
"version": "3.11.0",
"version": "3.11.3",
"dependencies": {
"@codemirror/lang-python": "^6.2.1",
"@codemirror/theme-one-dark": "^6.1.3",

View File

@@ -1,7 +1,23 @@
import type { ReactNode } from 'react';
import { Separator } from '../ui/separator';
import { RepeaterPane, NotFetched, KvRow, formatDuration } from './repeaterPaneShared';
import type { RepeaterStatusResponse, PaneState } from '../../types';
function Secondary({ children }: { children: ReactNode }) {
return <span className="ml-1.5 font-normal text-muted-foreground">{children}</span>;
}
function formatAirtimePercent(airtimeSec: number, uptimeSec: number): string | null {
if (uptimeSec <= 0) return null;
return `${((airtimeSec / uptimeSec) * 100).toFixed(2)}%`;
}
function formatPerMinute(count: number, uptimeSec: number): string | null {
if (uptimeSec <= 0) return null;
const rate = (count * 60) / uptimeSec;
return rate >= 10 ? rate.toFixed(0) : rate.toFixed(1);
}
export function TelemetryPane({
data,
state,
@@ -13,6 +29,11 @@ export function TelemetryPane({
onRefresh: () => void;
disabled?: boolean;
}) {
const txPct = data ? formatAirtimePercent(data.airtime_seconds, data.uptime_seconds) : null;
const rxPct = data ? formatAirtimePercent(data.rx_airtime_seconds, data.uptime_seconds) : null;
const rxPerMin = data ? formatPerMinute(data.packets_received, data.uptime_seconds) : null;
const txPerMin = data ? formatPerMinute(data.packets_sent, data.uptime_seconds) : null;
return (
<RepeaterPane title="Telemetry" state={state} onRefresh={onRefresh} disabled={disabled}>
{!data ? (
@@ -21,8 +42,24 @@ export function TelemetryPane({
<div className="space-y-2">
<KvRow label="Battery" value={`${data.battery_volts.toFixed(3)}V`} />
<KvRow label="Uptime" value={formatDuration(data.uptime_seconds)} />
<KvRow label="TX Airtime" value={formatDuration(data.airtime_seconds)} />
<KvRow label="RX Airtime" value={formatDuration(data.rx_airtime_seconds)} />
<KvRow
label="TX Airtime"
value={
<>
{formatDuration(data.airtime_seconds)}
{txPct && <Secondary>({txPct})</Secondary>}
</>
}
/>
<KvRow
label="RX Airtime"
value={
<>
{formatDuration(data.rx_airtime_seconds)}
{rxPct && <Secondary>({rxPct})</Secondary>}
</>
}
/>
<Separator className="my-1" />
<KvRow label="Noise Floor" value={`${data.noise_floor_dbm} dBm`} />
<KvRow label="Last RSSI" value={`${data.last_rssi_dbm} dBm`} />
@@ -30,7 +67,17 @@ export function TelemetryPane({
<Separator className="my-1" />
<KvRow
label="Packets"
value={`${data.packets_received.toLocaleString()} rx / ${data.packets_sent.toLocaleString()} tx`}
value={
<>
{data.packets_received.toLocaleString()} rx / {data.packets_sent.toLocaleString()}{' '}
tx
{rxPerMin && txPerMin && (
<Secondary>
(avg {rxPerMin} rx/min / {txPerMin} tx/min)
</Secondary>
)}
</>
}
/>
<KvRow
label="Flood"