fix: OTA wait for 0xFF confirm before reboot, version bump to 15, improved logging

This commit is contained in:
eddy 2026-08-02 00:48:28 +02:00
commit 516a938c7b
6 changed files with 87 additions and 28 deletions

View file

@ -424,7 +424,7 @@ void loop() {
}
static uint32_t heartbeat = 0;
if (millis() - heartbeat > 5000) {
if (millis() - heartbeat > 60000) {
Serial.printf("[heartbeat] t1=%s t2=%s btn=%s r1=%s r2=%s connected=%s\n",
t1Active ? "YES" : "no",
t2Active ? "YES" : "no",

View file

@ -63,6 +63,11 @@ uint32_t otaWritten = 0;
uint8_t otaExpectedSha[32];
mbedtls_sha256_context otaShaCtx;
bool otaShaStarted = false;
bool otaReady = false;
bool otaEnded = false;
bool otaConfirmed = false;
uint32_t otaEndedAt = 0;
#define OTA_CONFIRM_TIMEOUT_MS 10000
uint8_t hmacKey[HMAC_KEY_LEN];
uint8_t deviceUuid[ESP_UUID_LEN];
@ -183,6 +188,9 @@ static void otaReset() {
otaPartition = nullptr;
otaExpectedSize = 0;
otaWritten = 0;
otaReady = false;
otaEnded = false;
otaConfirmed = false;
if (otaShaStarted) {
mbedtls_sha256_free(&otaShaCtx);
otaShaStarted = false;
@ -258,36 +266,40 @@ class OtaCharacteristicCallbacks : public NimBLECharacteristicCallbacks {
mbedtls_sha256_finish_ret(&otaShaCtx, computedSha);
mbedtls_sha256_free(&otaShaCtx);
otaShaStarted = false;
esp_err_t err = esp_ota_end(otaHandle);
if (err != ESP_OK) {
Serial.printf("OTA: end failed (%d)\n", err);
otaReset();
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
return;
}
Serial.printf("OTA: SHA256 verify — written=%lu expected=%lu\n", otaWritten, otaExpectedSize);
if (memcmp(computedSha, otaExpectedSha, 32) != 0) {
Serial.println("OTA: SHA256 mismatch — aborting");
esp_ota_abort(otaHandle);
otaReset();
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
return;
}
err = esp_ota_set_boot_partition(otaPartition);
if (err != ESP_OK) {
Serial.printf("OTA: set boot partition failed (%d)\n", err);
otaReset();
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
return;
}
leds[0] = CRGB::Green;
FastLED.show();
Serial.println("OTA: SHA256 OK, setting otaReady=true, sending COMPLETE notify");
otaReady = true;
sendOtaNotify(pChar, OTA_STATUS_COMPLETE, 0);
Serial.println("OTA: SHA256 OK, rebooting...");
delay(500);
esp_restart();
Serial.printf("OTA: COMPLETE notify sent, otaReady=%d, otaConfirmed=%d, otaInProgress=%d\n",
otaReady, otaConfirmed, otaInProgress);
return;
}
if (!otaInProgress) return;
if (!otaInProgress) {
Serial.printf("OTA: write ignored — otaInProgress=false (len=%d, data0=0x%02X)\n", len, data[0]);
return;
}
if (len == 1 && data[0] == 0xFF) {
Serial.printf("OTA: 0xFF received — otaReady=%d, otaEnded=%d, otaConfirmed=%d, otaInProgress=%d\n",
otaReady, otaEnded, otaConfirmed, otaInProgress);
if (!otaEnded) {
Serial.println("OTA: 0xFF IGNORED — otaEnded is false (esp_ota_end not yet called or failed)");
return;
}
Serial.println("OTA: 0xFF confirm accepted, setting otaConfirmed=true");
otaConfirmed = true;
return;
}
if (data[0] < 0x10) {
uint32_t seq = ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) |
@ -521,6 +533,46 @@ void loop() {
}
}
if (otaReady) {
Serial.printf("OTA: loop() processing otaReady — otaWritten=%lu, otaExpectedSize=%lu\n",
otaWritten, otaExpectedSize);
esp_err_t err = esp_ota_end(otaHandle);
if (err != ESP_OK) {
Serial.printf("OTA: esp_ota_end failed (%d) — aborting\n", err);
otaReset();
} else {
Serial.println("OTA: esp_ota_end OK, setting otaEnded=true, waiting for 0xFF confirm");
otaEnded = true;
otaEndedAt = millis();
leds[0] = CRGB::Yellow;
FastLED.show();
}
otaReady = false;
Serial.printf("OTA: otaReady cleared — otaReady=%d, otaEnded=%d, otaConfirmed=%d, otaInProgress=%d\n",
otaReady, otaEnded, otaConfirmed, otaInProgress);
}
if (otaEnded && !otaConfirmed && (millis() - otaEndedAt > OTA_CONFIRM_TIMEOUT_MS)) {
Serial.printf("OTA: 0xFF confirm timeout (%lu ms) — discarding update, resuming normal operation\n",
millis() - otaEndedAt);
otaReset();
}
if (otaConfirmed) {
Serial.println("OTA: otaConfirmed=true, setting boot partition");
esp_err_t err = esp_ota_set_boot_partition(otaPartition);
if (err != ESP_OK) {
Serial.printf("OTA: set boot partition failed (%d)\n", err);
} else {
leds[0] = CRGB::Green;
FastLED.show();
Serial.println("OTA: done, rebooting...");
delay(500);
esp_restart();
}
otaReset();
}
static bool t1Stable = false;
static bool t2Stable = false;
static bool btnStable = false;
@ -574,7 +626,7 @@ void loop() {
}
static uint32_t heartbeat = 0;
if (!otaInProgress && millis() - heartbeat > 5000) {
if (!otaInProgress && millis() - heartbeat > 60000) {
bool anyBle1 = (connActive[0] && bleRelay1[0]) || (connActive[1] && bleRelay1[1]);
bool anyBle2 = (connActive[0] && bleRelay2[0]) || (connActive[1] && bleRelay2[1]);
Serial.printf("[heartbeat] R1=%s R2=%s t1=%s t2=%s btn=%s ble1=%s ble2=%s clients=%d\n",