fix: Different approach on the COM Port and MQTT Fix
This commit is contained in:
@@ -401,25 +401,37 @@ function StepFlash({ device, onFlashed }) {
|
||||
// Start reading raw UART output from the device after flash+reset
|
||||
const startSerialMonitor = async (port) => {
|
||||
serialActiveRef.current = true;
|
||||
// Give the OS a moment to fully release the port from esptool before we re-open
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
|
||||
// Wait for the OS/browser to fully release the port after esptool closed it
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
|
||||
try {
|
||||
await port.open({ baudRate: 115200 });
|
||||
} catch (openErr) {
|
||||
appendSerial(`[Error opening port: ${openErr.message}]`);
|
||||
scrollSerial();
|
||||
return;
|
||||
}
|
||||
|
||||
// Use getReader() directly — avoids locking issues from pipeTo()
|
||||
let reader;
|
||||
try {
|
||||
reader = port.readable.getReader();
|
||||
} catch (readerErr) {
|
||||
appendSerial(`[Error getting reader: ${readerErr.message}]`);
|
||||
scrollSerial();
|
||||
try { await port.close(); } catch (_) {}
|
||||
return;
|
||||
}
|
||||
const decoder = new TextDecoderStream();
|
||||
const readableStreamClosed = port.readable.pipeTo(decoder.writable);
|
||||
const reader = decoder.readable.getReader();
|
||||
serialReaderRef.current = reader;
|
||||
|
||||
const textDecoder = new TextDecoder();
|
||||
let lineBuffer = "";
|
||||
try {
|
||||
while (serialActiveRef.current) {
|
||||
const { value, done: streamDone } = await reader.read();
|
||||
if (streamDone) break;
|
||||
lineBuffer += value;
|
||||
lineBuffer += textDecoder.decode(value, { stream: true });
|
||||
const lines = lineBuffer.split(/\r?\n/);
|
||||
lineBuffer = lines.pop(); // keep incomplete last fragment
|
||||
for (const line of lines) {
|
||||
@@ -431,13 +443,16 @@ function StepFlash({ device, onFlashed }) {
|
||||
}
|
||||
} catch (_) {
|
||||
// Reader cancelled on cleanup — expected
|
||||
} finally {
|
||||
try { reader.releaseLock(); } catch (_) {}
|
||||
}
|
||||
};
|
||||
|
||||
const stopSerialMonitor = async () => {
|
||||
serialActiveRef.current = false;
|
||||
try { await serialReaderRef.current?.cancel(); } catch (_) {}
|
||||
try { portRef.current?.close(); } catch (_) {}
|
||||
try { serialReaderRef.current?.releaseLock(); } catch (_) {}
|
||||
try { await portRef.current?.close(); } catch (_) {}
|
||||
};
|
||||
|
||||
const handleFlash = async () => {
|
||||
@@ -724,31 +739,30 @@ function StepVerify({ device, onVerified }) {
|
||||
setTimedOut(false);
|
||||
setError("");
|
||||
|
||||
const startTime = Date.now();
|
||||
const startTime = new Date().toISOString();
|
||||
|
||||
intervalRef.current = setInterval(async () => {
|
||||
try {
|
||||
const data = await api.get(`/manufacturing/devices/${device.serial_number}`);
|
||||
if (data.mfg_status === "provisioned") {
|
||||
clearInterval(intervalRef.current);
|
||||
clearTimeout(timeoutRef.current);
|
||||
onVerified(data);
|
||||
return;
|
||||
}
|
||||
// Also accept any last_seen update (heartbeat) as evidence of life
|
||||
if (data.last_seen) {
|
||||
const ts = new Date(data.last_seen).getTime();
|
||||
if (ts > startTime) {
|
||||
// Poll the heartbeat endpoint — device is verified when it sends a heartbeat
|
||||
// after we started polling (i.e. after the flash completed)
|
||||
const hbData = await api.get(
|
||||
`/mqtt/heartbeats/${device.serial_number}?limit=1&offset=0`
|
||||
);
|
||||
if (hbData.heartbeats && hbData.heartbeats.length > 0) {
|
||||
const latest = hbData.heartbeats[0];
|
||||
const receivedAt = latest.received_at;
|
||||
if (receivedAt && receivedAt > startTime) {
|
||||
clearInterval(intervalRef.current);
|
||||
clearTimeout(timeoutRef.current);
|
||||
// Promote to provisioned
|
||||
// Promote device status to provisioned
|
||||
try {
|
||||
await api.request(`/manufacturing/devices/${device.serial_number}/status`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ status: "provisioned", note: "Auto-verified via wizard" }),
|
||||
});
|
||||
} catch (_) {}
|
||||
onVerified({ ...data, mfg_status: "provisioned" });
|
||||
const deviceData = await api.get(`/manufacturing/devices/${device.serial_number}`);
|
||||
onVerified({ ...deviceData, mfg_status: "provisioned" });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user