Add Ch Util, TX airtime and uptime to Device Info panel#1010
Add Ch Util, TX airtime and uptime to Device Info panel#1010wittrup wants to merge 2 commits intomeshtastic:mainfrom
Conversation
|
@wittrup is attempting to deploy a commit to the Meshtastic Team on Vercel. A member of the Team first needs to authorize it. |
|
|
There was a problem hiding this comment.
Pull request overview
This PR expands the Device Info panel to surface additional DeviceMetrics fields (Channel Utilization, TX Airtime, and Uptime) and wires telemetry updates into node.deviceMetrics so the UI can display them alongside existing battery/voltage data.
Changes:
- Persist telemetry-derived
deviceMetricsinto the node DB on telemetry packets. - Extend the UI
DeviceMetricstype and plumb the new metrics throughSidebar→DeviceInfoPanel. - Add i18n labels and improve uptime formatting to omit zero-value segments.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
packages/web/src/core/subscriptions.ts |
Updates nodeDB nodes with incoming telemetry metrics. |
packages/web/src/components/types.ts |
Extends UI DeviceMetrics to include channel utilization, TX airtime, and uptime seconds. |
packages/web/src/components/generic/Uptime.tsx |
Updates uptime formatting to skip zero-value segments. |
packages/web/src/components/Sidebar.tsx |
Passes additional metrics into DeviceInfoPanel. |
packages/web/src/components/DeviceInfoPanel.tsx |
Renders new device info rows for channel util, TX airtime, and uptime. |
packages/web/public/i18n/locales/en/ui.json |
Adds English labels for the new device info rows. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| airUtilTx !== undefined | ||
| ? `${(airUtilTx).toFixed(1)}%` |
There was a problem hiding this comment.
airUtilTx is typed as number | null | undefined, but this check only excludes undefined. If it is null, calling .toFixed(1) will throw at runtime. Guard with typeof airUtilTx === "number" (or airUtilTx != null) before formatting.
| airUtilTx !== undefined | |
| ? `${(airUtilTx).toFixed(1)}%` | |
| typeof airUtilTx === "number" | |
| ? `${airUtilTx.toFixed(1)}%` |
| value: | ||
| uptimeSeconds !== undefined ? ( | ||
| <Uptime seconds={uptimeSeconds} /> | ||
| ) : ( | ||
| "N/A" | ||
| ) |
There was a problem hiding this comment.
uptimeSeconds is typed as number | null | undefined, but this only checks !== undefined. If uptimeSeconds is null, it will be passed to <Uptime seconds={...} /> (expects a number) and can break formatting/rendering. Also, InfoDisplayItem.value is typed as string | number | null, but this branch assigns a React element; either render uptime as a string or widen the value type to React.ReactNode (and ensure the render path supports it).
| value: | |
| uptimeSeconds !== undefined ? ( | |
| <Uptime seconds={uptimeSeconds} /> | |
| ) : ( | |
| "N/A" | |
| ) | |
| customComponent: | |
| uptimeSeconds != null ? <Uptime seconds={uptimeSeconds} /> : undefined, | |
| value: uptimeSeconds != null ? null : "N/A", |
| connection.events.onTelemetryPacket.subscribe((packet) => { | ||
| const metrics = packet.data.variant.value; | ||
| const existing = nodeDB.getNode(packet.from); | ||
| nodeDB.addNode({ | ||
| ...(existing ?? {}), | ||
| num: packet.from, | ||
| deviceMetrics: { ...metrics }, | ||
| }); |
There was a problem hiding this comment.
This handler assumes packet.data.variant.value is always DeviceMetrics. Telemetry packets typically have multiple variant.case values (e.g. device/environment/power metrics). Without checking packet.data.variant.case before assigning into node.deviceMetrics, non-device telemetry variants could overwrite deviceMetrics with the wrong shape. Add an explicit guard (e.g. only update when variant.case === "deviceMetrics").
| }, | ||
| "channelUtil": { | ||
| "title": "Ch Util" | ||
| }, | ||
| "airUtilTx": { | ||
| "title": "TX Airtime" | ||
| }, | ||
| "uptime": { | ||
| "title": "Uptime" | ||
| } |
There was a problem hiding this comment.
New sidebar.deviceInfo.* UI labels were added only to en/ui.json. Other locales’ ui.json files don’t contain these keys, so non-English UIs will likely display the raw i18n key. Either add the corresponding entries to the other locale ui.json files or provide default/fallback strings in the t(...) calls for these new labels.
| channelUtilization !== undefined | ||
| ? `${(channelUtilization).toFixed(1)}%` |
There was a problem hiding this comment.
channelUtilization is typed as number | null | undefined, but this check only excludes undefined. If it is null, calling .toFixed(1) will throw at runtime. Prefer guarding with typeof channelUtilization === "number" (or channelUtilization != null) before formatting, and fall back to N/A otherwise.
| channelUtilization !== undefined | |
| ? `${(channelUtilization).toFixed(1)}%` | |
| typeof channelUtilization === "number" | |
| ? `${channelUtilization.toFixed(1)}%` |
This PR surfaces additional DeviceMetrics fields in the Device Info panel:
Telemetry from TELEMETRY_APP is merged into node.deviceMetrics so it aligns with existing battery/voltage handling.
Includes: