This commit is contained in:
legop3
2025-11-17 04:26:00 -05:00
parent a6995e0789
commit 37dbb1c5d9
5 changed files with 39 additions and 16 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webui</title>
<script type="module" crossorigin src="/assets/index-BGrcbIm7.js"></script>
<script type="module" crossorigin src="/assets/index-C8plXa0F.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DEkIseQD.css">
</head>
<body>
+8
View File
@@ -5,13 +5,16 @@ const { getMode, modeEvents } = require('./modeManager');
const roverManager = require('./roverManager');
const { managerEvents } = roverManager;
const assignmentService = require('./assignmentService');
const { getActiveDrivers, turnEvents } = require('./turnService');
function buildSession(socket) {
return {
socketId: socket?.id || null,
role: getRole(socket),
mode: getMode(),
roster: roverManager.getRoster(),
assignment: assignmentService.describeAssignment(socket?.id || ''),
activeDrivers: getActiveDrivers(),
};
}
@@ -61,6 +64,11 @@ managerEvents.on('lock', ({ roverId, locked }) => {
syncAll();
});
turnEvents.on('activeDriver', () => {
logger.info('Active driver change; syncing all clients');
syncAll();
});
module.exports = {
buildSession,
syncSocket,
+13 -1
View File
@@ -1,3 +1,4 @@
const EventEmitter = require('events');
const io = require('../globals/io');
const { sendAlert, COLORS } = require('./alertService');
const { MODES, getMode, modeEvents } = require('./modeManager');
@@ -5,6 +6,7 @@ const { MODES, getMode, modeEvents } = require('./modeManager');
const driverQueues = new Map(); // roverId -> { queue: [], current: socketId, timer: Timeout | null }
const activeDrivers = new Map();
const TURN_DURATION_MS = 60 * 1000;
const turnEvents = new EventEmitter();
function driverAdded(roverId, socketId, force) {
const queue = ensureQueue(roverId);
@@ -104,7 +106,15 @@ function setActiveDriver(roverId, socketId) {
} else {
activeDrivers.set(roverId, socketId);
}
io.emit('activeDriver', { roverId, socketId });
turnEvents.emit('activeDriver', { roverId, socketId });
}
function getActiveDrivers() {
const map = {};
activeDrivers.forEach((socketId, roverId) => {
map[roverId] = socketId;
});
return map;
}
function stopRover(roverId) {
@@ -126,4 +136,6 @@ module.exports = {
driverRemoved,
cleanupRover,
canDrive,
getActiveDrivers,
turnEvents,
};
+13 -10
View File
@@ -20,6 +20,14 @@ export default function TelemetryPanel() {
// const rawSnippet = frame?.raw ? (frame.raw.length > 80 ? `${frame.raw.slice(0, 80)}…` : frame.raw) : null;
const rawSnippet = frame?.raw ? frame.raw : null;
const roster = session?.roster ?? [];
const activeDriverId = roverId ? session?.activeDrivers?.[roverId] : null;
const driverLabel = !roverId
? 'n/a'
: activeDriverId
? activeDriverId === session?.socketId
? 'You'
: activeDriverId.slice(0, 6)
: 'Available';
const isAdmin = useMemo(
() => session?.role === 'admin' || session?.role === 'lockdown' || session?.role === 'lockdown-admin',
[session?.role],
@@ -45,6 +53,7 @@ export default function TelemetryPanel() {
<span> · role {session?.role || 'unknown'}</span>
<span> · mode {session?.mode || '--'}</span>
{updated && <span> · sensors {updated}</span>}
<span> · driver {driverLabel}</span>
</div>
{!roverId ? (
<p className="mt-1 text-[0.75rem] text-slate-400">Assign a rover to view sensors.</p>
@@ -52,23 +61,21 @@ export default function TelemetryPanel() {
<p className="mt-1 text-[0.75rem] text-slate-400">Waiting for sensor frames</p>
) : (
<>
<div className="flex gap-0.5 flex-wrap">
<div className="flex flex-wrap gap-0.5">
<Metric label="Charge" value={formatMetric(charge != null && capacity != null ? `${charge}/${capacity}` : null)} />
<Metric label="Charging" value={formatMetric(sensors.chargingState?.label)} />
<Metric label="OI mode" value={formatMetric(sensors.oiMode?.label)} />
<Metric label="Voltage" value={formatMetric(voltage)} />
<Metric label="Current" value={formatMetric(current)} />
<Metric label="Left Encoder" value={formatMetric(sensors.encoderCountsLeft)}/>
<Metric label="Right Encoder" value={formatMetric(sensors.encoderCountsRight)}/>
<Metric label="Left Encoder" value={formatMetric(sensors.encoderCountsLeft)} />
<Metric label="Right Encoder" value={formatMetric(sensors.encoderCountsRight)} />
</div>
<div className="flex gap-0.5 mt-1">
<div className="mt-1 flex gap-0.5">
<CliffBar value={sensors.cliffLeftSignal} />
<CliffBar value={sensors.cliffFrontLeftSignal} />
<CliffBar value={sensors.cliffFrontRightSignal} />
<CliffBar value={sensors.cliffRightSignal} />
</div>
</>
)}
@@ -131,10 +138,6 @@ function CliffBar({ value }) {
function Metric({ label, value }) {
return (
// <div className="flex items-center justify-between">
// <span className="text-slate-400">{label}</span>
// <span className="text-slate-200">{value}</span>
// </div>
<div className="bg-gray-700 rounded-sm p-0.5 text-sm">
{label}: {value}
</div>