feat(ui): переработать веб-панель и макет OLED

Панель как световое табло, а не дашборд: главный ответ занимает верх
страницы и читается с расстояния. Прежде самым крупным элементом были
часы браузера - единственное, что не несло информации о приборе, - а
ответ "есть подача или нет" был набран 11 кеглем в панели размером с
кнопку. Норма и авария выглядели почти одинаково.

Исправлены три содержательные ошибки:

- лампа выхода "Авария" горела ЗЕЛЁНЫМ при срабатывании: стиль
  "включено" был общим для всех ламп, и сработавшая сигнализация
  подсвечивалась цветом "всё хорошо";
- страница делала location.reload() при любом изменении состояния,
  стирая недописанный адрес в форме вместе с прокруткой и фокусом;
- CSS подключал шрифты с Google Fonts, тогда как сеть на объекте не
  разрешает внешние имена - нарисованный макет там не появлялся никогда.

Страница стала статической и уехала во флеш (PAGE_HTML PROGMEM, ~8 КБ,
отдаётся через send_P). Раньше HTML собирался строкой в куче на каждый
запрос: ~14 КБ при ~40 КБ свободной кучи. Состояние подставляет JS,
забирая /status и новый /config. В /status добавлено поле rdy.

/config отдаёт только имя хоста webhook: полный URL содержит секретный
токен, и выводить его на экран, видимый всем в помещении, незачем.

Цвета по конвенции сигнальных ламп: резерв теперь ЖЁЛТЫЙ, а не красный -
работающий резерв это предупреждение, система ещё справляется. Красный
оставлен для остановки основных. Убраны декоративные коды SYS_OK / 0xFF,
не кодировавшие ничего, и тройное дублирование состояния резерва.
Настройки свёрнуты в details.

OLED: верхняя строка отдана статусу кеглем 2 - прежде её постоянно
занимал заголовок "PUMP CONTROLLER v8", который никогда не менялся.
Три строки датчиков сжаты в одну, освободившееся место отдано состоянию
обоих реле. Текст остаётся латиницей: встроенный шрифт Adafruit GFX
кириллицы не содержит.

Проверено: сборка -Wall -Wextra без предупреждений; все три состояния
панели просмотрены в браузере на 375 и 800 px. На железе не проверялось.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 00:43:34 +07:00
co-authored by Claude Opus 5
parent 42cbb82492
commit cb151d2e30
3 changed files with 384 additions and 332 deletions
+76 -51
View File
@@ -106,27 +106,33 @@ OLED 128×64 (I2C): `SDA → D1`, `SCL → D2`, `VCC → 3V3`, `GND → GND`.
## 4. Экран
```
PUMP CONTROLLER v8
SUPPLY OK
────────────────────────
PUMP 1 : RUNNING
PUMP 2 : STOPPED
BACKUP : STANDBY
P1:RUN P2:OFF BK:OFF
ALARM:OFF BACKUP:OFF
────────────────────────
192.168.1.42
STATUS: OK
192.168.1.128
```
**Верхняя строка — главный ответ**, набрана крупно и читается от двери:
| Надпись | Значение |
|---|---|
| `PUMP 1/2 : RUNNING` | Насос работает |
| `PUMP 1/2 : STOPPED` | Насос остановлен |
| `BACKUP : ACTIVE` | Резервный насос запущен |
| `BACKUP : STANDBY` | Резерв в ожидании |
| `WiFi: NO CONNECTION` | Нет связи с сетью |
| `INIT...` | Идёт запуск (первые ~4 секунды) |
| `STATUS: OK` | Норма |
| `WARN: BACKUP RUNNING` | Работает резерв — требуется внимание |
| `!! ALARM: NO PUMPS !!` (мигает) | **Авария: подача воды прекращена** |
| `SUPPLY OK` | Норма, подача идёт |
| `BACKUP RUN` | Работает резерв, основные в порядке — обратите внимание |
| `NO SUPPLY` (мигает) | **Авария: оба основных стоят, подачи нет** |
| `BACKUP ON` (мигает) | **Авария: основные стоят, подачу держит резерв** |
| `STARTING` | Идёт запуск, первые ~4 секунды |
Вторая строка — датчики: `RUN` насос работает, `OFF` стоит. `P1` и `P2` —
основные, `BK` — резерв.
Третья строка — что подано на выходы: `ON` реле замкнуто, `OFF` разомкнуто.
Удобно при пусконаладке: видно, что прибор действительно выдал сигнал.
Нижняя строка — адрес в сети или `no network`, если связи нет.
Надписи латиницей: встроенный шрифт дисплея кириллицы не содержит.
---
@@ -134,57 +140,76 @@ STATUS: OK
Откройте `http://<IP-адрес прибора>` в любом браузере в той же сети.
На странице:
Панель устроена как световое табло: **сверху крупно главный ответ**, ниже —
лампы датчиков и выходов, в самом низу свёрнутые настройки.
* три карточки насосов с индикаторами;
* панель состояния системы (`SYS_OK` или `CRITICAL`);
* **состояние обоих реле** — «Включено» / «Выключено»;
* кнопка **Сбросить Wi-Fi**;
* блок **Настройки** — адрес уведомлений, имя устройства и две выдержки.
### 5.1 Главная плашка
Страница обновляется автоматически при изменении состояния насосов или реле.
| Плашка | Цвет | Что значит |
|---|---|---|
| **Подача есть** | зелёный | Норма, работает хотя бы один основной насос |
| **Работает резерв** | жёлтый | Резерв в работе, основные в порядке — обратите внимание |
| **Насосы стоят** | красный, пульсирует | **Авария: оба основных остановлены** |
| **Запуск** | серый | Первые ~4 секунды после включения |
### 5.1 Состояние реле
Под заголовком — уточнение: какой именно насос работает, или «подачу держит
резерв», если основные стоят, а резерв качает.
Два индикатора показывают, что прибор реально подал на выход:
Жёлтый у резерва выбран намеренно: работающий резерв — это предупреждение,
система ещё справляется. Красный оставлен для случая, когда основной подачи нет.
| Индикатор | Значение |
|---|---|
| Реле «Авария» — Включено | Выход `D3` активен, сигнал аварии выдан |
| Реле «Резерв» — Включено | Выход `D4` активен, резерв работает |
**Вкладка браузера тоже показывает состояние** — в её заголовке текущий статус,
а кружок-значок меняет цвет. Свёрнутую на телефоне вкладку видно, не открывая.
Полезно при пусконаладке: если реле показано «Включено», а нагрузка не
сработала — проблема в монтаже или в типе релейного модуля, а не в прошивке.
### 5.2 Лампы
### 5.2 Настройки
Три лампы датчиков: **Насос 1**, **Насос 2**, **Резерв** — «работает», «стоит»
или «ожидание».
Все настройки в одной форме. **Пустое поле означает «не менять»** — можно
поправить одну выдержку, не трогая остальное. Неверное значение так же
игнорируется, поэтому опечатка ничего не испортит.
Две лампы выходов: **Выход «Авария»** и **Выход «Резерв»** — «замкнут» или
«разомкнут». Это то, что прибор реально подал на реле.
Полезно при пусконаладке: если выход показан замкнутым, а нагрузка не сработала,
проблема в монтаже или в типе релейного модуля, а не в прошивке.
### 5.3 Настройки
Раскрываются по нажатию на строку **Настройки** — в обычной работе они свёрнуты
и не отвлекают.
**Пустое поле означает «не менять»** — можно поправить одну задержку, не трогая
остальное. Неверное значение так же игнорируется, поэтому опечатка ничего не
испортит.
| Поле | Что задаёт | Допустимо | По умолчанию |
|---|---|---|---|
| **Webhook URL** | адрес сервера уведомлений | до 220 символов | не задан |
| **Имя устройства** | поле `device` в уведомлении — по нему различают приборы на сервере | латиница, цифры, `_`, `-`; до 31 символа | `Wemos_D1_Pump` |
| **Выдержка аварии, с** | сколько оба основных насоса должны стоять до сигнала | 0…3600 | `5` |
| **Выдержка резерва, с** | сколько резерв должен работать до сигнала | 0…3600 | `0` (сразу) |
| **Адрес для уведомлений** | куда прибор шлёт сообщения | до 220 символов | не задан |
| **Имя прибора в уведомлениях** | по нему различают приборы на сервере | латиница, цифры, `_`, `-`; до 31 символа | `Wemos_D1_Pump` |
| **Задержка сигнала — аварии** | сколько оба основных должны стоять до сигнала | 0…3600 с | `5` |
| **Задержка сигнала — резерва** | сколько резерв должен работать до сигнала | 0…3600 с | `0` (сразу) |
Под полем адреса показано только **имя сервера**, а не весь адрес: он содержит
секретный ключ, и выводить его на экран, который видно всем в помещении, не
нужно. Чтобы сменить адрес — введите новый целиком.
Кнопка **Сменить сеть Wi-Fi** стирает сохранённую сеть и перезагружает прибор
(см. раздел 7).
Настройки сохраняются в файл во внутренней памяти прибора, переживают
отключение питания и сброс Wi-Fi.
отключение питания и смену сети Wi-Fi.
> Если панель показывает красное предупреждение «Файловая система недоступна»
> или настройки пропадают после перезагрузки — причина в настройке `Flash Size`
> Если панель показывает красное предупреждение «Память недоступна» или
> настройки пропадают после перезагрузки — причина в настройке `Flash Size`
> при прошивке. Она обязана совпадать с фактическим размером памяти платы:
> для этих приборов **`2MB (FS:64KB OTA:~992KB)`**. Вариант `4MB` на плате с
> 2 МБ приводит ровно к такому симптому.
> Русские буквы и пробелы в имени устройства **не сохранятся** — они будут
> Русские буквы и пробелы в имени прибора **не сохранятся** — они будут
> отброшены. Это не ошибка: ограничение защищает формат уведомления от поломки.
> Пишите, например, `Nasosnaya_1` или `Pump_Station_A`.
**На новом приборе адрес уведомлений не задан** — панель покажет
`не задан - уведомления отключены`, сообщения отправляться не будут, всё
остальное работает.
**На новом приборе адрес уведомлений не задан** — панель покажет «Не задан —
уведомления отключены», сообщения отправляться не будут, всё остальное работает.
---
@@ -219,7 +244,7 @@ STATUS: OK
`Pump_Control_Set`. Подключитесь к ней и введите новые данные (раздел 3).
**Если надо перевести прибор в другую сеть, а текущая работает** — нажмите
**Сбросить Wi-Fi** на панели мониторинга. Прибор перезагрузится и поднимет точку
**Сменить сеть Wi-Fi** в настройках панели. Прибор перезагрузится и поднимет точку
доступа.
**Если панель недоступна, а сеть работает** — выключите роутер и перезагрузите
@@ -238,15 +263,15 @@ STATUS: OK
| Событие | Задержка |
|---|---|
| Фиксация нового состояния датчика | 3 секунды (не настраивается) |
| Авария основных насосов (после фиксации) | **Выдержка аварии**, по умолчанию 5 с |
| Пуск резерва (после фиксации) | **Выдержка резерва**, по умолчанию 0 с |
| Авария основных насосов (после фиксации) | **Задержка сигнала аварии**, по умолчанию 5 с |
| Пуск резерва (после фиксации) | **Задержка сигнала резерва**, по умолчанию 0 с |
| Итого до сигнала аварии при значениях по умолчанию | **~8 секунд** |
| Итого до сигнала о резерве при значениях по умолчанию | ~3 секунды |
Обе выдержки настраиваются в панели (раздел 5.2) и действуют **одновременно на
Обе задержки настраиваются в панели (раздел 5.3) и действуют **одновременно на
реле и на уведомление** — отдельно задержать только уведомление нельзя.
Выдержка `0` означает «сразу после фиксации», то есть через те же 3 секунды
Задержка `0` означает «сразу после фиксации», то есть через те же 3 секунды
антидребезга.
---
@@ -266,7 +291,7 @@ STATUS: OK
| Реле сработали наоборот: включены в норме, отпускают при аварии | Стоит модуль с активным HIGH вместо active-LOW. Замените модуль либо потребуйте правку прошивки |
| Реле щёлкает при заливке прошивки | Нормально: схема автосброса USB дёргает `D3`. На работу не влияет |
| Имя устройства не сохраняется | В нём есть русские буквы, пробелы или знаки препинания — они отбрасываются. Допустимы только латиница, цифры, `_` и `-` |
| Выдержка не сохраняется | Значение вне диапазона 0…3600 или не целое число — поле игнорируется |
| Задержка не сохраняется | Значение вне диапазона 0…3600 или не целое число — поле игнорируется |
| Прибор не стартует после включения | На `D3` или `D4` висит нагрузка, тянущая пин к GND при старте — проверьте релейный модуль и его питание |
Подробный лог работы выводится в USB-порт: скорость **115200 бод**