pi stats from roverd to webui slop

This commit is contained in:
legop3
2026-06-03 12:14:47 -04:00
parent 290985bf47
commit dd7e685934
18 changed files with 1177 additions and 131 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
<title>Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-jio2k7HC.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-d695mNgs.css">
<script type="module" crossorigin src="/assets/index-B5dcDBYS.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ci1EF4ZU.css">
</head>
<body>
<div id="root"></div>
@@ -32,6 +32,11 @@ function handleMessage(roverId, msg) {
case 'sensor':
roverManager.handleSensorFrame(roverId, msg);
break;
case 'hostStats':
// Host stats are periodic Pi metadata, not user-facing rover events, so
// they are routed directly to roverManager instead of becoming alerts.
roverManager.handleHostStats(roverId, msg);
break;
case 'event': {
const nightVisionOn = coerceBool(msg.data?.nightVisionOn);
if (msg.event === 'nightVision.state' && nightVisionOn != null) {
@@ -88,6 +93,10 @@ roverWSS.on('connection', (ws) => {
if (!roverId) return;
if (msg.type === 'sensor') {
roverManager.handleSensorFrame(roverId, msg);
} else if (msg.type === 'hostStats') {
// Keep the Pi health stream separate from both Roomba sensorFrame data
// and generic rover events, which are surfaced as alerts.
roverManager.handleHostStats(roverId, msg);
} else if (msg.type === 'ack') {
handleAck(msg);
} else if (msg.type === 'event') {
@@ -127,6 +127,7 @@ const {
getRosterForSocket,
broadcastRoster,
setNightVisionState,
handleHostStats,
canSeeRover,
canRequestControl,
} = rosterLifecycle;
@@ -244,6 +245,7 @@ module.exports = {
getRosterForSocket,
broadcastRoster,
setNightVisionState,
handleHostStats,
handleSensorFrame,
requestControl,
releaseControl,
@@ -33,6 +33,7 @@ function createRosterLifecycle(deps) {
meta: null,
ws: null,
lastSensor: null,
lastHostStats: null,
docked: null,
lastBumpAt: null,
drivers: new Set(),
@@ -269,6 +270,30 @@ function createRosterLifecycle(deps) {
managerEvents.emit('rover', { roverId, action: 'nightVision', record });
}
function handleHostStats(roverId, msg = {}) {
const record = rovers.get(roverId);
if (!record) return;
const stats = msg && typeof msg.stats === 'object' && msg.stats ? msg.stats : {};
const receivedAt = Date.now();
// Host stats describe the Pi/Linux side of a rover, so they are stored
// separately from lastSensor and emitted on their own browser event. That
// keeps raw Roomba sensor frames from becoming a mixed metadata channel.
record.lastHostStats = {
raw: msg,
stats,
receivedAt,
};
record.lastSeen = receivedAt;
io.to(record.room).volatile.emit('roverHostStats', {
roverId,
stats,
receivedAt,
});
managerEvents.emit('hostStats', { roverId, stats, receivedAt });
}
function canSeeRover(roverId, socket) {
const record = rovers.get(String(roverId));
return isRoverVisibleToSocket(record, socket);
@@ -292,6 +317,7 @@ function createRosterLifecycle(deps) {
syncSpectatorRooms,
broadcastRoster,
setNightVisionState,
handleHostStats,
canSeeRover,
canRequestControl,
};