Commit Graph
41 Commits
Author SHA1 Message Date
oskarvitaliiandClaude Opus 5 635d5e2460 docs: add pump_controller_8_2_OLED_DONE to the projects index
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:56:50 +07:00
oskarvitalii 9d764ba43f Добавить проект pump_controller_8_2_OLED_DONE
Контроллер насосной станции на Wemos D1 mini: мониторинг двух основных
и резервного насоса, два реле аварий, OLED, веб-панель с настройками,
уведомления на HTTPS-webhook.

История проекта влита целиком, в сообщениях коммитов разобраны причины
принятых решений: выбор пинов D3/D4 под реле active-LOW, ограничение
блокировки loop() при отправке webhook, перенос настроек в LittleFS и
найденная причина несохранения настроек (чип 2 МБ при настройке IDE 4 МБ).
2026-08-07 22:56:09 +07:00
VitaliandClaude Opus 5 f0e8102c5c Уточнить в коде причину отказа от EEPROM
Комментарий утверждал, что запись в EEPROM на этой плате проваливается,
что читается как «EEPROM сломана». На деле причина была в неверном
Flash Size, и с верной настройкой работали бы оба механизма. Формулировка
исправлена, чтобы следующий читатель не пошёл менять хранилище вместо
проверки размера чипа.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 20:05:42 +07:00
VitaliandClaude Opus 5 5784e256a7 Зафиксировать проверенную на железе раскладку 2MB (FS:64KB)
Прошивка запущена на целевой плате: LittleFS монтируется и отдаёт
45056 Б, файл настроек читается при старте. В документации указан
фактически использованный вариант Flash Size вместо предполагавшегося
FS:128KB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 20:04:42 +07:00
VitaliandClaude Opus 5 f0844a15af Найдена причина: чип 2 МБ при настройке IDE 4 МБ
Плата имеет физически 2 МБ флеша, в IDE было выбрано 4MB (FS:2MB).
При этой раскладке сектор EEPROM лежит по смещению 0x3FB000, а начало
LittleFS — по 0x400000, тогда как чип заканчивается на 0x200000. Обе
области вне микросхемы, поэтому spi_flash_erase_sector() проваливался
и EEPROM.commit() возвращал false.

Лечится настройкой Flash Size = 2MB (FS:128KB OTA:~960KB), а не кодом:
любая раскладка 2MB кладёт файловую систему ниже 0x1FB000, а EEPROM в
сектор 511. С верной настройкой работали бы оба механизма хранения.

Ранее записанная в README гипотеза про «щель между FS и областью SDK»
была неверной и заменена подтверждённым разбором. Переход на LittleFS
остаётся оправданным по своим качествам, но проблему решает настройка
IDE — в документации это разделено явно, чтобы не ввести в заблуждение
при похожем симптоме на другой плате.

Документация исправлена: плата 2 МБ, а не 4 МБ; требование совпадения
выбранного размера с физическим; предупреждение о потере учётных данных
Wi-Fi при смене раскладки.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 19:51:38 +07:00
VitaliandClaude Opus 5 b18f0d0ce0 Перенести настройки из EEPROM в LittleFS
EEPROM.commit() на целевой плате возвращает false — падает сам вызов SDK.
Проверкой исходников исключены ошибка в библиотеке, перекрытие адресов и
стирание сектора со стороны WiFiManager. Физический размер флеша тоже ни
при чём: LittleFS на этом же чипе работает, что подтверждено соседним
проектом на такой же плате.

Наиболее вероятный механизм: при раскладке 4MB/FS:2MB сектор EEPROM (1019,
0x3FB000) попадает в щель между концом ФС (0x3FA000) и служебной областью
SDK (0x3FC000) и оказывается защищён от стирания. Доказать не удалось,
поэтому в документации гипотеза помечена как гипотеза. Переход на LittleFS
выбран не как обход симптома, а как переезд на подтверждённо работающий
на этом железе механизм.

Настройки теперь в /settings.json (ArduinoJson v7). Загрузка
отказоустойчива: отсутствующий или битый ключ оставляет значение по
умолчанию, поэтому файл от прошлой версии прошивки не ломается при
добавлении полей. Имена ключей вынесены в константы KEY_*, используемые и
при чтении, и при записи.

Молчаливой потери настроек больше нет: при недоступной ФС взводится
settingsFsReady = false, и веб-панель показывает предупреждение, что
настройки не переживут перезагрузку. В лог при старте выводится геометрия
ФС и предупреждение при выборе FS:none.

Проверено: xtensa-lx106-elf-g++ -fsyntax-only -Wall -Wextra против ядра
3.1.2 — предупреждений нет. На железе не проверялось.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 19:41:05 +07:00
VitaliandClaude Opus 5 56e6bfd098 Диагностика: печатать сектор EEPROM и границы FS против физического флеша
commit() возвращает false, то есть падает сам вызов SDK
(spi_flash_erase_sector либо spi_flash_write). Самая вероятная причина —
сектор EEPROM за пределами физической микросхемы.

При раскладке 4MB/FS:2MB сектор EEPROM это 1019 (смещение 0x3FB000), что
требует чипа не меньше 4 МБ. Теперь лог сам печатает это смещение и
сравнивает с ESP.getFlashChipRealSize(), а также границы файловой системы —
последнее важно, потому что при том же дефекте LittleFS по адресу
0x400000 окажется недоступен ровно так же.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 17:21:25 +07:00
VitaliandClaude Opus 5 d07a0dd23c Диагностика сохранения EEPROM: проверять commit() и перечитывание
Настройки не сохраняются после перезагрузки. Причина пока не установлена,
это шаг сбора улик, а не исправление.

Найден дефект, мешавший диагностике: результат EEPROM.commit()
игнорировался, поэтому лог печатал «Конфигурация сохранена» безусловно —
даже при провалившейся записи. Теперь запись подтверждается повторным
чтением сектора из флеша и сравнением всех полей; при расхождении в лог
идут записанные и прочитанные значения.

Добавлена проверка геометрии флеша при старте: несовпадение размера по
настройке IDE с физическим уводит сектор EEPROM за пределы микросхемы,
и запись молча теряется — симптом ровно тот же.

Проверкой чтения исключены: корректность библиотеки EEPROM, раскладка
адресов (258 из 512, без перекрытий), стирание сектора со стороны
WiFiManager::resetSettings() — он вызывает только WiFi.disconnect().

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:29:47 +07:00
VitaliandClaude Opus 5 a7ec85096a Настройки через веб, состояние реле в UI, распиновка под реле active-LOW
Распиновка. Пина D0, который использовался под выход «Резерв», в доступном
наборе нет. Кнопка сброса Wi-Fi удалена как избыточная: при пропавшей сети
wm.autoConnect() сам поднимает портал. Освободившийся D3 закрыл дефицит.

Выходы переехали на D3 и D4 и стали инверсными. Причина: для реле active-LOW
безопасное состояние — пин в HIGH, а D3/D4 подтянуты к HIGH внешними
резисторами платы и держат этот уровень всю загрузку. D8, наоборот, подтянут
к LOW и щёлкал бы реле при каждом включении питания. В setup() digitalWrite()
идёт до pinMode(), иначе защёлка выхода даёт короткий LOW.

Инверсия живёт только в setRelay(); логическое состояние дублируется в
relayMainOn/relayEmergOn, чтобы панель показывала смысл, а не уровень пина.

Настройки. device, выдержка аварии и выдержка резерва вынесены в /set_config
и EEPROM. Раскладка EEPROM версионирована: magic 0xA55B, старый 0xA55A
распознаётся и переносится, поэтому прошитые приборы не теряют webhook.
Значения по умолчанию воспроизводят прежнее поведение (5 с и 0 с).

Для резерва добавлена выдержка, которой раньше не было, симметрично основной
аварии. Обе выдержки гасят реле и вебхук одновременно.

device_name фильтруется до [A-Za-z0-9_-] вместо экранирования: такой набор
безопасен и в JSON, и в HTML. Пустое или неверное поле формы означает
«не менять», поэтому частичное заполнение не сбрасывает остальное.

Состояние реле выведено в /status и в панель.

Проверено: xtensa-lx106-elf-g++ -fsyntax-only -Wall -Wextra против ядра
3.1.2 — предупреждений в скетче нет (попутно убран неиспользуемый
isEmergency); валидация настроек прогнана на 22 граничных случаях;
раскладка EEPROM проверена на перекрытия. На железе не проверялось.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:02:21 +07:00
VitaliandClaude Opus 5 2deb1b979f Задокументировать два принятых ограничения
Отсутствие ретраев webhook — сознательное решение: автономная работа
без отправки событий это штатный режим.

Пауза мониторинга до 2 минут при старте без сохранённой сети
(блокирующий портал WiFiManager в setup()) — принята как есть,
с указанием способа лечения, если понадобится.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:59:57 +07:00
VitaliandClaude Opus 5 e4ef065c9b Ограничить блокировку loop() при отправке webhook бюджетом 3 с
BearSSL делает TLS-хендшейк синхронно, поэтому вместо асинхронности
блокировка ограничивается по времени.

Главный источник залипания — не таймауты HTTPClient, а DNS:
WiFiClientSecureCtx::connect(name, port) резолвит имя через
WiFi.hostByName() без таймаута и подвешивает loop() на ~10 с.
Теперь имя разрешается заранее с лимитом 800 мс, результат попадает
в кэш lwIP, и внутренний резолв возвращается мгновенно. Соединение
по-прежнему идёт по имени, поэтому SNI и заголовок Host сохраняются.

Остаток бюджета уходит в http.setTimeout(): он ограничивает и
connect+TLS (через _client->setTimeout() до connect), и чтение
ответа (собственный цикл HTTPClient по _tcpTimeout).

Худший случай: ~3.5 с вместо прежних 10-15 с. Выходы аварии не
затронуты — digitalWrite() и раньше выполнялся до отправки.

Проверено: xtensa-lx106-elf-g++ -fsyntax-only -Wall -Wextra против
ядра 3.1.2 — в скетче замечаний нет; разбор URL прогнан на 15
граничных случаях.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:40:42 +07:00
VitaliandClaude Opus 5 1cdcaa9e99 Initial commit: контроллер насосов v8.2 + документация
Прошивка Wemos D1 Mini для мониторинга трёх насосов: OLED,
веб-панель, webhook-уведомления, сброс Wi-Fi кнопкой.

Адрес webhook задаётся через веб-панель и хранится в EEPROM;
в исходнике не хранится, так как содержит секретный токен.

Добавлены README.md (техдокументация) и MANUAL.md (руководство).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:51:22 +07:00
oskarvitaliiandClaude Opus 4.8 d1f96007de fix(display): erase full icon height in boot carousel
The sun's lowest ray reached y+H, one row below the H-tall erase box,
leaving a stray dot/trail. Erase H+4 so nothing is left behind.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 13:55:53 +07:00
oskarvitaliiandClaude Opus 4.8 a0f96fc52d feat(display): boot icon carousel
On power-up, after the title splash the screen clears and each weather
icon slides in from the right to centre with its colour-coded label, then
slides out to the left — Fine, Fair, Changeable, Rain, Storm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 12:48:28 +07:00
oskarvitaliiandClaude Opus 4.8 98e8170b8b feat(web): RU/EN language toggle (Russian default)
Client-side i18n: static labels via data-i18n, dial zone words, and the
26 Zambretti phrases + categories + trend words translated in the browser.
Choice persists in localStorage. Device firmware unchanged (API stays
English; TFT stays Latin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 11:15:26 +07:00
oskarvitaliiandClaude Opus 4.8 e9ec610f1c feat(web): scrollable Forecast log with fixed height
Cap the log panel at ~216px with a thin themed scrollbar so a long
forecast history does not stretch the page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 10:43:02 +07:00
oskarvitaliiandClaude Opus 4.8 1e923249f6 docs: add web UI screenshot to project README
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 12:20:36 +07:00
oskarvitaliiandClaude Opus 4.8 11f57a244d chore: make repo an Arduino collection with WeatherPredictor project
Flatten so the repo root is the Arduino sketchbook; the project lives in
WeatherPredictor/. Add a collection index README at the root and move the
detailed project README into WeatherPredictor/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 11:58:33 +07:00
oskarvitaliiandClaude Opus 4.8 fc72f9b0bd docs: add project README
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 11:52:33 +07:00
oskarvitaliiandClaude Opus 4.8 482a788f10 chore: nest project under Arduino/WeatherPredictor
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 11:41:01 +07:00
oskarvitaliiandClaude Opus 4.8 2e3af80188 feat(display): mini forecast icon + Wi-Fi IP, BGR colour fix
Rework the 160x80 status screen: large predicted-weather icon in the
right window (scaled to fill), Wi-Fi/IP line at the bottom (or 'offline'),
colour-coded forecast category, and the trend arrow shown only when
rising/falling. Colours are built R/B-swapped for this BGR ST7735S panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 23:05:13 +07:00
oskarvitaliiandClaude Opus 4.8 f1fe0b728f feat: forecast change log
Record each forecast change (Zambretti letter transition) with a
timestamp into a 24-entry ring buffer, persisted to LittleFS and
restored on boot. New /api/forecasts endpoint and a 'Forecast log'
panel in the web UI (newest first, category colour, timestamp).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 22:40:28 +07:00
oskarvitaliiandClaude Opus 4.8 f4a9a04207 feat(web): city presets for station settings
Add a City preset dropdown (Astana, Karaganda, Almaty, Bishkek,
Tashkent, Yekaterinburg, Omsk, Novosibirsk, Krasnoyarsk, Moscow,
Saint Petersburg) that fills altitude, coordinates and time zone from
average values. Manual entry and Custom remain; the matching preset is
auto-selected on load when coordinates match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 22:21:32 +07:00
oskarvitaliiandClaude Opus 4.8 8dc469be3d feat(web): UTC-offset time zone picker and labelled barograph axes
Time zone is now a UTC+/-HH dropdown (e.g. UTC+7) instead of raw
minutes. Barograph gains dual value axes (pressure left in hPa,
temperature right in C), start/end time labels and gridlines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 22:10:02 +07:00
oskarvitaliiandClaude Opus 4.8 26a5071e86 feat(web): redesign UI as a barometer instrument
Dark dusk-indigo panel with brass/enamel accents, serif almanac
headings + monospace instrument readouts. Signature element: an
antique barometer dial with a live needle and a ghost 'set hand' at
the pressure 3h ago -- the trend made physical. Barograph, stat tiles
and settings kept quiet. Fully self-contained (no external fonts/CDNs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:42:34 +07:00
oskarvitaliiandClaude Opus 4.8 74121a2ef2 fix: robust 3h trend across non-monotonic epochs (NTP jumps)
Scan all samples for the newest one >=3h old instead of assuming
strictly increasing timestamps, so an NTP time correction no longer
breaks trend detection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:27:10 +07:00
oskarvitaliiandClaude Opus 4.8 e29faf641a feat: self-contained web UI with live view, SVG chart, settings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:21:59 +07:00
oskarvitaliiandClaude Opus 4.8 396688cd98 feat: HTTP server with REST API for current/history/settings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:15:16 +07:00
oskarvitaliiandClaude Opus 4.8 ea0256a5b9 feat: NTP time sync writing to DS3231 (by IP, DNS-independent)
This LAN's router does not resolve external hostnames, so NTP uses
hard-coded Cloudflare/Google anycast IPs instead of names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:05:29 +07:00
oskarvitaliiandClaude Opus 4.8 cb3a06382e feat: Wi-Fi provisioning via WiFiManager captive portal
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:41:30 +07:00
oskarvitaliiandClaude Opus 4.8 77d0a35d69 feat: persist pressure history to LittleFS across reboots
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:31:53 +07:00
oskarvitaliiandClaude Opus 4.8 0a8dbe198d feat: integrate scheduler and full status display (landscape 160x80)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:18:36 +07:00
oskarvitaliiandClaude Opus 4.8 4e53e7388f feat: persistent settings in LittleFS JSON
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:08:03 +07:00
oskarvitaliiandClaude Opus 4.8 5c96cfc1f3 feat: in-RAM pressure history ring buffer with 3h trend
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:02:40 +07:00
oskarvitaliiandClaude Opus 4.8 5819739fcb feat: Zambretti forecast with trend classification
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:59:17 +07:00
oskarvitaliiandClaude Opus 4.8 2d52fcd851 feat: DS3231 RTC read/set with lost-power detection
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:55:47 +07:00
oskarvitaliiandClaude Opus 4.8 d042a94378 feat: BMP180 read and sea-level pressure conversion
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:43:03 +07:00
oskarvitaliiandClaude Opus 4.8 906adaddfe feat: TFT display init and splash screen
Landscape 160x80 (rotation 3, no invert) per this panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:39:13 +07:00
oskarvitaliiandClaude Opus 4.8 074bc99875 feat: sketch scaffold with I2C bus bring-up and scanner
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:30:34 +07:00
oskarvitaliiandClaude Opus 4.8 ffb2ac3756 docs: add Weather Predictor implementation plan (13 tasks)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 19:19:23 +07:00
oskarvitaliiandClaude Opus 4.8 ea90ef364f docs: add Weather Predictor design spec
Autonomous barometric weather station on Wemos D1 mini with BMP180,
DS3231 RTC and 0.96" ST7735 TFT. Local Zambretti forecast, web UI,
LittleFS storage, WiFiManager + NTP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:28:17 +07:00