# Provozní režimy EMS - praktický přehled

Tenhle dokument je zkrácený provozní cheat sheet. Cíl je jednoduchý:

- rychle poznat, co EMS v daném slotu dělá
- umět to porovnat s `planning_interval`
- ověřit to na live registrech Deye a ve FE

## 1. Co je zdroj pravdy

- EMS provozní režim lokality: `ems.site_operating_mode.mode_code`
- aktivní plán: `ems.planning_interval`
- fyzická konfigurace invertoru: `asset_inverter` + `site_grid_connection`
- live stav Deye: registry 108, 109, 141, 142, 143, 145, 178, 340

Když něco nesedí, porovnávej vždy v tomto pořadí:

1. `planning_interval`
2. `control/registers` na FE
3. `modbus_command` journal

## 2. EMS režimy lokality

### AUTO

Normální provoz. EMS bere sloty z `planning_interval` a podle nich řídí Deye, EV, TČ a signály.

V AUTO se pak mohou objevit sloty s různým exportním záměrem:

- `PV_SURPLUS`
- `BATTERY_SELL`
- `NONE`

### SELF_SUSTAIN

Bezpečný provoz bez obchodní logiky.

- Deye fyzicky běží v PASSIVE
- baterie se nechává pro vlastní spotřebu
- export je jen nouzový ventil, pokud je potřeba kvůli feasibility

### CHARGE_CHEAP

- nabíjení ze sítě
- export se nepoužívá
- fyzicky CHARGE

### PRESERVE

- baterie je uzamčená
- žádné nabíjení ani vybíjení
- fyzicky PASSIVE

### MANUAL

- EMS setpointy nezapisuje
- vše je ruční řízení

## 3. Tvoje 5 provozních archetypů

### 1. Standardní režim s přetokem

Co tím myslíme:

- baterie se normálně nabíjí i vybíjí podle plánu
- přetok do sítě je povolený
- exportní limit je jen tvrdý site / inverter cap
- když je baterie plná, přebytek FVE jde do sítě

Jak to je v implementaci:

- `export_mode = PV_SURPLUS`
- `export_limit_w = hard cap`
- `solar_sell = 1`
- `deye_physical_mode = PASSIVE`
- v PASSIVE se pro exportní slot (bez plánovaného nabíjení z baterie) používají typicky **`108` i `109` na max** z invertoru; přebytek do sítě řeší **142/145** a firmware, ne umělé **108 = 0** (to dřív matlo měnič jako „baterie plná“)

Poznámka:

- exportní limit se už netipuje z forecastu
- neomezuješ tedy výkon do sítě podle předpovědi, jen podle hard capu

### 2. Standardní režim s vypnutým přetokem

Co tím myslíme:

- `solar_sell = false`
- přebytek FVE se nesmí posílat do sítě
- jakmile je baterie plná, FVE se utlumí

Jak to je v implementaci:

- tohle není samostatný fyzický Deye režim
- většinou jde o kombinaci:
  - `reg 143 = 0` nebo site `no_export`
  - případně `export_ban = true` a `reg 145 = 0`
- fyzicky to pořád bývá PASSIVE

Poznámka:

- tohle je důležité ověřovat na `reg 143` a `reg 145`, ne jen na `grid_setpoint_w`

### 3. Prodej přebytku do sítě bez nabíjení baterie

Co tím myslíme:

- baterie není cílem
- nechci ji nabíjet
- chci prodávat celou výrobu do sítě

Jak to je v implementaci:

- `export_mode = PV_SURPLUS`
- `solar_sell = 1`
- `export_limit_w = hard cap`

Poznámka k implementaci:

- tohle je v kódu garantované až ve chvíli, kdy planner dá `battery_setpoint_w = 0`
- pokud je `battery_setpoint_w > 0`, tak současná implementace už dovoluje i nabíjení baterie, i když exportní záměr zůstává `PV_SURPLUS`
- jinými slovy: čisté „prodávám výrobu, ale baterii nechci nabíjet“ ještě není samostatný fyzický Deye režim, je to kombinace plánovacího setpointu a exportního záměru

Použití:

- vhodné, když je výkupní cena vysoká
- baterii chceš šetřit na jiný slot

### 4. Šetření baterie

Co tím myslíme:

- když je kupní cena nízká
- nechci brát energii z baterie
- raději budu kupovat ze sítě

Jak to je v implementaci:

- `battery discharge A = 0`
- fyzicky PASSIVE
- baterie se nevybíjí, ale podle slotu se může pořád nabíjet nebo držet

Poznámka:

- tohle je jiné než SELL
- tady jen chráníš baterii, neprodáváš ji

### 5. Aktivní prodej do sítě z baterie

Co tím myslíme:

- `selling first`
- baterie prodává do sítě plným výkonem, co dovolí střídač / baterie / síť

Jak to je v implementaci:

- `export_mode = BATTERY_SELL`
- `deye_physical_mode = SELL`
- `reg 142 = 0`
- `reg 178 = 32`
- `reg 109` na max; **`reg 108` EMS ve SELL nemění** (selling first = **142**; u **PASSIVE** + přetoku FVE se **108** zapisuje **0**)

## 4. Další režimy, které v praxi existují

### CHARGE_CHEAP

- nabíjení ze sítě
- fyzicky CHARGE

### SELF_SUSTAIN

- vlastní spotřeba
- fyzicky PASSIVE
- export jen jako nouzový ventil

### PRESERVE

- baterie uzamčená
- žádné řízení baterie

### MANUAL

- EMS nezasahuje

## 5. Registry, které má smysl kontrolovat

### 108

Max charge current.

### 109

Max discharge current.

### 142

Limit control:

- `0` = selling first
- `1` = zero export to load
- `2` = zero export to CT

### 143

Export cap.

- tvrdý site / inverter limit
- neforecastuje se

### 145

Solar sell:

- `1` = povoleno
- `0` = zakázáno

### 178

Bitové pole:

- bits 4-5 = peak shaving switch
- bits 0-1 = GEN export cut-off u BA81

### 340

Max solar power pro řízenou FVE A.

- není to exportní cap
- je to strop výroby pole A

## 6. Co kontrolovat na FE

### Planning page

Zkontroluj:

- `deye_physical_mode`
- `grid_setpoint_w`
- `export_limit_w`
- `export_mode`
- `deye_gen_cutoff_enabled`
- `effective_buy_price`
- `effective_sell_price`

### Control panel

Na živém panelu porovnej:

- reg 142
- reg 143
- reg 145
- reg 178

Reg 143 musí být vidět jako hard cap.

## 7. Rychlá kontrola nesrovnalostí

1. Najdi slot v `Planning`
2. Podívej se na:
   - `battery_setpoint_w`
   - `grid_setpoint_w`
   - `export_limit_w`
   - `export_mode`
   - `deye_physical_mode`
3. Otevři `ControlPanel`
4. Porovnej live registry:
   - 142
   - 143
   - 145
   - 178
5. Podívej se do `modbus_command`

## 8. Co je v implementaci důležité vědět

Tady jsou dva praktické detaily:

- `export_limit_w` se bere jako hard cap z lokality / invertoru
- export se už netipuje z forecastu

To znamená:

- při `PV_SURPLUS` se má pustit maximum, které dovoluje distribuce a HW
- při `BATTERY_SELL` se použije SELL a prodej z baterie
- při běžném importu / šetření baterie se exportní logika nemá „uhádnout“ z ceny nebo forecastu

## 9. Kde hledat v kódu

- plánování: `backend/services/planning_engine.py`
- mapování plánu na setpointy: `backend/services/control/setpoints.py`
- zápis Deye: `backend/services/control/inverter.py`
- live registry: `backend/app/routers/sites.py`
- FE plánování: `frontend/src/pages/Planning.tsx`
- FE live registry: `frontend/src/components/ControlPanel.tsx`

## 10. Planner v2

Pro přesné zadání nové verze planneru se řiď sekcí **Planner v2** v [`docs/04-modules/planning.md`](/home/dusan.vojacek@triglav.local/Documents/AI-projekty/ems-cursor/docs/04-modules/planning.md).

Krátké shrnutí:

- `reserve_soc_percent` = ranní cílová rezerva
- `min_soc_percent` = tvrdá TOU / fyzická podlaha
- PV A je řiditelná, PV B je neřiditelná
- při záporné prodejní ceně se zakazuje export
- v BA81 se cutoff mikroinvertoru řeší přímo v planneru
- pokud je zapnuté `PLANNING_ENGINE_COMPARE_ENABLED`, backend spočítá i druhou verzi nad stejným vstupem, uloží ji jako read-only `planning_run` se stavem `comparison`, napáruje ji na aktivní run přes `comparison_of_run_id` a FE ji ukáže v `/plan/compare`; fyzicky se aplikuje jen aktivní plán
