ota-hub-reactjs 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -36,7 +36,7 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
36
36
|
let inSlipFrame = false; // are we inside a SLIP frame?
|
|
37
37
|
let escapeNext = false;
|
|
38
38
|
const reader = transport.rawRead();
|
|
39
|
-
base.updateConnection(uuid, (c) => ({ ...c
|
|
39
|
+
base.updateConnection(uuid, (c) => ({ ...c }));
|
|
40
40
|
try {
|
|
41
41
|
while (true) {
|
|
42
42
|
const conn = base.getConnection(uuid);
|
|
@@ -44,6 +44,8 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
44
44
|
console.log("Kack!");
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
+
if (conn.isFlashing || !conn.isConnected)
|
|
48
|
+
break;
|
|
47
49
|
const { value, done } = await reader.next();
|
|
48
50
|
if (done || !value)
|
|
49
51
|
break;
|
|
@@ -114,6 +116,7 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
}
|
|
119
|
+
await new Promise((resolve) => setTimeout(resolve, 100)); // Little breather before attempt any disconnects
|
|
117
120
|
}
|
|
118
121
|
catch (e) {
|
|
119
122
|
base.appendLog(uuid, {
|
|
@@ -122,13 +125,11 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
122
125
|
});
|
|
123
126
|
}
|
|
124
127
|
finally {
|
|
125
|
-
|
|
126
|
-
base.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
131
|
-
await disconnect(uuid);
|
|
128
|
+
base.updateConnection(uuid, (c) => ({ ...c }));
|
|
129
|
+
const conn = base.getConnection(uuid);
|
|
130
|
+
if (conn?.isConnected) {
|
|
131
|
+
await disconnect(uuid);
|
|
132
|
+
}
|
|
132
133
|
}
|
|
133
134
|
};
|
|
134
135
|
const restartDevice = async (uuid, default_transport) => {
|
|
@@ -177,7 +178,8 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
177
178
|
const esploader = new ESPLoader({
|
|
178
179
|
transport,
|
|
179
180
|
baudrate: use_baudrate,
|
|
180
|
-
enableTracing:
|
|
181
|
+
enableTracing: !!conn.debugLogging,
|
|
182
|
+
debugLogging: !!conn.debugLogging,
|
|
181
183
|
});
|
|
182
184
|
try {
|
|
183
185
|
await esploader.main();
|
|
@@ -229,18 +231,6 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
229
231
|
};
|
|
230
232
|
const disconnect = async (uuid, timeout = 2000) => {
|
|
231
233
|
const conn = base.getConnection(uuid);
|
|
232
|
-
// 1. POLITELY KILL THE READER
|
|
233
|
-
// If we have an active reader generator in state, call return() to
|
|
234
|
-
// gracefully resolve the pending reader.next() in the background loop
|
|
235
|
-
if (conn?.reader && typeof conn.reader.return === "function") {
|
|
236
|
-
try {
|
|
237
|
-
// @ts-ignore - The underlying AsyncGenerator handles return gracefully
|
|
238
|
-
await conn.reader.return();
|
|
239
|
-
}
|
|
240
|
-
catch (e) {
|
|
241
|
-
console.warn(`[${uuid}] Error returning generator lock:`, e);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
234
|
if (conn?.transport) {
|
|
245
235
|
try {
|
|
246
236
|
// Attempt disconnect, but don’t hang if the port is crashed
|
|
@@ -256,13 +246,17 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
256
246
|
// Always clear the transport and reset connection state
|
|
257
247
|
base.updateConnection(uuid, (c) => ({
|
|
258
248
|
...c,
|
|
259
|
-
port: releasePortByDefault ?
|
|
260
|
-
transport: releasePortByDefault ?
|
|
261
|
-
|
|
249
|
+
port: releasePortByDefault ? null : c.port,
|
|
250
|
+
transport: releasePortByDefault ? null : c.transport,
|
|
251
|
+
esp: releasePortByDefault ? null : c.transport,
|
|
262
252
|
isConnected: false,
|
|
263
253
|
isConnecting: false,
|
|
264
254
|
autoConnect: false,
|
|
265
255
|
}));
|
|
256
|
+
base.appendLog(uuid, {
|
|
257
|
+
level: 0,
|
|
258
|
+
message: "[!] Serial disconnected",
|
|
259
|
+
});
|
|
266
260
|
await conn?.onDisconnect?.();
|
|
267
261
|
};
|
|
268
262
|
const addConnection = async ({ uuid, propCreator, }) => {
|
|
@@ -332,37 +326,34 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
332
326
|
};
|
|
333
327
|
// This function now handles an entire device flashing session
|
|
334
328
|
const handleFlashFirmware = async (uuid, assetsToFlash) => {
|
|
329
|
+
// Capture the original connection and port reference before disconnect
|
|
335
330
|
const conn = base.getConnection(uuid);
|
|
336
331
|
// 1. Bail if we don't have the required state
|
|
337
|
-
if (!conn ||
|
|
338
|
-
!conn.transport ||
|
|
339
|
-
!conn.port ||
|
|
340
|
-
!conn.esp ||
|
|
341
|
-
assetsToFlash.length === 0)
|
|
332
|
+
if (!conn || !conn.port || assetsToFlash.length === 0)
|
|
342
333
|
return;
|
|
343
|
-
|
|
344
|
-
await disconnect(uuid);
|
|
334
|
+
const prevAutoConnect = conn.autoConnect;
|
|
345
335
|
base.updateConnection(uuid, (c) => ({
|
|
346
336
|
...c,
|
|
337
|
+
port: conn.port, // Restore the port into state in case disconnect wiped it
|
|
347
338
|
isFlashing: true,
|
|
348
339
|
flashProgress: 0,
|
|
349
340
|
flashError: undefined,
|
|
341
|
+
autoConnect: false,
|
|
350
342
|
}));
|
|
343
|
+
if (conn.isConnected)
|
|
344
|
+
await disconnect(uuid);
|
|
345
|
+
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
351
346
|
try {
|
|
352
347
|
// --- Connect ONCE ---
|
|
353
348
|
const transport = new Transport(conn.port, true);
|
|
354
349
|
const esploader = new ESPLoader({
|
|
355
350
|
transport,
|
|
356
351
|
baudrate: 921600,
|
|
357
|
-
enableTracing:
|
|
352
|
+
enableTracing: !!conn.debugLogging,
|
|
353
|
+
debugLogging: !!conn.debugLogging,
|
|
358
354
|
});
|
|
359
|
-
try
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
catch (e) {
|
|
363
|
-
console.log("failed to esploader.main()", e);
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
355
|
+
// This may fail, that'll bubble the failure up to the upper try/catch
|
|
356
|
+
await esploader.main();
|
|
366
357
|
// --- Prepare an ARRAY of files for the library ---
|
|
367
358
|
const fileArray = await Promise.all(assetsToFlash.map(async ({ blob, address }) => {
|
|
368
359
|
const arrayBuffer = await blob.arrayBuffer();
|
|
@@ -371,32 +362,34 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
371
362
|
.join("");
|
|
372
363
|
return { data: binaryString, address };
|
|
373
364
|
}));
|
|
365
|
+
let lastRenderTime = 0;
|
|
374
366
|
const flashOptions = {
|
|
375
|
-
fileArray,
|
|
367
|
+
fileArray,
|
|
376
368
|
flashSize: "keep",
|
|
377
369
|
flashMode: "qio",
|
|
378
370
|
flashFreq: "80m",
|
|
379
371
|
eraseAll: fileArray.length > 1, // Writing more than 1 thing, so likely writing partitions.
|
|
380
372
|
compress: true,
|
|
381
373
|
reportProgress: (fileIndex, written, total) => {
|
|
382
|
-
// You can enhance progress reporting to show which file is being flashed
|
|
383
374
|
const progress = (written / total) * 100;
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
375
|
+
const now = performance.now();
|
|
376
|
+
// Throttle UI updates to at most once every 100ms (~10 FPS),
|
|
377
|
+
// but ALWAYS ensure the final 100% tick renders.
|
|
378
|
+
if (now - lastRenderTime > 100 || written === total) {
|
|
379
|
+
lastRenderTime = now;
|
|
380
|
+
// Optional: Only log every 100ms as well to prevent console spam
|
|
381
|
+
console.log(`Flashing file ${fileIndex + 1}/${fileArray.length}: ${progress.toFixed(1)}%`);
|
|
382
|
+
base.updateConnection(uuid, (c) => ({
|
|
383
|
+
...c,
|
|
384
|
+
flashProgress: progress,
|
|
385
|
+
}));
|
|
386
|
+
}
|
|
389
387
|
},
|
|
390
388
|
};
|
|
391
389
|
// --- Call writeFlash ONCE with all files ---
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
catch (e) {
|
|
397
|
-
console.log("failed to esploader.writeFlash", e);
|
|
398
|
-
}
|
|
399
|
-
// --- Disconnect ---
|
|
390
|
+
base.updateConnection(uuid, (c) => ({ ...c, flashProgress: -1 }));
|
|
391
|
+
await esploader.writeFlash(flashOptions);
|
|
392
|
+
// --- Disconnect cleanly ---
|
|
400
393
|
await esploader.after();
|
|
401
394
|
try {
|
|
402
395
|
await transport.disconnect();
|
|
@@ -411,9 +404,8 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
411
404
|
...c,
|
|
412
405
|
isFlashing: false,
|
|
413
406
|
flashProgress: 100,
|
|
407
|
+
autoConnect: prevAutoConnect,
|
|
414
408
|
}));
|
|
415
|
-
// --- Reconnect the standard monitor ---
|
|
416
|
-
await connect(uuid);
|
|
417
409
|
}
|
|
418
410
|
catch (e) {
|
|
419
411
|
console.error(`[${uuid}] Flashing failed:`, e);
|
|
@@ -423,6 +415,8 @@ export function useESP32MultiDeviceWhisperer({ releasePortByDefault, ...props }
|
|
|
423
415
|
flashError: e?.message ?? "Unknown error",
|
|
424
416
|
}));
|
|
425
417
|
// Attempt recovery
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
426
420
|
await connect(uuid);
|
|
427
421
|
}
|
|
428
422
|
};
|
package/package.json
CHANGED