This commit is contained in:
legop3
2026-06-12 12:40:00 -04:00
parent cc06709674
commit bcd54c28e1
9 changed files with 162 additions and 153 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -12,7 +12,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Roomba Rover" /> <meta name="apple-mobile-web-app-title" content="Roomba Rover" />
<title>Roomba Rover</title> <title>Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-CcFK0l2M.js"></script> <script type="module" crossorigin src="/assets/index-B4ejc0Ok.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BVKa8Zph.css"> <link rel="stylesheet" crossorigin href="/assets/index-BVKa8Zph.css">
</head> </head>
<body> <body>
@@ -12,7 +12,7 @@ export default function SpectatorTelemetryOverlay({ sensors, telemetry = null, m
['Voltage', voltageMv != null ? `${(voltageMv / 1000).toFixed(2)} V` : '--'], ['Voltage', voltageMv != null ? `${(voltageMv / 1000).toFixed(2)} V` : '--'],
['Current', currentMa != null ? `${currentMa} mA` : '--'], ['Current', currentMa != null ? `${currentMa} mA` : '--'],
['Charge', batteryChargeMah != null ? `${batteryChargeMah}` : '--'], ['Charge', batteryChargeMah != null ? `${batteryChargeMah}` : '--'],
['Oi', oiLabel || '--'], ['OI', oiLabel || '--'],
]; ];
const charging = Boolean(chargingLabel && chargingLabel.toLowerCase() !== 'not charging'); const charging = Boolean(chargingLabel && chargingLabel.toLowerCase() !== 'not charging');
const oiNormalized = oiLabel.toLowerCase(); const oiNormalized = oiLabel.toLowerCase();
@@ -41,7 +41,7 @@ export default function SpectatorTelemetryOverlay({ sensors, telemetry = null, m
<span className={`rounded px-1.5 py-0.5 ${chargingTone}`}> <span className={`rounded px-1.5 py-0.5 ${chargingTone}`}>
{charging ? 'Charging' : docked ? 'Not charging' : 'Not charging'} {charging ? 'Charging' : docked ? 'Not charging' : 'Not charging'}
</span> </span>
<span className={`rounded px-1.5 py-0.5 ${oiTone}`}>Oi: {oiLabel}</span> <span className={`rounded px-1.5 py-0.5 ${oiTone}`}>OI: {oiLabel}</span>
</div> </div>
{telemetryEntries.map(([labelText, value]) => ( {telemetryEntries.map(([labelText, value]) => (
<span key={labelText} className="flex items-center justify-between gap-0.5"> <span key={labelText} className="flex items-center justify-between gap-0.5">
@@ -32,7 +32,7 @@ function LowBatteryOverlay({ roverId = null, sensors, batteryConfig, compact = f
if (!battery.warnActive && !battery.urgentActive) return null; if (!battery.warnActive && !battery.urgentActive) return null;
const message = battery.urgentActive const message = battery.urgentActive
? 'Battery very low, dock the rover and charge immediately!!' ? 'BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!'
: 'Battery low! please dock and charge the rover soon.'; : 'Battery low! please dock and charge the rover soon.';
const containerClass = compact ? 'p-2 top-6' : 'p-4 top-10'; const containerClass = compact ? 'p-2 top-6' : 'p-4 top-10';
@@ -56,7 +56,7 @@ function OvercurrentOverlay({ roverId = null, sensors, overcurrentLimiter = null
<div className="h-full bg-red-700/60" style={{ width: fillWidth }} /> <div className="h-full bg-red-700/60" style={{ width: fillWidth }} />
</div> </div>
<div className={`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${textClass} ${padClass}`}> <div className={`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${textClass} ${padClass}`}>
<div>Overcurrent</div> <div>OVERCURRENT</div>
<div className={`mt-0 font-medium text-white ${subTextClass}`}>{safeLabels.join(', ')}</div> <div className={`mt-0 font-medium text-white ${subTextClass}`}>{safeLabels.join(', ')}</div>
</div> </div>
</div> </div>
@@ -59,7 +59,7 @@ function TelemetrySummary({ sensors, voltage, current, batteryTemp, charge, capa
<Metric label="Charge" value={charge != null ? `${charge} mAh` : '--'} /> <Metric label="Charge" value={charge != null ? `${charge} mAh` : '--'} />
<Metric label="Capacity" value={capacity != null ? `${capacity} mAh` : '--'} /> <Metric label="Capacity" value={capacity != null ? `${capacity} mAh` : '--'} />
<Metric label="Charge" value={chargePct} /> <Metric label="Charge" value={chargePct} />
<Metric label="Oi mode" value={oiMode} /> <Metric label="OI mode" value={oiMode} />
<Metric label="Docked" value={docked} /> <Metric label="Docked" value={docked} />
<Metric label="Charging state" value={charging} /> <Metric label="Charging state" value={charging} />
</div> </div>
+1 -1
View File
@@ -105,7 +105,7 @@ export function TelemetryProvider({ children }) {
if (!entries) return; if (!entries) return;
evaluateSelectorEntries( evaluateSelectorEntries(
roverId, roverId,
[...entries].filter((entry) => entry.mode === 'visual' && entry.throttleMs > 0), [...entries].filter((entry) => entry.mode === 'visual' && throttleMsForEntry(entry) > 0),
); );
}); });
if (visualAllPendingRef.current) { if (visualAllPendingRef.current) {
+29 -20
View File
@@ -75,6 +75,15 @@ function bucketNumber(value, step) {
return Math.round(Number(value) / step) * step; return Math.round(Number(value) / step) * step;
} }
function sensorNumber(value) {
// Some visual sensors, especially light bumps, need every reported value to
// be eligible for rendering because coarse bucketing can leave the UI looking
// stuck near object edges. This still benefits from selector equality because
// only the specific subscribed field can trigger its consumer.
if (value == null || !Number.isFinite(Number(value))) return value ?? null;
return Number(value);
}
export function mapTelemetryEqual(left, right) { export function mapTelemetryEqual(left, right) {
return shallowObjectEqual(left, right); return shallowObjectEqual(left, right);
} }
@@ -105,20 +114,20 @@ export function selectVisualMapTelemetry(frame) {
rightWheelOvercurrent: Boolean(wheelOver.rightWheel), rightWheelOvercurrent: Boolean(wheelOver.rightWheel),
sideBrushOvercurrent: Boolean(wheelOver.sideBrush), sideBrushOvercurrent: Boolean(wheelOver.sideBrush),
mainBrushOvercurrent: Boolean(wheelOver.mainBrush), mainBrushOvercurrent: Boolean(wheelOver.mainBrush),
wheelLeftCurrentMa: bucketNumber(sensors.wheelLeftCurrentMa ?? 0, 25), wheelLeftCurrentMa: bucketNumber(sensors.wheelLeftCurrentMa ?? 0, 5),
wheelRightCurrentMa: bucketNumber(sensors.wheelRightCurrentMa ?? 0, 25), wheelRightCurrentMa: bucketNumber(sensors.wheelRightCurrentMa ?? 0, 5),
sideBrushCurrentMa: bucketNumber(sensors.sideBrushCurrentMa ?? 0, 25), sideBrushCurrentMa: bucketNumber(sensors.sideBrushCurrentMa ?? 0, 5),
mainBrushCurrentMa: bucketNumber(sensors.mainBrushCurrentMa ?? 0, 25), mainBrushCurrentMa: bucketNumber(sensors.mainBrushCurrentMa ?? 0, 5),
lightBumpLeftSignal: bucketNumber(sensors.lightBumpLeftSignal, 25), lightBumpLeftSignal: sensorNumber(sensors.lightBumpLeftSignal),
lightBumpFrontLeftSignal: bucketNumber(sensors.lightBumpFrontLeftSignal, 25), lightBumpFrontLeftSignal: sensorNumber(sensors.lightBumpFrontLeftSignal),
lightBumpCenterLeftSignal: bucketNumber(sensors.lightBumpCenterLeftSignal, 25), lightBumpCenterLeftSignal: sensorNumber(sensors.lightBumpCenterLeftSignal),
lightBumpCenterRightSignal: bucketNumber(sensors.lightBumpCenterRightSignal, 25), lightBumpCenterRightSignal: sensorNumber(sensors.lightBumpCenterRightSignal),
lightBumpFrontRightSignal: bucketNumber(sensors.lightBumpFrontRightSignal, 25), lightBumpFrontRightSignal: sensorNumber(sensors.lightBumpFrontRightSignal),
lightBumpRightSignal: bucketNumber(sensors.lightBumpRightSignal, 25), lightBumpRightSignal: sensorNumber(sensors.lightBumpRightSignal),
cliffLeftSignal: bucketNumber(sensors.cliffLeftSignal, 25), cliffLeftSignal: bucketNumber(sensors.cliffLeftSignal, 5),
cliffFrontLeftSignal: bucketNumber(sensors.cliffFrontLeftSignal, 25), cliffFrontLeftSignal: bucketNumber(sensors.cliffFrontLeftSignal, 5),
cliffFrontRightSignal: bucketNumber(sensors.cliffFrontRightSignal, 25), cliffFrontRightSignal: bucketNumber(sensors.cliffFrontRightSignal, 5),
cliffRightSignal: bucketNumber(sensors.cliffRightSignal, 25), cliffRightSignal: bucketNumber(sensors.cliffRightSignal, 5),
cliffLeft: Boolean(sensors.cliffLeft), cliffLeft: Boolean(sensors.cliffLeft),
cliffFrontLeft: Boolean(sensors.cliffFrontLeft), cliffFrontLeft: Boolean(sensors.cliffFrontLeft),
cliffFrontRight: Boolean(sensors.cliffFrontRight), cliffFrontRight: Boolean(sensors.cliffFrontRight),
@@ -132,12 +141,12 @@ export function selectLightBumpTelemetry(frame) {
const sensors = frame?.sensors; const sensors = frame?.sensors;
if (!sensors) return []; if (!sensors) return [];
return [ return [
bucketNumber(sensors.lightBumpLeftSignal, 25), sensorNumber(sensors.lightBumpLeftSignal),
bucketNumber(sensors.lightBumpFrontLeftSignal, 25), sensorNumber(sensors.lightBumpFrontLeftSignal),
bucketNumber(sensors.lightBumpCenterLeftSignal, 25), sensorNumber(sensors.lightBumpCenterLeftSignal),
bucketNumber(sensors.lightBumpCenterRightSignal, 25), sensorNumber(sensors.lightBumpCenterRightSignal),
bucketNumber(sensors.lightBumpFrontRightSignal, 25), sensorNumber(sensors.lightBumpFrontRightSignal),
bucketNumber(sensors.lightBumpRightSignal, 25), sensorNumber(sensors.lightBumpRightSignal),
]; ];
} }