fix discharge battery
Some checks failed
CI and deploy / migration-check (push) Failing after 18s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-04-19 23:46:16 +02:00
parent e3776226a4
commit 7f3b0957cc
4 changed files with 19 additions and 24 deletions

View File

@@ -119,22 +119,22 @@ def apply_overrides(plan, overrides) -> Setpoints:
| **CHARGE** | `battery_w` > 500 **a** `grid_setpoint_w` > 200 (nabíjení ze sítě) |
| **PASSIVE** | vše ostatní |
**PASSIVE** (včetně FVE přetoku do sítě): reg. **108/109** škálované podle `battery_w` z plánu, reg. **145** = 1 (solar sell), reg. **142** = `deye_zero_export_mode`.
**PASSIVE** (AUTO, včetně FVE přetoku do sítě): reg. **108** i **109** na **maximum z DB** (plný proudový rozsah baterie); jemnější výkon drží **TOU časové body** z plánu. Reg. **145** = 1 (solar sell), reg. **142** = `deye_zero_export_mode`.
**SELF_SUSTAIN** (záložní režim po Modbus mismatch apod.) zůstává **PASSIVE** z hlediska `get_deye_mode`, ale `write_inverter_setpoints` nastaví **reg. 108 i 109 na maximum z DB** (`self_sustain_local_use=True` v `ControlSetpoints`), **reg. 142** na `asset_inverter.deye_zero_export_mode` (1 = zero export to load, 2 = zero export to CT) a **TOU SOC** na **`min_soc_percent`** (typicky 12 %), aby střídač maximalizoval využití baterie lokálně místo zákazu nabíjení při `battery_w=None`.
**SELF_SUSTAIN** (záložní režim po Modbus mismatch apod.) zůstává **PASSIVE** z hlediska `get_deye_mode`; **108/109** jsou stejně **max z DB** jako u AUTO PASSIVE. Rozdíl je **`self_sustain_local_use=True`**: **TOU SOC** se drží na **`min_soc_percent`** (typicky 12 %) a `battery_w=None`, aby střídač prioritizoval lokální buffer při zero-export, ne ekonomiku LP.
### Klíčové registry podle typu slotu
| Registr | Charge | Pass-through / PASSIVE | SELL (battery-led) | Self-consumption |
|---|---|---|---|---|
| **108** (charge A) | škálo dle `battery_w` | škálo dle `battery_w` (>0) / **0** | **0** | **0** |
| **109** (discharge A) | **0** | škálo dle `\|battery_w\|` (<0) / **0** | **max z DB** | škálo dle `\|battery_w\|` |
| **108** (charge A) | škálo dle `battery_w` | **max z DB** | **0** | **max z DB** |
| **109** (discharge A) | **0** | **max z DB** | **max z DB** | **max z DB** |
| **142** (limit control) | `deye_zero_export_mode` | `deye_zero_export_mode` | **0** (selling first) | `deye_zero_export_mode` |
| **143** (export cap) | max z DB | max z DB | `min(max_site, max(200, \|grid_setpoint_w\|))` | max z DB |
| **145** (solar sell) | 1 | 1 | 1 | 1 |
| **178** (peak shaving) | 48 | 48 | **32** | 48 |
Při provozním režimu **SELF_SUSTAIN** je v PASSIVE **108 = max** i **109 = max** (viz odstavec výše), nikoli hodnoty ve sloupci „Pass-through“.
Sloupce **Pass-through / PASSIVE** (AUTO) a **Self-consumption** (typicky SELF_SUSTAIN / záloha) mají u **108/109** stejně **max z DB**; liší se hlavně **TOU SOC** a `battery_w` (viz výše).
Hodnota `deye_zero_export_mode` (1 = zero export to load, 2 = zero export to CT) pochází z `asset_inverter.deye_zero_export_mode` a závisí na fyzické instalaci (přítomnost CT). Detail v [`modbus-registers.md`](modbus-registers.md).

View File

@@ -12,8 +12,8 @@ EMS zapisuje řídící hodnoty přes journal (`modbus_command`) a **`write_regi
| Reg | Název | Rozsah | Jednotka | Použití v EMS |
|-----|-------|--------|----------|---------------|
| 108 | Max charge current | 0 … **max dle modelu** (manuál Deye) | 1 A | EMS počítá proud v **SQL**: `COALESCE(deye_register_max_charge_a, FLOOR(LEAST(W)/51.2))` — sloupec stropu v **A** je volitelný (NULL = jen odvod z kW); při vyplnění např. 350 při W→351 A se použije 350. V Pythonu se navíc **clampuje horní strop 350 A** (`DEYE_LV_BATTERY_MAX_CHARGE_DISCHARGE_A`), aby firmware nevracel 350 při zápisu 351. |
| 109 | Max discharge current | 0 … **max dle modelu** (manuál Deye) | 1 A | Stejně: `COALESCE(deye_register_max_discharge_a, FLOOR(LEAST(W)/51.2))` + **clamp 350 A** jako u 108. |
| 108 | Max charge current | 0 … **max dle modelu** (manuál Deye) | 1 A | Strop **A** z DB (`COALESCE(deye_register_max_charge_a, odvod z kW)` + clamp **350 A**). Ve **PASSIVE** (AUTO) `write_inverter_setpoints` zapisuje **vždy plný strop** — škálování podle malého `battery_w` z LP se **nepoužívá** (TOU výkon drží jemnější signál). Režim **CHARGE** stále odvádí proud z plánovaného výkonu přes `battery_watts_to_amps`. |
| 109 | Max discharge current | 0 … **max dle modelu** (manuál Deye) | 1 A | Obdobně jako 108; ve **PASSIVE** plný strop, **SELL** plný vybíjecí proud, **CHARGE** typicky 0. |
| 128 | Grid charge current | 0 … **max dle modelu** (manuál Deye) | 1 A | Nabíjení ze sítě. Firmware automaticky sníží reálný proud tak, aby `load + battery_charge` nepřekročil velikost jističe — proto LP v `planning_engine.py` plánuje `gi[t]`**do `max_import_power_w + BMS_max_charge`**, aby uměl využít cenově nejlepší 15min okna pro nabíjení na plný BMS strop (viz `planning.md` sekce „Plánovací strop gi[t] vs. fyzický jistič"). Fyzické dodržení jističe drží reg 128 + firmware. |
| 130 | Grid charge enable | 0/1 | — | 1 = povolit nabíjení ze sítě |
| 141 | Energy mgmt mode | bitmask | — | EMS vždy **0** (neměnit jinak) |

View File

@@ -3,7 +3,7 @@
## Keep it simple
- **Méně heuristik a pevných wattových práhů v řízení** — každá magická konstanta je místo, kde se rodí neshody s plánem a ekonomikou.
- **SELL na Deye** používej jen tam, kde produktově opravdu chceme režim „**vylít baterii do sítě**“ (selling first). Vše ostatní patří do **PASSIVE** a tok FVE ↔ baterie ↔ síť se řeší **reg. 108 / 109 / 142** podle plánu a instalace.
- **SELL na Deye** používej jen tam, kde produktově opravdu chceme režim „**vylít baterii do sítě**“ (selling first). Vše ostatní patří do **PASSIVE**: **108/109** dávají **plný proudový rozsah** baterie, směr toku a ekonomiku drží **142** + **TOU** z plánu a instalace.
- Novou logiku vždy ověřit proti **reálnému řádku plánu** (audit / `planning_interval`) a typické chybě „plán říká kW, měnič jede na MW“.
## Přehled
@@ -24,7 +24,7 @@ Detekce v `get_deye_mode` (`battery_w` = `battery_setpoint_w` z plánu, záporn
- **CHARGE:** `battery_w` > 500 **a** `grid_setpoint_w` > 200 → nabíjení ze sítě; reg. **142** dle CHARGE větve v exporteru, **178** = 48.
- **SELL:** `grid_setpoint_w` < 0 **a** `battery_w` < 0 **a** `|battery_w| ≥ |grid_setpoint_w|` → záměr **vybíjet baterii do sítě** (selling first); reg. **142** = 0, **178** = 32, **108** = 0, **109** = max, reg. **143** omezen podle `|grid_setpoint_w|` (viz `control_exporter.py`).
- **PASSIVE:** vše ostatní — tok FVE a baterie řídí **reg. 108** (nabíjení) a **109** (vybíjení, škálované podle `|battery_w|`), **142** = `deye_zero_export_mode`, **145** = 1, **178** = 48.
- **PASSIVE:** vše ostatní — **reg. 108** a **109** na **plný strop** z konfigurace střídače (jako SELF_SUSTAIN); jemné řízení výkonu/SOC jde přes **TOU časové body** z plánu, **142** = `deye_zero_export_mode`, **145** = 1, **178** = 48.
**SELF_SUSTAIN:** `battery_w = None` ⇒ v `get_deye_mode` jako 0 ⇒ typicky **PASSIVE**; v `write_inverter_setpoints` při `self_sustain_local_use=True`**108 i 109 = max**, reg. **142** = zero export dle DB, TOU SOC = **`min_soc_percent`**. **PRESERVE:** `lock_battery`**108 = 0**, **109 = 0**.