Files
ems/docs/04-modules/modbus-command-journal.md

4.2 KiB
Raw Blame History

Modbus command journal

Účel

Každý zápis na Modbus TCP (Deye a později další aktiva) se ukládá do tabulky ems.modbus_command jako samostatný řádek: cílový registr, hodnota, endpoint, vazba na site_id a volitelně na planning_run_id. Po zápisu má řádek stav written; samostatný verifikační job (každé 2 minuty) nebo ruční GET /api/v1/sites/{site_id}/control/verify přečte registr zpět a nastaví value_verified a stav verified nebo mismatch. Výjimka: souvislý blok Deye 6264 (systémový čas) se ověřuje tolerančně podle dekódovaného data/času (kvůli tikajícím sekundám na invertoru); viz modbus-registers.md.

Schéma ems.modbus_command

Sloupec Význam
asset_type / asset_id / asset_code Typ aktiva (inverter, …), FK logicky na příslušnou tabulku, čitelný kód
device_* Host, port, Modbus unit ID
register Číslo registru (decimal); v logu též hex
register_name Např. charge_limit, export_limit
value_to_write / value_written / value_verified Požadavek, potvrzený zápis, ověření čtením
status pending, written, verified, failed, mismatch, retrying
planning_run_id Volitelná vazba na aktivní plán
deye_physical_mode U zápisů z write_inverter_setpoints: PASSIVE / SELL / CHARGE (stejná hodnota na všech řádcích daného běhu exportu); jinak NULL
attempt_count Počet pokusů o zápis (pro limity retry)

Indexy: podle (site_id, status, created_at) a částečný index pro pending / retrying.

Verifikace a bezpečnost

  1. Po mismatch se odešle Discord alert (notification_service.send_discord / notify_modbus_mismatch), pokud je nastaven DISCORD_WEBHOOK_URL.
  2. Retry zápisu max. 3× (počítáno přes attempt_count po zápisech).
  3. Po třech neúspěšných cyklech: přepnutí lokality na SELF_SUSTAIN přes ems.fn_set_mode (activated_by = system:mismatch, poznámka = důvod) a kritický Discord alert (notify_self_sustain_activated).

Implementace: services/control_exporter.pyverify_modbus_commands, _switch_to_self_sustain.

Střídač (Deye)

write_inverter_setpoints přidá do journalu podle potřeby 6264 (čas — po čtení z invertoru jen při driftu / 24h intervalu; viz modbus-registers.md) a time pointy 148177 (bloky 36 typicky jednou denně; viz modbus-registers.md), dále 108, 109, 141, 142, 178, 143. Každý řádek daného exportního běhu má deye_physical_mode (PASSIVE / SELL / CHARGE). Reg 191 EMS nezapisuje (SolarmanApp). Převod výkonu: battery_watts_to_amps v modbus-registers.md.

Dávky: execute_modbus_commands slučuje souvislé adresy do jednoho write_registers (FC 0x10). verify_modbus_commands čte zpět po souvislých blocích (read_holding_registers, FC 0x03). Detail režimů: modbus-registers.md.

APScheduler

Job Frekvence Popis
verify_modbus každé 2 min Pro každou aktivní site vybere written příkazy s written_at v posledních 10 min a zavolá verify_modbus_commands.

Ruční API

GET /api/v1/sites/{site_id}/control/verify?minutes=10

Vrátí počty checked / verified / mismatch a seznam dotčených příkazů s aktuálním stavem po verifikaci.

ems.cutoff_switch_log

Tabulka pro budoucí logování cut-off přepínačů (mikroinvertory / GEN při záporné prodejní ceně). Záznam při změně stavu: asset_code, new_state, previous_state, reason, sell_price_czk, triggered_by. Zatím jen schéma; logika napojení v control_exporter je v TODO.

Konfigurace

  • .env: DISCORD_WEBHOOK_URL — prázdné = notifikace vypnuté (jen log).

Související soubory

  • Migrace: db/migration/V023__modbus_command_journal.sql, V025__deye_physical_mode.sql, V030__deye_clock_sync_at.sql
  • Backend: backend/services/control_exporter.py, backend/services/modbus_client.py, backend/services/notification_service.py, backend/app/main.py
  • Registry Deye: docs/04-modules/modbus-registers.md