9.8 KiB
Provozní režimy EMS
Keep it simple
- Žádné wattové prahy pro výběr SELL / CHARGE — mapování z MILP setpointů je čistě ze znamének
battery_setpoint_wagrid_setpoint_w(vizget_deye_modevexporter_monolith.py). - ZERO (PASSIVE) = zero export k CT/zátěži (142 =
deye_zero_export_mode), s plnými proudy 108/109 jen ve výchozím stavu; pro přetok FVE do sítě nebo odběr ze sítě bez vybíjení baterie se jeden z proudů vynuluje (_deye_zero_export_amps_for_passive). - SELL = plánovaný export i plánované vybíjení (oba záporné) → 142 = selling first, 178 = vypnutý grid peak shaving (32); po návratu do ZERO/CHARGE zase 178 = 48.
- Novou logiku vždy ověřit proti reálnému řádku plánu (audit /
planning_interval).
Přehled
| Mode | Solver constraints | Deye fyzický režim | Baterie |
|---|---|---|---|
| AUTO | žádné | PASSIVE/SELL/CHARGE dle plánu | dle plánu |
| SELF_SUSTAIN | min_import; export jen jako nouzový ventil (silně penalizovaný) | 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:
- EMS provozní režim (
AUTO,SELF_SUSTAIN, …): jediný zdroj v DBems.site_operating_mode.mode_code+ větev v_build_setpoints/export_setpoints(např.CHARGE_CHEAPpřepíše setpointy před zápisem — stále jedna funkce exportu). - Deye fyzický režim (
PASSIVE/CHARGE/SELL): jediný zdrojget_deye_mode(exporter_monolith.py); zápis vwrite_inverter_setpoints(). - Omezení LP v
planning_engine.solve_dispatch()podlemode_code; zápis Deye včetnělock_batteryu PRESERVE.
Odkud jsou battery_setpoint_w a grid_setpoint_w (AUTO)
Nejde o samostatný „tip“ z predikce FVE, který by exporter náhodně přetáhl do SELL nebo CHARGE.
- Zdroj dat: pro režim AUTO exporter načte aktivní řádek
ems.planning_intervalpro aktuální 15min slot (_fetch_plan_row_for_slot_offset→_build_setpointsvexporter_monolith.py). - Kdo je naplnil: sloupce pocházejí z výstupu
planning_engine.solve_dispatch()— MILP nad bilanční rovnicí za slot (základní značky v kódu:gi[t]≥ 0 import ze sítě,ge[t]≥ 0 export ze sítě,bc[t]/bd[t]nabíjení / vybíjení baterie). Uložené hodnoty odpovídajígrid_setpoint_w = round(gi[t] - ge[t])abattery_setpoint_w = round(bc[t] - bd[t])(viz sestaveníDispatchResulta zápis plánu). - Fyzika u elektroměru: v jednom slotu model pracuje s čistým tokem ze sítě jako rozdílem
giage; predikce PV a spotřeba vstupují do bilance a omezení řešiče, ne jako náhradní logika mapování na Deye. - Role
get_deye_mode: pouze přeloží už hotový plán na kombinaci registrů (PASSIVE / CHARGE / SELL). Očekávání provozu (např. kdy přesně má být výdej baterie do sítě vs. přetok FVE) má držet LP a výběr slotů (allow_charge,allow_discharge_export, …), ne dodatečné wattové heuristiky v exporteru.
Fyzické režimy Deye (výstup control exporteru)
Jediné místo pro klasifikaci Deye PASSIVE | CHARGE | SELL z MILP setpointů je get_deye_mode v exporter_monolith.py.
Značení: battery_w = battery_setpoint_w (kladné = nabíjení, záporné = vybíjení); grid_setpoint_w (kladné = import, záporné = export).
| Režim | Podmínka z plánu | 108 / 109 (zkráceně) | 142 | 178 |
|---|---|---|---|---|
| CHARGE | battery_w > 0 a grid_setpoint_w > 0 |
dle plánu nabíjení / 0 vybíjení | větev CHARGE | 48 |
| SELL | battery_w < 0 a grid_setpoint_w < 0 |
0 nabíjení / max vybíjení | 0 (selling first) | 32 (peak shaving off) |
| PASSIVE (ZERO) | vše ostatní | viz tabulka ZERO níže | deye_zero_export_mode |
48 |
ZERO: výchozí a dvě varianty proudu (reg. 108 / 109)
Všechny řádky předpokládají 142 = zero export (ne SELL).
| Situace | Podmínka (plán) | Reg. 108 (max charge A) | Reg. 109 (max discharge A) |
|---|---|---|---|
| Výchozí | ostatní případy PASSIVE | max | max |
| Přetok FVE do sítě | grid_setpoint_w < 0 a battery_w ≥ 0 |
0 | max |
| Držet baterii, brát ze sítě | grid_setpoint_w > 0 a battery_w ≤ 0 |
max | 0 |
Nabíjení ze sítě s vysokým cílovým SoC v TOU řeší větev CHARGE (grid charge v time pointech), ne tato tabulka.
ZERO a „zakázaný export FVE do sítě“ (jen řiditelná pole)
Reg. 145 (solar sell) na Deye je přepínač typu enabled / disabled pro přebytek FVE na straně měniče (počítá se vůči režimu 142 zero export a stavu 108 — viz modbus-registers.md, pass-through krok za krokem).
- Pouze to, co EMS umí přes Deye Modbus ovlivnit — typicky FVE pole řízené střídačem (
asset_pv_array.controllable = true, u referenční lokality home-01 např. string za Deye). - Pole mimo tento kanál (např. pv-b u home-01,
controllable = false, často samostatný ongrid GEN) reg. 145 neovládá; jejich výkon jde do plánovače jakopv_b_forecast_w, ale curtailment / solar sell logika Deye se jich netýká.
Implementace dnes: exporter vždy zapisuje 145 = 1 (solar sell enabled). Tvrdé vypnutí přebytku řiditelného FVE do sítě přes 145 = 0 z politik (no_export, BLOCK_EXPORT, …) je v plánu — viz docs/05-todo.md (sekce Deye řízení – rozšíření).
Implementace (BLOCK_EXPORT): při effective_sell_price < 0 (slot z plánu) EMS drží fyzicky stále PASSIVE, ale zapne zákaz exportu přebytků pro řiditelnou FVE:
- reg 145 = 0 (solar sell disabled) mimo SELL
- BA81: navíc přes reg 179 (bits0–1) aktivuje „MI export to Grid cutoff“ pro mikroinvertory na GEN portu (jen pokud je
asset_inverter.deye_gen_microinverter_cutoff_enabled = true). Týká se jen výroby, kterou Deye umí ovlivnit; pv-b / ongrid GEN u home-01 tímto neomezíš.
PV1/PV2 vs. GEN port (důležité pro BLOCK_EXPORT)
- PV1/PV2 (hlavní stringy na DC vstupu Deye): výkon je v režimu zero-export řiditelný (střídač umí výrobu stáhnout až k nule, pokud není odběr a baterie už nemůže nabíjet). Při BLOCK_EXPORT tedy dává smysl „zakázat export“ přes reg 145 = 0 – Deye zamezí přetokům z těchto stringů.\n+- GEN port (AC coupling / mikroinvertory / ongrid GEN): výkon nelze plynule omezovat. Pole vyrábí „co dá slunce“ a pokud ho nespotřebuje dům + EV/TČ + baterie, přebytek fyzicky teče do sítě.\n+ - U instalací typu BA81 je proto k dispozici jen tvrdý cut-off (reg 179 bits0–1).\n+ - U malé baterie (např. BA81 ~6 kW max charge a navíc při vysokém SoC ještě méně) může při plném osvitu často nastat přebytek i při BLOCK_EXPORT – a bez cut-off by šel do sítě.\n+ - Naopak při malém osvitu / velké spotřebě jsou „každé watty z GEN“ užitečné (jít do domu/baterie) a cut-off by zbytečně zahodil výrobu.\n+
Z toho plyne: cut-off GEN portu je smysluplné řídit podle očekávaného přebytku, ne jen podle „sell < 0“. Detail návrhu implementace je v
docs/04-modules/planning.md(sekce o GEN portu a export banu).
SELF_SUSTAIN: battery_w = None ⇒ v get_deye_mode jako 0 ⇒ PASSIVE; v write_inverter_setpoints při self_sustain_local_use=True → 108 i 109 = max (bez variant ZERO výše), reg. 142 dle DB, TOU SOC = min_soc_percent. PRESERVE: lock_battery → 108 = 0, 109 = 0.
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(hard constraint, pokud má lokalita k dispozici GEN port cut-off; jinak solver export jen penalizuje přes zápornou cenu) - 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 vmodbus-command-journal.md)