Telemetry strip
A row of labeled readings separated by bars, each colored by how it stands.
On this page
Code
import { TelemetryStrip, type TelemetryGroup } from "@bosunkit/components/telemetry-strip";
import { useEffect, useState, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"The onboard computer's vitals on a live feed: load, memory, temperature, the NMEA 2000 bus, AIS, GPS and the " +
"shore link move every two seconds between ok, warning and bad, beside an uptime with no status.";
const FEED_MILLISECONDS: number = 2000;
/** One reading per tick for each live value; the feed walks through them and starts over. */
const CPU_PERCENT: readonly number[] = [34, 41, 58, 77, 92, 71, 46, 38];
const MEMORY_PERCENT: readonly number[] = [62, 64, 67, 71, 86, 88, 74, 63];
const CORE_CELSIUS: readonly number[] = [54, 56, 61, 72, 86, 79, 63, 57];
const NMEA_FRAMES: readonly number[] = [412, 398, 405, 0, 0, 388, 420, 409];
const AIS_PER_MINUTE: readonly number[] = [38, 41, 44, 47, 39, 36, 40, 42];
const SATELLITES: readonly number[] = [11, 10, 9, 6, 3, 7, 10, 11];
const UPLINK_MILLISECONDS: readonly number[] = [42, 48, 61, 140, 0, 0, 95, 44];
function level(value: number, warnAt: number, badAt: number): TelemetryGroup["status"] {
if (value >= badAt) {
return "bad";
}
return value >= warnAt ? "warn" : "ok";
}
function reading(series: readonly number[], tick: number): number {
return series[tick % series.length] ?? 0;
}
function groups(tick: number): readonly TelemetryGroup[] {
const cpu: number = reading(CPU_PERCENT, tick);
const memory: number = reading(MEMORY_PERCENT, tick);
const core: number = reading(CORE_CELSIUS, tick);
const frames: number = reading(NMEA_FRAMES, tick);
const ais: number = reading(AIS_PER_MINUTE, tick);
const satellites: number = reading(SATELLITES, tick);
const uplink: number = reading(UPLINK_MILLISECONDS, tick);
return [
{ label: "CPU", value: `${String(cpu)}%`, status: level(cpu, 70, 90) },
{ label: "Mem", value: `${String(memory)}%`, status: level(memory, 85, 95) },
{ label: "Core", value: `${String(core)} °C`, status: level(core, 75, 85) },
{
label: "NMEA 2000",
value: frames === 0 ? "no frames" : `${String(frames)} frames/s`,
status: frames === 0 ? "bad" : "ok",
},
{ label: "AIS", value: `${String(ais)}/min`, status: "ok" },
{
label: "GPS",
value: satellites < 4 ? `no fix, ${String(satellites)} sats` : `3D fix, ${String(satellites)} sats`,
status: satellites < 4 ? "bad" : satellites < 8 ? "warn" : "ok",
},
{
label: "Starlink",
value: uplink === 0 ? "offline" : `${String(uplink)} ms`,
status: uplink === 0 ? "bad" : level(uplink, 120, Number.POSITIVE_INFINITY),
},
{ label: "Uptime", value: "14 d 6 h" },
];
}
export default function Showcase(): ReactElement {
const [tick, setTick]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
useEffect((): (() => void) => {
const timer: number = window.setInterval((): void => {
setTick((current: number): number => current + 1);
}, FEED_MILLISECONDS);
return (): void => {
window.clearInterval(timer);
};
}, []);
return (
<div style={{ width: "100%" }}>
<TelemetryStrip groups={groups(tick)} />
</div>
);
}
A telemetry strip shows a few readings of the system itself, such as load, memory and the NMEA link, in one quiet row.
Each group is a label and a value as the caller displays them. A group's status colors its value green for ok,
amber for warn and red for bad, and leaves it uncolored when unset. The color is never the only signal: the value
is a word or a number the crew can read in any theme. The strip is not a live region: readings that change every
second are read when a screen reader reaches them, not announced on each update over the alert zone's announcements.
Examples
Live
Code
import { TelemetryStrip } from "@bosunkit/components/telemetry-strip";
import type { ReactElement } from "react";
export const description: string = "Four readings in a row: one in order, one at a warning, one bad, and one with no status.";
export default function Live(): ReactElement {
return (
<TelemetryStrip
groups={[
{ label: "CPU", value: "34%", status: "ok" },
{ label: "Mem", value: "86%", status: "warn" },
{ label: "NMEA", value: "offline", status: "bad" },
{ label: "Net", value: "starlink" },
]}
/>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| groupsrequired | readonly TelemetryGroup[] | – | The readings, in order. |
| className | string | undefined | – | Classes added to the strip's own. |
Keep the summary useful
Give each item a stable identity, label and unit, and keep its place as values change. Use the strip for a short set of related summaries; a long list belongs in a table or a dedicated instrument view. Distinguish the current value from a total, average or peak over a stated window.
Fast updates must not repeatedly interrupt a screen reader. Reserve announcements for meaningful state changes and make ordinary readings available through their labels and detail view. Preserve missing and stale states rather than substituting zero, and identify recorded data in report examples.
Related
- Status strip: the global strip with the stream's state and the UTC clock.
- Data integrity: the states a reading can be in.
- Color: the reserved colors a status draws on.