From d07a0dd23c948c2970ab7b9de8cdadda46a4f1e0 Mon Sep 17 00:00:00 2001 From: Vitali Date: Fri, 7 Aug 2026 16:29:47 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=B8=D0=B0=D0=B3=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BA=D0=B0=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20EEPROM:=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=8F=D1=82=D1=8C=20commit()=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=87=D0=B8=D1=82=D1=8B=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Настройки не сохраняются после перезагрузки. Причина пока не установлена, это шаг сбора улик, а не исправление. Найден дефект, мешавший диагностике: результат EEPROM.commit() игнорировался, поэтому лог печатал «Конфигурация сохранена» безусловно — даже при провалившейся записи. Теперь запись подтверждается повторным чтением сектора из флеша и сравнением всех полей; при расхождении в лог идут записанные и прочитанные значения. Добавлена проверка геометрии флеша при старте: несовпадение размера по настройке IDE с физическим уводит сектор EEPROM за пределы микросхемы, и запись молча теряется — симптом ровно тот же. Проверкой чтения исключены: корректность библиотеки EEPROM, раскладка адресов (258 из 512, без перекрытий), стирание сектора со стороны WiFiManager::resetSettings() — он вызывает только WiFi.disconnect(). Co-Authored-By: Claude Opus 5 --- .../pump_controller_8_2_OLED_DONE.ino | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/pump_controller_8_2_OLED_DONE/pump_controller_8_2_OLED_DONE.ino b/pump_controller_8_2_OLED_DONE/pump_controller_8_2_OLED_DONE.ino index 99fb05d..fc6dc87 100644 --- a/pump_controller_8_2_OLED_DONE/pump_controller_8_2_OLED_DONE.ino +++ b/pump_controller_8_2_OLED_DONE/pump_controller_8_2_OLED_DONE.ino @@ -149,16 +149,57 @@ static void eepromReadStr(int addr, int fieldLen, char* dst) { dst[fieldLen] = '\0'; } -void eepromWriteConfig() { +// Возвращает true только если запись подтверждена перечитыванием из флеша. +// Проверка нужна потому, что EEPROM.commit() умеет вернуть false (например при +// неверно выбранном размере флеша в IDE), и молчаливая потеря настроек выглядит +// точно так же, как «не сохраняется». +bool eepromWriteConfig() { EEPROM.put(EEPROM_MAGIC_ADDR, EEPROM_MAGIC_V2); eepromWriteStr(EEPROM_URL_ADDR, WEBHOOK_MAX_LEN, webhook_url); eepromWriteStr(EEPROM_DEVICE_ADDR, DEVICE_MAX_LEN, device_name); EEPROM.put(EEPROM_ALARM_ADDR, alarmDelaySec); 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); Serial.println("[EEPROM] URL: " + String(webhook_url[0] ? webhook_url : "(не задан)")); + return true; } static void configSetDefaults() { @@ -670,6 +711,21 @@ void setup() { 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); eepromReadConfig();