fix battery charge u self_sustain rezimu
This commit is contained in:
@@ -308,6 +308,8 @@ class ControlSetpoints:
|
||||
effective_sell_price_czk_kwh: float | None = None
|
||||
#: True = reg 108/109 na 0 (PRESERVE – Deye baterii nepoužívá)
|
||||
lock_battery: bool = False
|
||||
#: Režim SELF_SUSTAIN: plný rozsah nabíjení/vybíjení na invertoru + zero-export (reg 142) a nízké TOU %.
|
||||
self_sustain_local_use: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -1184,6 +1186,7 @@ def _build_setpoints(mode: OperatingModeInfo, pi: asyncpg.Record | None) -> Cont
|
||||
ev1_power_w=0,
|
||||
ev2_power_w=0,
|
||||
target_soc_pct=None,
|
||||
self_sustain_local_use=True,
|
||||
)
|
||||
|
||||
if code == "CHARGE_CHEAP":
|
||||
@@ -1291,8 +1294,14 @@ def _deye_passive_tou_battery_soc_pct(
|
||||
|
||||
Jinak zůstane provozní podlaha ``min_soc_percent`` (typicky nízká % → přetok do sítě
|
||||
možný dle chování Deye).
|
||||
|
||||
Režim **SELF_SUSTAIN** (``self_sustain_local_use``): vždy ``min_soc_percent`` — nízké
|
||||
TOU drží prioritu „baterie jako buffer“ při plném reg. 108/109 a reg. 142 zero-export;
|
||||
neaplikuje se sem logika 100 % podle ceny (LP se v SELF_SUSTAIN nepoužívá).
|
||||
"""
|
||||
mn = _deye_tou_min_soc_pct(inv)
|
||||
if setpoints.self_sustain_local_use:
|
||||
return mn
|
||||
|
||||
bat_w = 0 if setpoints.battery_w is None else int(setpoints.battery_w)
|
||||
sell = setpoints.effective_sell_price_czk_kwh
|
||||
@@ -1311,7 +1320,8 @@ def get_deye_mode(setpoints: ControlSetpoints) -> str:
|
||||
SELL only when battery actively discharges for grid export (bat_w < -500
|
||||
AND grid_w < -200). Pass-through (PV → grid, battery idle) stays PASSIVE
|
||||
with reg 108 = 0 + reg 145 = 1 (solar sell).
|
||||
battery_w=None (SELF_SUSTAIN) → bat_w considered 0 → PASSIVE.
|
||||
battery_w=None (SELF_SUSTAIN) → bat_w considered 0 → PASSIVE; při exportu se ale
|
||||
zapíše plný reg. 108/109 (viz ``self_sustain_local_use`` v ``write_inverter_setpoints``).
|
||||
"""
|
||||
grid_w = int(setpoints.grid_setpoint_w or 0)
|
||||
bat_w = 0 if setpoints.battery_w is None else int(setpoints.battery_w)
|
||||
@@ -1384,6 +1394,11 @@ async def write_inverter_setpoints(
|
||||
elif deye_mode == "CHARGE":
|
||||
charge_a = battery_watts_to_amps(bat_w, inv.max_charge_a)
|
||||
discharge_a = 0
|
||||
elif setpoints_now.self_sustain_local_use:
|
||||
# SELF_SUSTAIN: plný nabíjecí i vybíjecí proud invertoru — přebytek FVE jde do baterie,
|
||||
# reg. 142 = zero export to load/CT (viz selling_mode níže), ne reg. 108 = 0.
|
||||
charge_a = int(inv.max_charge_a)
|
||||
discharge_a = int(inv.max_discharge_a)
|
||||
else:
|
||||
charge_a = int(inv.max_charge_a) if bat_w > 0 else 0
|
||||
discharge_a = int(inv.max_discharge_a)
|
||||
|
||||
@@ -123,6 +123,26 @@ class DeyeTouParamsTests(unittest.TestCase):
|
||||
self.assertTrue(g)
|
||||
self.assertEqual(s, 95)
|
||||
|
||||
def test_self_sustain_tou_stays_min_soc_even_if_sell_negative(self) -> None:
|
||||
"""SELF_SUSTAIN: nízké TOU (min_soc), ne 100 % z negativní vykupní — LP se nepoužívá."""
|
||||
sp = ControlSetpoints(
|
||||
battery_w=None,
|
||||
grid_export_limit=0,
|
||||
ev1_current_a=0,
|
||||
ev2_current_a=0,
|
||||
heat_pump_enable=False,
|
||||
grid_setpoint_w=0,
|
||||
ev1_power_w=0,
|
||||
ev2_power_w=0,
|
||||
target_soc_pct=None,
|
||||
effective_sell_price_czk_kwh=-0.48,
|
||||
self_sustain_local_use=True,
|
||||
)
|
||||
self.assertEqual(get_deye_mode(sp), "PASSIVE")
|
||||
_p, s, g = _deye_tou_params(sp, _inv(min_soc=12, reserve_soc=20))
|
||||
self.assertFalse(g)
|
||||
self.assertEqual(s, 12)
|
||||
|
||||
def test_lock_battery_uses_min_soc(self) -> None:
|
||||
sp = ControlSetpoints(
|
||||
battery_w=0,
|
||||
|
||||
Reference in New Issue
Block a user