fix(control): reg 108 v PV_SURPLUS sleduje charge intent (BA81 nenabíjelo levné ráno)

deye_battery_charge_discharge_amps: v PASSIVE+PV_SURPLUS reg 108 = max když plán
chce nabíjet (bat_w>0) místo tvrdé 0; baterka nabere co zvládne, přebytek nad
nabíjecí rychlost do sítě. + kalibrace: SoC u maxima → dojet na 100% (BMS). Sell
beze změny. Vědomě přepsán test starého chování. 365 passed. Všechny Deye lokality.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dusan Vojacek
2026-06-16 16:32:01 +02:00
parent 17147ca412
commit daf7ed4d4b
7 changed files with 83 additions and 8 deletions

View File

@@ -68,7 +68,7 @@ Vychází z **`grid_setpoint_w`** a **`battery_w`** z `ControlSetpoints` (aktivn
Režim **CHARGE_CHEAP** nastaví oba setpointy na stejný kladný výkon (min. 1 W), aby byl výsledek **CHARGE**.
**PASSIVE (ZERO):** u slotu **`export_mode = PV_SURPLUS`** exporter nastaví **108 = 0** (nabíjecí proud), **109 = max**baterie nemá kam brát přebytek FVE, jde do sítě při **145 = 1**; **142** zůstává **`deye_zero_export_mode`** (u CT často **2** = zero export k měření zátěže, ne selling first z baterie). Detail: `operating-modes.md`.
**PASSIVE (ZERO):** u slotu **`export_mode = PV_SURPLUS`** reg **108** (nabíjecí proud) **sleduje charge intent plánu** (fix 2026-06-16): `bat_w > 0` **108 = max** (baterka nabere kolik fyzicky zvládne, přebytek **nad nabíjecí rychlost** jde do sítě při **145 = 1**řeší případ „výroba > rychlost baterky" na export-omezených i běžných lokalitách); SoC u maxima (`>= max_soc 3 p.b.`, `BATTERY_CALIB_TOPOFF_MARGIN_PCT`) + přebytek → **108 = max** (BMS rekalibrace na 100 %); jen „prodej PV a drž baterku" daleko od maxima (`bat_w <= 0`) → **108 = 0**. **109 = max**; **142** zůstává **`deye_zero_export_mode`** (u CT často **2**). Dřív tvrdě **108 = 0** i při `bat_w > 0` → baterka nenabíjela ani levné ranní PV (control bug, BA81). Detail: `operating-modes.md`, changelog 2026-06-16.
### BA81: GEN port cut-off (reg 178 bits01) z plánu

View File

@@ -4,7 +4,7 @@
- **Žádné wattové prahy pro výběr SELL / CHARGE** — mapování z MILP setpointů je čistě ze **znamének** `battery_setpoint_w` a `grid_setpoint_w` (viz `get_deye_mode` v `exporter_monolith.py`).
- **Přetok FVE do sítě** se neodvozuje z forecastového capu: plán nese explicitní `export_limit_w` jako tvrdý limit lokality / invertoru, ne jako tipované maximum z předpovědi.
- **ZERO (PASSIVE)** = **142** = `deye_zero_export_mode` (1/2, ne selling first). **PV_SURPLUS:** **108 = 0**, **109 = max** — přebytek FVE do sítě (**145 = 1**), ne do baterie. Jinak **108/109** typicky max; výjimka import bez vybíjení → **109 = 0**.
- **ZERO (PASSIVE)** = **142** = `deye_zero_export_mode` (1/2, ne selling first). **PV_SURPLUS** (fix 2026-06-16): reg **108 sleduje charge intent plánu**`bat_w > 0` **108 = max** (baterka nabere kolik fyzicky zvládne, přebytek **nad nabíjecí rychlost** jde do sítě, **145 = 1**); SoC u maxima (`>= max_soc 3 p.b.`) + přebytek → **108 = max** (BMS kalibrace na 100 %); jen „prodej PV a drž baterku" daleko od maxima (`bat_w <= 0`) → **108 = 0**. **109 = max**. Jinak **108/109** typicky max; výjimka import bez vybíjení → **109 = 0**.
- **SELL** = plánovaný export **i** plánované vybíjení (oba záporné) → **142** = selling first, **178** = vypnutý grid peak shaving (32); reg **108** EMS **nemění** (export řídí 142, ne vynucené 0 A). 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`).

View File

@@ -5,6 +5,14 @@ Formát: **datum (ISO)** · stručný důvod · soubory · chování / ověřen
---
## 2026-06-16 — control: reg 108 v PV_SURPLUS sleduje charge intent (BA81 nenabíjelo levné ráno)
- **Problém (triáž BA81):** výroba 12 kW (= ~2× nabíjecí rychlost baterky 6 kW), levné ranní výkupní ceny, baterka stála celé ráno na 29 % a vše šlo do sítě; nabíjet začala až odpoledne (dražší). Plán PŘITOM chtěl nabíjet (soc_tgt rostl), ale realita ne → promeškaná levná ranní arbitráž (~0.7 Kč/kWh). NEbyl to forecast (canonical ≈ realita) ani planner — **exekuce.**
- **Příčina:** `deye_battery_charge_discharge_amps` (setpoints.py) v PASSIVE + `export_mode=PV_SURPLUS` vracela tvrdě **`108=0` i když `bat_w>0`** (záměrné, testem podchycené chování — ale chyba pro „výroba > nabíjecí rychlost"). Deye pak prodával vše, baterku nenabil. `get_deye_mode`: `bat_w>0 & grid<0` (export) → PASSIVE, ne CHARGE.
- **Mechanismus (fix):** reg 108 v PV_SURPLUS **sleduje charge intent plánu**: `bat_w>0`**108=max** (baterka nabere kolik fyzicky zvládne, přebytek nad rychlost do sítě); SoC u maxima (`>= max_soc 3 p.b.`) + přebytek → **108=max** (BMS rekalibrace na 100 %); jen `bat_w<=0` daleko od maxima → **108=0**. Sell/discharge beze změny (mód + 109, 108 neřešíme — díky DV za korekci). Strop SoC drží Deye max_soc.
- **Soubory:** `setpoints.py` (`deye_battery_charge_discharge_amps` + konstanta `BATTERY_CALIB_TOPOFF_MARGIN_PCT`), `inverter.py` (napojení živého SoC + max_soc), `test_control_deye_passive_pv_charge.py` (vědomě přepsán test starého chování + 2 nové), CLAUDE.md §18, operating-modes.md, modbus-registers.md.
- **Ověření:** plná sada **365 passed, 4 xfailed**. Mimo solver → golden gate beze změny. Platí pro všechny Deye lokality (BA81 i hypotetická malá s nízkým export limitem).
## 2026-06-14 — EV anti-fragmentace + 3f power floor (Fix B, solver_v2)
- **Problém:** EV nabíjení v solveru spojité po slotech bez start/stop penalty → rozsekané přes nesouvislé sloty + dílčí 1f trickle (sub-6A, který control stejně shazoval na 0 A) → cyklování nabíječky, Tesla notifikace.