Диагностика сохранения EEPROM: проверять commit() и перечитывание
Настройки не сохраняются после перезагрузки. Причина пока не установлена, это шаг сбора улик, а не исправление. Найден дефект, мешавший диагностике: результат EEPROM.commit() игнорировался, поэтому лог печатал «Конфигурация сохранена» безусловно — даже при провалившейся записи. Теперь запись подтверждается повторным чтением сектора из флеша и сравнением всех полей; при расхождении в лог идут записанные и прочитанные значения. Добавлена проверка геометрии флеша при старте: несовпадение размера по настройке IDE с физическим уводит сектор EEPROM за пределы микросхемы, и запись молча теряется — симптом ровно тот же. Проверкой чтения исключены: корректность библиотеки EEPROM, раскладка адресов (258 из 512, без перекрытий), стирание сектора со стороны WiFiManager::resetSettings() — он вызывает только WiFi.disconnect(). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -149,16 +149,57 @@ static void eepromReadStr(int addr, int fieldLen, char* dst) {
|
|||||||
dst[fieldLen] = '\0';
|
dst[fieldLen] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void eepromWriteConfig() {
|
// Возвращает true только если запись подтверждена перечитыванием из флеша.
|
||||||
|
// Проверка нужна потому, что EEPROM.commit() умеет вернуть false (например при
|
||||||
|
// неверно выбранном размере флеша в IDE), и молчаливая потеря настроек выглядит
|
||||||
|
// точно так же, как «не сохраняется».
|
||||||
|
bool eepromWriteConfig() {
|
||||||
EEPROM.put(EEPROM_MAGIC_ADDR, EEPROM_MAGIC_V2);
|
EEPROM.put(EEPROM_MAGIC_ADDR, EEPROM_MAGIC_V2);
|
||||||
eepromWriteStr(EEPROM_URL_ADDR, WEBHOOK_MAX_LEN, webhook_url);
|
eepromWriteStr(EEPROM_URL_ADDR, WEBHOOK_MAX_LEN, webhook_url);
|
||||||
eepromWriteStr(EEPROM_DEVICE_ADDR, DEVICE_MAX_LEN, device_name);
|
eepromWriteStr(EEPROM_DEVICE_ADDR, DEVICE_MAX_LEN, device_name);
|
||||||
EEPROM.put(EEPROM_ALARM_ADDR, alarmDelaySec);
|
EEPROM.put(EEPROM_ALARM_ADDR, alarmDelaySec);
|
||||||
EEPROM.put(EEPROM_EMERG_ADDR, emergDelaySec);
|
EEPROM.put(EEPROM_EMERG_ADDR, emergDelaySec);
|
||||||
EEPROM.commit();
|
|
||||||
Serial.printf("[EEPROM] Конфигурация сохранена: device=%s, авария=%u с, резерв=%u с\n",
|
if (!EEPROM.commit()) {
|
||||||
|
Serial.println(F("[EEPROM] ОШИБКА: commit() вернул false, настройки НЕ сохранены"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Повторный begin() перечитывает сектор из флеша в буфер — это и есть проверка,
|
||||||
|
// что записанное действительно легло на флеш, а не только в ОЗУ.
|
||||||
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
|
|
||||||
|
uint16_t magicChk, alarmChk, emergChk;
|
||||||
|
char urlChk[WEBHOOK_MAX_LEN + 1];
|
||||||
|
char devChk[DEVICE_MAX_LEN + 1];
|
||||||
|
EEPROM.get(EEPROM_MAGIC_ADDR, magicChk);
|
||||||
|
eepromReadStr(EEPROM_URL_ADDR, WEBHOOK_MAX_LEN, urlChk);
|
||||||
|
eepromReadStr(EEPROM_DEVICE_ADDR, DEVICE_MAX_LEN, devChk);
|
||||||
|
EEPROM.get(EEPROM_ALARM_ADDR, alarmChk);
|
||||||
|
EEPROM.get(EEPROM_EMERG_ADDR, emergChk);
|
||||||
|
|
||||||
|
bool ok = (magicChk == EEPROM_MAGIC_V2) &&
|
||||||
|
(strcmp(urlChk, webhook_url) == 0) &&
|
||||||
|
(strcmp(devChk, device_name) == 0) &&
|
||||||
|
(alarmChk == alarmDelaySec) &&
|
||||||
|
(emergChk == emergDelaySec);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
Serial.println(F("[EEPROM] ОШИБКА: запись не подтвердилась при перечитывании!"));
|
||||||
|
Serial.printf("[EEPROM] magic: записан 0x%04X, прочитан 0x%04X\n",
|
||||||
|
EEPROM_MAGIC_V2, magicChk);
|
||||||
|
Serial.printf("[EEPROM] device: записан '%s', прочитан '%s'\n", device_name, devChk);
|
||||||
|
Serial.printf("[EEPROM] выдержки: записаны %u/%u, прочитаны %u/%u\n",
|
||||||
|
alarmDelaySec, emergDelaySec, alarmChk, emergChk);
|
||||||
|
Serial.println("[EEPROM] URL записан: " + String(webhook_url));
|
||||||
|
Serial.println("[EEPROM] URL прочитан: " + String(urlChk));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("[EEPROM] Сохранено и проверено: device=%s, авария=%u с, резерв=%u с\n",
|
||||||
device_name, alarmDelaySec, emergDelaySec);
|
device_name, alarmDelaySec, emergDelaySec);
|
||||||
Serial.println("[EEPROM] URL: " + String(webhook_url[0] ? webhook_url : "(не задан)"));
|
Serial.println("[EEPROM] URL: " + String(webhook_url[0] ? webhook_url : "(не задан)"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void configSetDefaults() {
|
static void configSetDefaults() {
|
||||||
@@ -670,6 +711,21 @@ void setup() {
|
|||||||
Serial.println(F("[OLED] Дисплей не найден! Проверь адрес (0x3C/0x3D) и провода."));
|
Serial.println(F("[OLED] Дисплей не найден! Проверь адрес (0x3C/0x3D) и провода."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Диагностика флеша. Если «размер по настройке IDE» больше физического, то
|
||||||
|
// сектор EEPROM оказывается за пределами микросхемы и запись молча теряется —
|
||||||
|
// выглядит это ровно как «настройки не сохраняются».
|
||||||
|
uint32_t flashIde = ESP.getFlashChipSize();
|
||||||
|
uint32_t flashReal = ESP.getFlashChipRealSize();
|
||||||
|
Serial.printf("[FLASH] по настройке IDE: %u Б, физически: %u Б -> %s\n",
|
||||||
|
flashIde, flashReal,
|
||||||
|
flashIde == flashReal ? "совпадает" : "!!! НЕ СОВПАДАЕТ !!!");
|
||||||
|
Serial.printf("[FLASH] скетч %u Б, свободно под скетч %u Б\n",
|
||||||
|
ESP.getSketchSize(), ESP.getFreeSketchSpace());
|
||||||
|
if (flashIde != flashReal) {
|
||||||
|
Serial.println(F("[FLASH] ВНИМАНИЕ: выберите в IDE верный размер флеша,"));
|
||||||
|
Serial.println(F("[FLASH] иначе EEPROM не сохраняется."));
|
||||||
|
}
|
||||||
|
|
||||||
EEPROM.begin(EEPROM_SIZE);
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
eepromReadConfig();
|
eepromReadConfig();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user