Enable host OTA over BLE and harden ESP-NOW slave distribution.
Allow the same staged firmware upload path on BLE as UART, fix distribute stack/event-group crashes, and recover sticky slave OTA sessions instead of failing with err=4. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+22
-25
@@ -788,23 +788,23 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="col-12" x-show="isUARTHost() || !hostUp()">
|
||||
<section class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">Firmware OTA (A/B)</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted small mb-3">
|
||||
Lädt eine <code>.bin</code> auf den Master (nur UART-Host, DIP8=0), danach verteilt die Firmware automatisch per ESP-NOW an alle verfügbaren Slaves.
|
||||
Während des Uploads pausiert das Live-Polling. Bei BLE-Host ist OTA nicht verfügbar.
|
||||
Lädt eine <code>.bin</code> auf den Master (UART oder BLE), danach verteilt die Firmware automatisch per ESP-NOW an alle verfügbaren Slaves.
|
||||
Während des Uploads pausiert das Live-Polling. BLE braucht ATT MTU ≥ 219.
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control form-control-sm" accept=".bin,application/octet-stream"
|
||||
@change="otaFile = $event.target.files[0]"
|
||||
:disabled="ota.active || busy || !isUARTHost()">
|
||||
:disabled="ota.active || busy || !hostUp()">
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center mb-2">
|
||||
<button type="button" class="btn btn-primary btn-sm"
|
||||
@click="uploadOTA()"
|
||||
:disabled="ota.active || busy || !isUARTHost() || !otaFile">
|
||||
:disabled="ota.active || busy || !hostUp() || !otaFile">
|
||||
Firmware hochladen
|
||||
</button>
|
||||
<span class="text-muted small" x-show="otaFile"
|
||||
@@ -812,7 +812,7 @@
|
||||
</div>
|
||||
<div class="ota-progress-panel mt-3"
|
||||
x-show="ota.active || ota.phase === 'distributing' || ota.phase === 'done' || ota.phase === 'error'">
|
||||
<p class="small text-muted mb-2">Master (UART)</p>
|
||||
<p class="small text-muted mb-2">Master (Host)</p>
|
||||
<table class="table table-sm pp-table ota-progress-table mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -845,7 +845,8 @@
|
||||
Slaves (ESP-NOW)
|
||||
<span x-text="'(' + otaSlaveRows().length + ')'"></span>
|
||||
</p>
|
||||
<p class="small text-muted mb-2" x-show="ota.message && ota.step === 'slaves'"
|
||||
<p class="small text-muted mb-2"
|
||||
x-show="ota.step === 'slaves' && otaSlaveRows().length > 0 && ota.message"
|
||||
x-text="ota.message"></p>
|
||||
<table class="table table-sm pp-table ota-progress-table mb-2">
|
||||
<tbody>
|
||||
@@ -877,9 +878,8 @@
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-show="otaSlaveRows().length === 0">
|
||||
<td colspan="2" class="text-muted small py-3">
|
||||
Warte auf Slave-Fortschritt…
|
||||
</td>
|
||||
<td colspan="2" class="text-muted small py-3"
|
||||
x-text="otaDistEmptyHint()"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1422,7 +1422,19 @@
|
||||
if (status === 1 || status === 2) return 'bg-secondary';
|
||||
return 'bg-info';
|
||||
},
|
||||
otaDistEmptyHint() {
|
||||
const msg = this.ota.message || '';
|
||||
if (/übersprungen/i.test(msg)) {
|
||||
return msg;
|
||||
}
|
||||
if (this.ota.phase === 'done') {
|
||||
return 'Keine Slave-Verteilung gemeldet.';
|
||||
}
|
||||
return 'Warte auf Slave-Fortschritt…';
|
||||
},
|
||||
otaSlaveRows() {
|
||||
// Only real OTA progress — do not invent placeholder rows from the
|
||||
// client list (that contradicted "keine Slaves / übersprungen").
|
||||
const details = this.mergeSlaveDetails(this.ota.slaveDetails);
|
||||
const ids = new Set(Object.keys(details).map(Number).filter(id => !Number.isNaN(id)));
|
||||
for (const [k, v] of Object.entries(this.ota.slaveProgress || {})) {
|
||||
@@ -1454,21 +1466,6 @@
|
||||
bytesLabel: total ? `${bytes} / ${total} bytes` : `${bytes} bytes`
|
||||
});
|
||||
}
|
||||
if (rows.length === 0 && (this.ota.phase === 'distributing' || this.ota.step === 'slaves')) {
|
||||
const targets = (this.state.clients || []).filter(c => c.available);
|
||||
const limit = this.ota.slaves > 0 ? this.ota.slaves : targets.length;
|
||||
for (const c of targets.slice(0, limit)) {
|
||||
rows.push({
|
||||
id: c.id,
|
||||
mac: c.mac ? this.formatMac(c.mac) : '—',
|
||||
percent: 0,
|
||||
status: 1,
|
||||
statusLabel: this.otaSlaveStatusLabel(1),
|
||||
barClass: this.otaSlaveBarClass(1),
|
||||
bytesLabel: '—'
|
||||
});
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
applyOTAProgress(p) {
|
||||
|
||||
Reference in New Issue
Block a user