mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
requet fix and ui change
This commit is contained in:
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
@@ -11,8 +11,8 @@
|
|||||||
<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="Multi Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||||
<title>Multi Roomba Rover</title>
|
<title>Multi Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BT4tyIib.js"></script>
|
<script type="module" crossorigin src="/assets/index-BpIdNRSY.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DYarsG-0.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CGvUXLso.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -275,13 +275,6 @@ function broadcastLidarScan(payload) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function broadcastLidarLine(payload) {
|
|
||||||
for (const socket of io.sockets.sockets.values()) {
|
|
||||||
if (!isVerified(socket)) continue;
|
|
||||||
socket.emit('neato:lidarLine', payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lidarRuntime =
|
lidarRuntime =
|
||||||
brainslugHost && brainslugKey
|
brainslugHost && brainslugKey
|
||||||
? createLidarRuntime({
|
? createLidarRuntime({
|
||||||
@@ -299,9 +292,6 @@ if (lidarRuntime) {
|
|||||||
lidarRuntime.on('scan', (payload) => {
|
lidarRuntime.on('scan', (payload) => {
|
||||||
broadcastLidarScan(payload);
|
broadcastLidarScan(payload);
|
||||||
});
|
});
|
||||||
lidarRuntime.on('line', (payload) => {
|
|
||||||
broadcastLidarLine(payload);
|
|
||||||
});
|
|
||||||
lidarRuntime.on('status', () => {
|
lidarRuntime.on('status', () => {
|
||||||
emitUpdate();
|
emitUpdate();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ function createLidarRuntime({ logger, host, port = 6053, key, logFile = '', shou
|
|||||||
state.stats.rotationsWithoutScan += 1;
|
state.stats.rotationsWithoutScan += 1;
|
||||||
emitFrame({ status: 'error', reason: 'rotation_without_scan', scan: null });
|
emitFrame({ status: 'error', reason: 'rotation_without_scan', scan: null });
|
||||||
resetScanState();
|
resetScanState();
|
||||||
|
triggerPollSoon();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.stats.scansOk += 1;
|
state.stats.scansOk += 1;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Purpose: Defines the Vip Neato Card module and the local helpers/components used in this file.
|
// 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.
|
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useSocket } from '../../context/SocketContext.jsx';
|
|
||||||
|
|
||||||
function normalizeState(value) {
|
function normalizeState(value) {
|
||||||
return String(value || '').trim();
|
return String(value || '').trim();
|
||||||
@@ -66,11 +65,9 @@ export default function VipNeatoCard({
|
|||||||
onPowerCycle,
|
onPowerCycle,
|
||||||
fullWidth = false,
|
fullWidth = false,
|
||||||
}) {
|
}) {
|
||||||
const socket = useSocket();
|
|
||||||
const [working, setWorking] = useState('');
|
const [working, setWorking] = useState('');
|
||||||
const [lidarFlash, setLidarFlash] = useState(false);
|
const [lidarFlash, setLidarFlash] = useState(false);
|
||||||
const [showLidarDebug, setShowLidarDebug] = useState(false);
|
const [showLidarDebug, setShowLidarDebug] = useState(false);
|
||||||
const [recentLidarLines, setRecentLidarLines] = useState([]);
|
|
||||||
const wrapClass = fullWidth ? 'w-full' : 'w-full max-w-xl';
|
const wrapClass = fullWidth ? 'w-full' : 'w-full max-w-xl';
|
||||||
|
|
||||||
const configured = Boolean(neato?.configured);
|
const configured = Boolean(neato?.configured);
|
||||||
@@ -135,19 +132,6 @@ export default function VipNeatoCard({
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [lidar]);
|
}, [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 (
|
return (
|
||||||
<section className={`surface text-sm text-slate-200 ${wrapClass}`}>
|
<section className={`surface text-sm text-slate-200 ${wrapClass}`}>
|
||||||
<div className="grid gap-0.5">
|
<div className="grid gap-0.5">
|
||||||
@@ -267,23 +251,37 @@ export default function VipNeatoCard({
|
|||||||
<div className="mt-0.25 aspect-square rounded-md bg-slate-900 p-0.25">
|
<div className="mt-0.25 aspect-square rounded-md bg-slate-900 p-0.25">
|
||||||
{lidarDots ? (
|
{lidarDots ? (
|
||||||
<svg viewBox="0 0 220 220" className="h-full w-full">
|
<svg viewBox="0 0 220 220" className="h-full w-full">
|
||||||
<circle cx="110" cy="110" r="92" fill="none" stroke="#475569" strokeWidth="1" />
|
<rect x="0" y="0" width="220" height="220" fill="#020617" />
|
||||||
<circle cx="110" cy="110" r="61" fill="none" stroke="#334155" strokeWidth="1" />
|
<circle cx="110" cy="110" r="92" fill="none" stroke="#166534" strokeWidth="1" />
|
||||||
<circle cx="110" cy="110" r="31" fill="none" stroke="#1e293b" strokeWidth="1" />
|
<circle cx="110" cy="110" r="61" fill="none" stroke="#15803d" strokeWidth="1" />
|
||||||
<line x1="110" y1="18" x2="110" y2="202" stroke="#334155" strokeWidth="1" />
|
<circle cx="110" cy="110" r="31" fill="none" stroke="#22c55e" strokeWidth="1" />
|
||||||
<line x1="18" y1="110" x2="202" y2="110" stroke="#334155" strokeWidth="1" />
|
<line x1="110" y1="18" x2="110" y2="202" stroke="#166534" strokeWidth="1" />
|
||||||
<circle cx="110" cy="110" r="4" fill="#e2e8f0" />
|
<line x1="18" y1="110" x2="202" y2="110" stroke="#166534" strokeWidth="1" />
|
||||||
|
<circle cx="110" cy="110" r="4" fill="#4ade80" />
|
||||||
<polyline
|
<polyline
|
||||||
points={lidarDots}
|
points={lidarDots}
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="#38bdf8"
|
stroke="#4ade80"
|
||||||
strokeWidth="1.5"
|
strokeWidth="1.5"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
/>
|
/>
|
||||||
|
{lidarPoints
|
||||||
|
.filter(
|
||||||
|
(point) =>
|
||||||
|
point && point.valid && Number.isFinite(point.angleDeg) && Number.isFinite(point.distanceMm),
|
||||||
|
)
|
||||||
|
.map((point) => {
|
||||||
|
const angleRad = ((Number(point.angleDeg) - 90) * Math.PI) / 180;
|
||||||
|
const normalized = Math.max(0, Math.min(1, Number(point.distanceMm) / 4000));
|
||||||
|
const scaledRadius = normalized * 92;
|
||||||
|
const x = 110 + Math.cos(angleRad) * scaledRadius;
|
||||||
|
const y = 110 + Math.sin(angleRad) * scaledRadius;
|
||||||
|
return <circle key={`${point.angleDeg}-${point.distanceMm}-${point.intensity}`} cx={x} cy={y} r="1.6" fill="#86efac" />;
|
||||||
|
})}
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full items-center justify-center text-center text-xs text-slate-400">
|
<div className="flex h-full items-center justify-center text-center text-xs text-emerald-300">
|
||||||
Waiting for scan
|
Waiting for scan
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -304,18 +302,6 @@ export default function VipNeatoCard({
|
|||||||
<div>Rotation no scan: {lidarStats?.rotationsWithoutScan ?? '--'}</div>
|
<div>Rotation no scan: {lidarStats?.rotationsWithoutScan ?? '--'}</div>
|
||||||
<div>Parseable payloads: {lidarStats?.parseablePayloads ?? '--'}</div>
|
<div>Parseable payloads: {lidarStats?.parseablePayloads ?? '--'}</div>
|
||||||
<div>Point payloads: {lidarStats?.pointPayloads ?? '--'}</div>
|
<div>Point payloads: {lidarStats?.pointPayloads ?? '--'}</div>
|
||||||
<div className="mt-0.5 border-t border-slate-700 pt-0.5 text-slate-400">Raw ESP lines</div>
|
|
||||||
<div className="mt-0.25 max-h-40 overflow-y-auto rounded bg-black/30 px-0.5 py-0.5 text-[0.62rem] leading-tight text-slate-300">
|
|
||||||
{recentLidarLines.length ? (
|
|
||||||
recentLidarLines.map((entry, index) => (
|
|
||||||
<div key={`${index}-${entry.source || 'line'}`} className="break-all">
|
|
||||||
<span className="text-slate-500">[{entry.source || 'line'}]</span> {entry.line}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div className="text-slate-500">No raw lines yet</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user