register 340 -omezovani vyrkonu pv pole (home-01)
Some checks failed
CI and deploy / migration-check (push) Failing after 11s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-01 12:51:28 +02:00
parent e686bc1d2c
commit 1e0300dd7e
8 changed files with 200 additions and 11 deletions

View File

@@ -125,6 +125,8 @@ CREATE TABLE asset_battery (
### `asset_pv_array`
Každé FVE pole zvlášť důležité pro predikci (azimut, sklon). **Zelený bonus** (dotace za vyrobenou elektřinu) se váže na **úroveň pole**, ne na celou lokalitu: které pole má bonus, jaká je sazba Kč/kWh a platnost, určují sloupce `green_bonus_*`. Výpočet příjmu za interval probíhá funkcí `ems.fn_green_bonus_revenue` z výroby v Wh; není součástí efektivní prodejní ceny ze sítě.
**Deye reg 340 (max solar power, W):** strop pro řiditelné DC pole A na hybridu počítá `ems.fn_inverter_pv_a_max_w(inverter_id)` jako **součet `nominal_power_wp`** řádků s `controllable = true` vázaných na daný invertor. Exportér (`exporter_monolith.write_inverter_setpoints`) tento cap použije jen u `asset_inverter.manufacturer` = Deye a **pouze pokud součet > 0**; při součtu 0 se reg 340 z EMS nezapisuje (nezasahuje do ručního nastavení v invertoru).
```sql
CREATE TABLE asset_pv_array (
id SERIAL PRIMARY KEY,

View File

@@ -130,9 +130,20 @@ registru **178** (v některých manuálech/UI uváděno jako “register 179”
- `deye_gen_cutoff_enabled = false` → reg **178** bits **01** = **2** (`10b`, disable = cut-off **OFF** / export povolen)
Zápisy se ukládají do `ems.modbus_command` a ověřují v `verify_modbus_commands` (porovnává se pouze maska
bits 01). Detail registrů: [`modbus-registers.md`](modbus-registers.md) (reg 179).
bits 01). Detail registrů: [`modbus-registers.md`](modbus-registers.md) (reg 178).
### PV A curtailment — zápis reg 340 (max solar power)
- **Implementace:** `backend/services/control/exporter_monolith.py``export_setpoints` načte cap v `_load_inverter_config` (`ems.fn_inverter_pv_a_max_w(ai.id)`), `_build_setpoints` v režimu **AUTO** dopočítá `ControlSetpoints.pv_a_allowed_w`, `write_inverter_setpoints` zařadí **reg 340**, pokud je výrobce invertoru Deye, cap > 0 a `pv_a_allowed_w` je vyplněné.
- **Data:** `pv_a_forecast_solver_w` / `pv_a_curtailed_w` z aktivního `planning_interval` (json z `ems.fn_planning_interval_at_offset`); cap = součet `nominal_power_wp` řiditelných polí na invertoru (bez nového sloupce v DB).
- **Verify:** reg **340** není kritický → po 3× mismatch verify **bez** přepnutí do SELF_SUSTAIN (stejně jako reg 178); viz [`modbus-command-journal.md`](modbus-command-journal.md).
#### Ověření po nasazení (smoke)
1. `select ems.fn_inverter_pv_a_max_w(<id kontrolovatelného deye-main invertoru>);` — při **0** na PV A (např. odpojené pole, `nominal_power_wp = 0`) EMS reg 340 **nezapisuje**.
2. Dočasně zvýšit `nominal_power_wp` na controllable PV A → po dalším běhu exportu řádek v `ems.modbus_command` pro register **340** → po verify jobu stav **`verified`**.
3. Živé čtení: `read_deye_registers_live` vrací **`reg340_max_solar_power_w`**.
### Fyzický režim (`get_deye_mode` v `exporter_monolith.py`)
| Fyzický režim | Podmínka z `ControlSetpoints` |
@@ -167,7 +178,7 @@ Hodnota `deye_zero_export_mode` (1 = zero export to load, 2 = zero export to CT)
Po zápisu na Modbus se hodnoty ověřují v `verify_modbus_commands` (`control_exporter.py`). Po **3 neúspěšných** cyklech zápis+verify:
- **Kritické registry** (**108, 109, 142, 143, 145**) → přepnutí lokality do **SELF_SUSTAIN** (`system:mismatch`).
- **Ostatní** (včetně **178** a **TOU power W 154159** po vyčerpání soft pravidel) → zůstane **AUTO** (nebo aktuální režim), řádek journalu **`mismatch`**, Discord upozornění.
- **Ostatní** (včetně **178**, **340** a **TOU power W 154159** po vyčerpání soft pravidel) → zůstane **AUTO** (nebo aktuální režim), řádek journalu **`mismatch`**, Discord upozornění.
Při přechodu **SELF_SUSTAIN → AUTO** (`run_fn_set_mode_with_discord`) se na pozadí spustí **rolling replan**, aby aktivní plán odpovídal plné optimalizaci. Viz [`modbus-command-journal.md`](modbus-command-journal.md).

View File

@@ -19,12 +19,20 @@ EMS zapisuje řídící hodnoty přes journal (`modbus_command`) a **`write_regi
| 141 | Energy mgmt mode | bitmask | — | EMS vždy **0** (neměnit jinak) |
| 142 | Limit control (System work mode) | 0/1/2 | — | **0** = selling first, **1** = zero export to load, **2** = zero export to CT. Hodnota v non-SELL režimech pochází z `asset_inverter.deye_zero_export_mode` (závisí na instalaci viz tabulka níže). V režimu SELL vždy **0**. |
| 145 | Solar sell | 0/1 | — | **0** = disabled (přebytek FVE na **straně měniče** se nesmí vést do sítě — curtailment vůči síti), **1** = enabled. Platí jen pro **FVE pod kontrolou Deye** (`controllable = true`); druhá pole (např. **pv-b** u home-01) EMS tímto registerem neřídí. EMS dnes **vždy zapisuje 1**; při 108 = 0 a 145 = 1 přebytky z řiditelného stringu typicky tečou do sítě (viz pass-through níže). |
| 340 | Max solar power | 0 … cap (W) | 1 W | Strop výkonu DC PV řízeného střídačem (pole A). EMS zapisuje jen pokud `manufacturer` = Deye a `ems.fn_inverter_pv_a_max_w(inverter_id) > 0` (součet `nominal_power_wp` controllable polí). Hodnota z aktivního `planning_interval`: bez curtailmentu = cap; s `pv_a_curtailed_w > 0` = `clamp(0, cap, pv_a_forecast_solver_w pv_a_curtailed_w)`. **Není** v `DEYE_CRITICAL_REGS_SELF_SUSTAIN` — verify mismatch nečeká přepnutí do SELF_SUSTAIN. |
| 143 | Export limit W | závisí na typu (SUN-20K až ~13 500) | 1 W | Max export do sítě; hodnota z `site_grid_connection.max_export_power_w` |
| 178 | Control board special 1 | bitmask | — | Bitové pole pro více funkcí. **EMS používá:** (a) bits **45** pro peak shaving switch: **32** (`0b00100000`, bit45 = **10**) v režimu **SELL**; **48** (`0b00110000`, bit45 = **11**) v **PASSIVE/CHARGE**. (b) **BA81:** bits **01** pro „MI export to Grid cutoff“ (AC coupling / GEN): **2** = disable (cutoff OFF), **3** = enable (cutoff ON). EMS zapisuje jako **read-modify-write** (zachová ostatní bity). V některých manuálech/UI je to označené jako „register 179“ (1-based). |
| 190 | GEN peak shaving | 016000 | 1 W | Peak shaving na GEN portu |
| 191 | Grid peak shaving power | 016000 | 1 W | **EMS NEZAPISUJE** nastavit **manuálně v SolarmanApp**. Hodnota určuje výkon peak shavingu v **W**. |
`exporter_monolith.write_inverter_setpoints` zapisuje přes **`modbus_command`** (journal; jeden řádek na registr) a **`execute_modbus_commands`** odesílá **souvislé bloky jedním FC 0x10** (např. 6264, 148159, 166177, 108109, 141143, 145 podle toho, co je ve frontě). Pořadí v journalu: **6264** (čas, viz níže), **time points 148177** (jen řádky zařazené do daného běhu), **108, 109, 141, 142, 143, 145, 178**. Popisné názvy v DB bere `DEYE_REGISTER_NAMES`. **Reg 191** EMS nezapisuje.
`exporter_monolith.write_inverter_setpoints` zapisuje přes **`modbus_command`** (journal; jeden řádek na registr) a **`execute_modbus_commands`** odesílá **souvislé bloky jedním FC 0x10** (např. 6264, 148159, 166177, 108109, 141143, 145, 340 podle toho, co je ve frontě). Pořadí v journalu: **6264** (čas, viz níže), **time points 148177** (jen řádky zařazené do daného běhu), **108, 109, 141, 142, 143, 145, 340 (podmíněně), 178**. Popisné názvy v DB bere `DEYE_REGISTER_NAMES`. **Reg 191** EMS nezapisuje.
### Reg 340 (max solar power)
- **FC 0x10**, jednotka **W**; firmware omezuje strop výroby z řiditelných stringů (pole A na hybridu).
- **Kdy EMS zapisuje:** `asset_inverter.manufacturer` odpovídá Deye **a** `ems.fn_inverter_pv_a_max_w(inverter_id) > 0` (součet `nominal_power_wp` z `asset_pv_array` kde `controllable = true`). Při součtu **0** EMS reg 340 **nezapisuje** (např. odpojené pole A s `nominal_power_wp = 0` v DB — ruční hodnota v invertoru zůstane).
- **Hodnota:** z `ControlSetpoints.pv_a_allowed_w` (AUTO): bez curtailmentu = plný cap; při `pv_a_curtailed_w > 0` viz tabulka výše. Režimy **SELF_SUSTAIN / PRESERVE / CHARGE_CHEAP** mají `pv_a_allowed_w = None` → žádný zápis 340 z EMS v daném ticku.
- **Živé čtení:** `read_deye_registers_live` vrací **`reg340_max_solar_power_w`**.
### Reg 191 (výkon grid peak shaving)
@@ -131,7 +139,7 @@ Deye má 6 časových bloků. EMS přepisuje **bloky 12** (TOU index 01) p
| 2 | **`next_slot_hhmm()`** začátek **následujícího** 15min slotu | `planning_interval` pro **další** slot (`_fetch_plan_row_for_slot_offset(..., 1)`) | Přechod na další čtvrthodinu | viz tabulka níže | viz tabulka níže |
| 36 | **23:55** (2355) | — | Neaktivní (pasivní profil); ne 23:59 — firmware Deye často 2359 neuloží → verify mismatch | **`min_soc_percent`** (DB) | NE |
**Registry 108 / 109 / 141 / 142 / 143 / 145 / 178** odpovídají **aktuálnímu** plánu (okamžitý výstup; `setpoints_now` v `write_inverter_setpoints`). TOU řádky 12 doplňují stejnou logiku pro časové segmenty (`_deye_tou_params`).
**Registry 108 / 109 / 141 / 142 / 143 / 145 / 340 (podmíněně) / 178** odpovídají **aktuálnímu** plánu (okamžitý výstup; `setpoints_now` v `write_inverter_setpoints`). TOU řádky 12 doplňují stejnou logiku pro časové segmenty (`_deye_tou_params`).
Příklad v 14:18: blok 1 má čas **1415**, blok 2 čas **1430** mezi 14:15 a 14:29 je aktivní segment z bloku 1 (sladěný s plánem pro 14:1514:30), po 14:30 blok 2 (plán 14:3014:45). Po dalším exportu se oba časy posunou (např. 14:30 / 14:45).

View File

@@ -487,6 +487,8 @@ COMMENT ON COLUMN ems.planning_interval.pv_a_curtailed_w IS
'Hodnota > 0 znamená že solver rozhodl omezit výrobu pole A přes Modbus.';
```
**Fyzická realizace na Deye (bez změny solveru):** u hybridu s `manufacturer = Deye` a nenulovým součtem `nominal_power_wp` controllable polí na invertoru exportér mapuje `pv_a_forecast_solver_w` / `pv_a_curtailed_w` na zápis **holding registru 340** (max solar power, W) — viz [`control.md`](control.md) sekce *PV A curtailment* a [`modbus-registers.md`](modbus-registers.md) reg 340.
---
## Tuning pro malé baterie (např. BA81)