Files
ems/docs/04-modules/operating-modes.md
Dusan Vojacek efc2cbfded
All checks were successful
CI and deploy / migration-check (push) Successful in 3s
CI and deploy / deploy (push) Successful in 25s
fix battery charge u self_sustain rezimu
2026-04-19 15:09:33 +02:00

66 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`)