# Provozní režimy EMS ## Přehled | Mode | Solver constraints | Deye fyzický režim | Baterie | |------|-------------------|-------------------|---------| | AUTO | žádné | PASSIVE/SELL/CHARGE dle plánu | dle plánu | | SELF_SUSTAIN | no_export, min_import | vždy PASSIVE | plné limity | | CHARGE_CHEAP | no_export, no_discharge | CHARGE | nabíjení max | | PRESERVE | no_charge, no_discharge | PASSIVE | lock (0/0) | | MANUAL | solver neběží | EMS nezapisuje | — | Implementace: omezení LP v `planning_engine.solve_dispatch()` podle `mode_code` z `ems.site_operating_mode`; zápis Deye v `control_exporter.write_inverter_setpoints()` (včetně `lock_battery` u PRESERVE). ## Fyzické režimy Deye (výstup control_exporteru) Detekce z `battery_w` a `grid_setpoint_w` (`get_deye_mode`): - **PASSIVE:** `grid_setpoint_w >= -200` → reg **142** = `deye_zero_export_mode`, reg **178** = 48; **108** = max jen při plánovaném nabíjení (`battery_w` > 0), jinak typicky **108 = 0** a **109** = max — **výjimka SELF_SUSTAIN:** příznak `self_sustain_local_use` → **108 i 109 = max** (viz `control_exporter.py`). **0/0** jen při `lock_battery` (PRESERVE). - **SELL:** `grid_setpoint_w < -200` → reg142=0, reg178=32, 108/109=max - **CHARGE:** `grid_setpoint_w > 200` **a** `battery_w > 500` → reg142=1, reg178=48 `battery_w = None` a `self_sustain_local_use=True` (**SELF_SUSTAIN**) ⇒ pro `get_deye_mode` se bere jako 0 ⇒ při `grid_setpoint_w = 0` je **PASSIVE**; v `write_inverter_setpoints` se ale zapíše **108 = max** a **109 = max**, reg **142** = zero export dle DB, TOU SOC = **`min_soc_percent`** (ne ekonomická větev 100 % z ceny). ## EMS politiky (nejsou fyzické stavy Deye) - **PV_SELL_ONLY:** AUTO + constraint solveru `max_discharge_from_pv` - **BLOCK_EXPORT:** AUTO + záporná sell_price → `ge[t]=0` - **NEGATIVE_HARVEST:** AUTO + záporná buy_price → max charge/load - **PROTECT:** SELF_SUSTAIN s konzervativními limity Tyto politiky jsou parametrizace AUTO/SELF_SUSTAIN, ne samostatné fyzické stavy. --- ## Loxone a UI (shrnutí) EMS a Loxone sdílí pojmenované provozní režimy; Loxone dostává číslo režimu přes Virtual Input a může fungovat autonomně (watchdog při výpadku EMS). ``` POST /api/v1/sites/{site_id}/mode { "mode": "SELF_SUSTAIN", "valid_until": null, "notes": "…" } ``` Backend: `ems.fn_set_mode` přes `run_fn_set_mode_with_discord` (při skutečné změně `mode_code` → Discord, pokud je `DISCORD_WEBHOOK_URL`) + HTTP na Loxone `/dev/sps/io/EMS_Mode/{loxone_mode_value}`. Dočasné přepisy s `valid_until` ruší `ems.fn_expire_modes()`, která vrací řádky `(site_id, site_code, old_mode, new_mode)` pro každé přepnutí — scheduler je použije pro stejné Discord upozornění. **Klíčový princip:** Loxone watchdog nečte DB – sleduje pulzy `EMS_Heartbeat`. Detail: `docs/loxone-integration.md`. Detail Modbus / Discord: `docs/04-modules/modbus-command-journal.md`. ### Tabulka režimů (Loxone / zátěže) | Kód | Loxone int | EV | TČ | Poznámka | |-----|------------|----|----|----------| | `AUTO` | 1 | dle plánu | dle plánu | setpointy z plánu | | `SELF_SUSTAIN` | 2 | stop | stop | fallback / výpadek EMS | | `CHARGE_CHEAP` | 3 | stop | stop | max nabíjení ze sítě | | `PRESERVE` | 4 | stop | stop | baterie uzamčena (Modbus 0/0) | | `MANUAL` | 0 | stop | stop | servis, EMS neexportuje | ### Otevřené body - [ ] Doplnit alerty při `ems_heartbeat_status = 'stale'` (Discord při změně provozního režimu z backendu je popsán v `modbus-command-journal.md`)