123 lines
9.0 KiB
Markdown
123 lines
9.0 KiB
Markdown
# Энергомониторинг v2: LoRa + LAN, сервер учёта, интерфейс (Егорин / ORBIT)
|
||
|
||
## 1. Архитектура
|
||
|
||
```
|
||
┌─ LoRa-узлы (869 МГц) ──→ Шлюз gw1 (ESP32 + RA-01H + W5500, RJ45) ─┐
|
||
│ Ethernet
|
||
┌─ LAN-узлы (WT32-ETH01, RJ45) ─────────────────────────────────────┤
|
||
▼
|
||
Mosquitto (Proxmox srv001, :1883)
|
||
│
|
||
┌───────────────────────────────┼──────────────────┐
|
||
▼ ▼ ▼
|
||
provisioner.js Home Assistant n8n
|
||
(учёт устройств, API :8090, (MQTT Discovery — (алерты в
|
||
Postgres, HA Discovery) сущности сами) @Svetdo_bot)
|
||
▲
|
||
│ REST
|
||
Веб-интерфейс (ui-prototype.html → далее React)
|
||
```
|
||
|
||
Правило выбора транспорта узла: **есть розетка RJ45 в щите → LAN-узел** (WT32-ETH01,
|
||
надёжнее, чаще телеметрия, LWT-статус). **Кабеля нет → LoRa-узел** через шлюз.
|
||
Протокол данных у обоих одинаковый.
|
||
|
||
## 2. Железо (дополнение к v1)
|
||
|
||
| Позиция | Модель | Цена | Прим. |
|
||
|---|---|---|---|
|
||
| LAN-узел | **WT32-ETH01** (ESP32 + LAN8720, RJ45) | 700–900 ₽ | вместо DevKit+RA-01H |
|
||
| Шлюз v2 | ESP32 DevKit + RA-01H + **W5500 mini** | +250 ₽ к v1 | Ethernet вместо WiFi |
|
||
| PoE-вариант | Olimex **ESP32-POE** | ~2500 ₽ | питание по одному кабелю, для мачт/удалённых щитов |
|
||
|
||
Распиновка WT32-ETH01: PZEM на IO5/IO17 (UART2); входы реле IO32/IO33
|
||
(внутренний pullup) и IO35/IO36 (только вход — внешний pullup 10к на 3.3V);
|
||
выходы реле IO2/IO4/IO14/IO15. Шлюз: LoRa и W5500 на общей шине VSPI
|
||
(SCK18/MISO19/MOSI23), CS: LoRa=5, W5500=4.
|
||
|
||
## 3. Единое пространство топиков (v2)
|
||
|
||
| Топик | Направление | Содержимое |
|
||
|---|---|---|
|
||
| `nodes/<id>/info` | узел → сервер, **retained** | паспорт: `{"id","fw","hw":"lan\|lora","caps":{"pzem":true,"relays":4,"ctl":true},"ip","mac","gw"}` |
|
||
| `nodes/<id>/data` | узел → сервер | телеметрия: v, a, w, kwh, pf, hz, r[], seq (+rssi/snr/gw для LoRa) |
|
||
| `nodes/<id>/status` | LAN-узел → сервер | `online`/`offline` (LWT). LoRa-узлам статус ставит сервер по таймауту last_seen |
|
||
| `nodes/<id>/cmd` | сервер → узел | `{"cmd":"relay","n":0,"s":1}` · `{"cmd":"poll"}` · `{"cmd":"info"}` |
|
||
| `gateways/<id>/status` | шлюз | online/offline (LWT) |
|
||
|
||
LAN-узлы публикуют напрямую; LoRa-узлы шлют JSON с полем `"t":"info"|"d"`,
|
||
шлюз раскладывает по тем же топикам и добавляет rssi/snr/gw.
|
||
|
||
## 4. Механизм добавления устройств на сервер
|
||
|
||
Принцип: **узел регистрируется сам, человек только подтверждает.**
|
||
Прошивка одинаковая для всех узлов, отличается только `NODE_ID` — на объекте
|
||
монтажнику ничего настраивать не нужно.
|
||
|
||
1. **Выход в эфир.** При включении узел публикует `nodes/<id>/info` (retained).
|
||
LoRa-узел делает то же через шлюз. Повтор раз в 10 минут.
|
||
2. **Регистрация.** `provisioner.js` видит неизвестный `node_id` → создаёт запись
|
||
в `devices` со `status='pending'`. Паспорт (транспорт, IP/MAC или шлюз+RSSI,
|
||
прошивка, число реле) сохраняется автоматически.
|
||
3. **Интерфейс.** На экране «Устройства» появляется янтарная полоса
|
||
«Обнаружены новые устройства» со списком pending-узлов.
|
||
4. **Мастер добавления** (3 шага):
|
||
- *Паспорт* — проверка, что это ожидаемый узел (ID, транспорт, RSSI/IP, реле);
|
||
- *Параметры* — название, проект (Егорин/ORBIT), объект, имена реле;
|
||
- *Подтверждение* — `POST /api/devices/<id>/approve`.
|
||
5. **Автопубликация в HA.** При approve сервис публикует retained-конфиги
|
||
MQTT Discovery (`homeassistant/sensor|switch/.../config`) — датчики V/A/W/кВт·ч
|
||
и выключатели реле появляются в Home Assistant без правки yaml.
|
||
6. **Жизненный цикл.** `pending → active → disabled`. Disabled-узел данные пишет,
|
||
но скрыт с борда и не публикуется в HA. Повторное включение — снова approve.
|
||
|
||
Замена узла в поле: новый узел с тем же `NODE_ID` подхватывает старую карточку
|
||
(info обновит fw/mac), история сохраняется.
|
||
|
||
## 5. REST API (provisioner.js, :8090)
|
||
|
||
| Метод | Путь | Назначение |
|
||
|---|---|---|
|
||
| GET | `/api/devices?status=pending\|active&project=egorin\|orbit` | список + последняя телеметрия (view `v_devices_board`) |
|
||
| POST | `/api/devices/:id/approve` | `{name, project, object, relay_names[]}` → active + HA Discovery |
|
||
| POST | `/api/devices/:id/disable` | скрыть/отклонить |
|
||
| POST | `/api/devices/:id/cmd` | команда узлу, пишется в журнал `commands` |
|
||
| GET | `/api/devices/:id/history?hours=24` | ряды для графиков |
|
||
| GET | `/api/devices/:id/relay-events` | журнал переключений реле |
|
||
|
||
Запуск: `npm i mqtt pg express && node provisioner.js`
|
||
(ENV: `MQTT_URL`, `PG_URL`, `PORT`). Схема БД — `schema.sql` (Postgres).
|
||
|
||
## 6. Структура интерфейса (ORBIT design system)
|
||
|
||
Стиль: фон #070a10, акцент #4ADE80, Unbounded + Onest + JetBrains Mono,
|
||
glassmorphism-карточки. Desktop ≥1024: левый рейл 80px; mobile: нижний таб-бар
|
||
(паттерн ORBIT GPS). Рабочий прототип — `ui-prototype.html`.
|
||
|
||
```
|
||
├─ Обзор сводка по проектам: Σ кВт·ч сегодня/месяц, узлы в сети,
|
||
│ последние события реле, состояние шлюзов
|
||
├─ Устройства ★ основной экран (реализован в прототипе):
|
||
│ ├─ фильтр-чипы Все / Егорин / ORBIT
|
||
│ ├─ полоса «Обнаружены новые устройства» (pending) → мастер добавления
|
||
│ ├─ сетка карточек: статус-точка с пульсацией, бейдж LAN/LoRa+RSSI,
|
||
│ │ метрики В·А·Вт·кВт·ч (mono), тумблеры реле с именами, last seen
|
||
│ └─ карточка узла (drill-down, след. итерация): графики W/kWh за 24ч/30д,
|
||
│ журнал реле, паспорт, кнопки poll / перезапрос info / disable
|
||
├─ Шлюзы gw1..N: online, IP, число узлов, средний RSSI по узлам
|
||
├─ Журнал relay_events + commands: кто переключил, что, когда, источник
|
||
└─ Настройки MQTT-брокер, таймаут offline, частота/SF сети, ретенция БД
|
||
```
|
||
|
||
## 7. Порядок внедрения
|
||
|
||
1. Postgres: применить `schema.sql` (LXC на srv001).
|
||
2. Запустить `provisioner.js` (Docker/LXC, systemd).
|
||
3. Прошить шлюз `gateway_lora_eth.ino`, воткнуть в свитч щитовой.
|
||
4. Прошить узлы: LAN — `node_lan_energy.ino`, LoRa — `node_lora_energy_v2.ino`
|
||
(уникальные NODE_ID: eg01…, orb01…, eg-lan1…).
|
||
5. Узлы появятся в pending → добавить через мастер → проверить сущности в HA.
|
||
6. n8n: подписка на `nodes/+/data`, алерты в @Svetdo_bot
|
||
(узел offline >5 мин, ток выше порога, внеплановое отключение реле).
|