This commit is contained in:
legop3
2026-05-01 18:56:11 -04:00
parent 2833175fca
commit b76405ed46
7 changed files with 45 additions and 32 deletions
+3
View File
@@ -0,0 +1,3 @@
# web UI optimization
- reduce amount of invalidation for unrelated session and socket updates, wherever possible.
- example: new log line invalidates more than just log panels
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -11,7 +11,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
<title>Multi Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-FrukTaHm.js"></script>
<script type="module" crossorigin src="/assets/index-BT4tyIib.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DYarsG-0.css">
</head>
<body>
@@ -11,6 +11,10 @@ function sanitizeLogText(value) {
.replace(/\x1B\[[0-9;]*[A-Za-z]/g, '');
}
function shellQuote(value) {
return `'${String(value || '').replace(/'/g, `'\"'\"'`)}'`;
}
function parsePayloadFromLine(line) {
const raw = sanitizeLogText(line).trim();
if (!raw) return null;
@@ -264,20 +268,26 @@ function createLidarRuntime({ logger, host, port = 6053, key, logFile = '', shou
if (state.process) return;
ensureLogStream();
const args = [
const baseCommand = [
'env',
'PYTHONUNBUFFERED=1',
'NO_COLOR=1',
'TERM=dumb',
'uvx',
'--from',
'aioesphomeapi',
'aioesphomeapi-logs',
host,
shellQuote(host),
'--port',
String(port || 6053),
shellQuote(String(port || 6053)),
'--noise-psk',
key,
shellQuote(key),
'--no-states',
];
].join(' ');
const launchCommand = `if command -v script >/dev/null 2>&1; then exec script -qefc ${shellQuote(baseCommand)} /dev/null; else exec ${baseCommand}; fi`;
logger.info('Starting Neato lidar log stream', { host, port: Number(port || 6053) });
const proc = spawn('uvx', args, {
const proc = spawn('bash', ['-lc', launchCommand], {
stdio: ['ignore', 'pipe', 'pipe'],
});
state.process = proc;
-2
View File
@@ -16,7 +16,6 @@ export default function VipPanel() {
const {
session,
neatoLidar,
neatoLidarLines,
identifySession,
requestVerification,
requestPrivateRoverAccess,
@@ -81,7 +80,6 @@ export default function VipPanel() {
<VipNeatoCard
neato={session?.neato || null}
lidar={neatoLidar}
lidarLines={neatoLidarLines}
onStart={neatoStart}
onSendHome={neatoSendHome}
onLocate={neatoLocate}
+16 -2
View File
@@ -2,6 +2,7 @@
// Purpose: Defines the Vip Neato Card module and the local helpers/components used in this file.
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
import { useEffect, useState } from 'react';
import { useSocket } from '../../context/SocketContext.jsx';
function normalizeState(value) {
return String(value || '').trim();
@@ -58,7 +59,6 @@ function buildLidarDots(points = []) {
export default function VipNeatoCard({
neato,
lidar,
lidarLines,
onStart,
onSendHome,
onLocate,
@@ -66,9 +66,11 @@ export default function VipNeatoCard({
onPowerCycle,
fullWidth = false,
}) {
const socket = useSocket();
const [working, setWorking] = useState('');
const [lidarFlash, setLidarFlash] = useState(false);
const [showLidarDebug, setShowLidarDebug] = useState(false);
const [recentLidarLines, setRecentLidarLines] = useState([]);
const wrapClass = fullWidth ? 'w-full' : 'w-full max-w-xl';
const configured = Boolean(neato?.configured);
@@ -85,7 +87,6 @@ export default function VipNeatoCard({
const robotError = normalizeState(neato?.telemetry?.robotError) || '--';
const robotAlert = normalizeState(neato?.telemetry?.robotAlert) || '--';
const lidarPoints = Array.isArray(lidar?.points) ? lidar.points : [];
const recentLidarLines = Array.isArray(lidarLines) ? lidarLines : [];
const lidarDots = buildLidarDots(lidarPoints);
const lidarStatus = normalizeState(lidar?.status) || '--';
const lidarDebug = lidar?.debug && typeof lidar.debug === 'object' ? lidar.debug : null;
@@ -134,6 +135,19 @@ export default function VipNeatoCard({
return () => clearTimeout(timer);
}, [lidar]);
useEffect(() => {
function handleLidarLine(payload = null) {
const next = payload && typeof payload === 'object' ? payload : null;
if (!next?.line) return;
setRecentLidarLines((prev) => [...prev.slice(-199), next]);
}
socket.on('neato:lidarLine', handleLidarLine);
return () => {
socket.off('neato:lidarLine', handleLidarLine);
};
}, [socket]);
return (
<section className={`surface text-sm text-slate-200 ${wrapClass}`}>
<div className="grid gap-0.5">
-12
View File
@@ -9,7 +9,6 @@ const INITIAL_STATE = {
connected: false,
session: null,
neatoLidar: null,
neatoLidarLines: [],
logs: [],
adminLogs: [],
llmCommentaryState: null,
@@ -133,18 +132,8 @@ export function SessionProvider({ children }) {
const next = payload && typeof payload === 'object' ? payload : null;
setState((prev) => ({ ...prev, neatoLidar: next }));
}
function handleNeatoLidarLine(payload = null) {
const next = payload && typeof payload === 'object' ? payload : null;
if (!next?.line) return;
setState((prev) => ({
...prev,
neatoLidarLines: [...prev.neatoLidarLines.slice(-199), next],
}));
}
socket.on('session:sync', handleSession);
socket.on('neato:lidar', handleNeatoLidar);
socket.on('neato:lidarLine', handleNeatoLidarLine);
socket.on('log:init', handleLogInit);
socket.on('log:entry', handleLogEntry);
socket.on('adminlog:init', handleAdminLogInit);
@@ -154,7 +143,6 @@ export function SessionProvider({ children }) {
return () => {
socket.off('session:sync', handleSession);
socket.off('neato:lidar', handleNeatoLidar);
socket.off('neato:lidarLine', handleNeatoLidarLine);
socket.off('log:init', handleLogInit);
socket.off('log:entry', handleLogEntry);
socket.off('adminlog:init', handleAdminLogInit);