Skip to content

Commit 170b566

Browse files
committed
Fix timed export extending past Amber headroom target (#24)
The extension logic in maybe_restore_timed_grid_export kept extending exports as long as SOC > export_soc_floor (45%), not realising the headroom target had already been met (75% SOC for Amber, 50% for Green). All six headroom-based start_timed_grid_export call sites in morning.py and afternoon.py now derive export_soc_floor from the headroom target: max(DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT, 100 - headroom_target_kwh/BATTERY_KWH*100) so exports stop — and are not extended — once the target SOC is reached.
1 parent e0afef6 commit 170b566

2 files changed

Lines changed: 30 additions & 6 deletions

File tree

‎logic/afternoon.py‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,15 @@ async def handle_afternoon_period(ctx: PeriodHandlerContext) -> bool:
168168
mode=SIGEN_MODES["GRID_EXPORT"], reason=mid_period_reason,
169169
outcome="mid-period high-SOC safety export triggered",
170170
)
171+
mid_period_headroom_target_soc = max(
172+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
173+
100.0 - mid_period_headroom_target_kwh / BATTERY_KWH * 100.0,
174+
)
171175
mid_period_override_started = await start_timed_grid_export(
172176
period=PERIOD, reason=mid_period_reason,
173177
duration_minutes=mid_period_duration_minutes,
174178
now_utc=now_utc, battery_soc=mid_period_soc, is_clipping_export=True,
175-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
179+
export_soc_floor=mid_period_headroom_target_soc,
176180
)
177181
if mid_period_override_started:
178182
return True
@@ -227,10 +231,14 @@ async def handle_afternoon_period(ctx: PeriodHandlerContext) -> bool:
227231
mode=mode, reason=reason,
228232
outcome="pre-period export triggered",
229233
)
234+
headroom_target_soc = max(
235+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
236+
100.0 - headroom_target_kwh / BATTERY_KWH * 100.0,
237+
)
230238
override_started = await start_timed_grid_export(
231239
period=PERIOD, reason=reason, duration_minutes=duration_minutes,
232240
now_utc=now_utc, battery_soc=soc,
233-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
241+
export_soc_floor=headroom_target_soc,
234242
)
235243
if not override_started:
236244
logger.warning(
@@ -327,10 +335,14 @@ async def handle_afternoon_period(ctx: PeriodHandlerContext) -> bool:
327335
mode=mode, reason=reason,
328336
outcome="period-start timed export started",
329337
)
338+
headroom_target_soc = max(
339+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
340+
100.0 - headroom_target_kwh / BATTERY_KWH * 100.0,
341+
)
330342
override_started = await start_timed_grid_export(
331343
period=PERIOD, reason=reason, duration_minutes=duration_minutes,
332344
now_utc=now_utc, battery_soc=soc, is_clipping_export=is_clipping_export,
333-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
345+
export_soc_floor=headroom_target_soc,
334346
)
335347
if override_started:
336348
s["start_set"] = True

‎logic/morning.py‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,15 @@ async def handle_morning_period(ctx: PeriodHandlerContext) -> bool:
168168
mode=SIGEN_MODES["GRID_EXPORT"], reason=mid_period_reason,
169169
outcome="mid-period high-SOC safety export triggered",
170170
)
171+
mid_period_headroom_target_soc = max(
172+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
173+
100.0 - mid_period_headroom_target_kwh / BATTERY_KWH * 100.0,
174+
)
171175
mid_period_override_started = await start_timed_grid_export(
172176
period=PERIOD, reason=mid_period_reason,
173177
duration_minutes=mid_period_duration_minutes,
174178
now_utc=now_utc, battery_soc=mid_period_soc, is_clipping_export=True,
175-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
179+
export_soc_floor=mid_period_headroom_target_soc,
176180
)
177181
if mid_period_override_started:
178182
return True
@@ -227,10 +231,14 @@ async def handle_morning_period(ctx: PeriodHandlerContext) -> bool:
227231
mode=mode, reason=reason,
228232
outcome="pre-period export triggered",
229233
)
234+
headroom_target_soc = max(
235+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
236+
100.0 - headroom_target_kwh / BATTERY_KWH * 100.0,
237+
)
230238
override_started = await start_timed_grid_export(
231239
period=PERIOD, reason=reason, duration_minutes=duration_minutes,
232240
now_utc=now_utc, battery_soc=soc,
233-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
241+
export_soc_floor=headroom_target_soc,
234242
)
235243
if not override_started:
236244
logger.warning(
@@ -327,10 +335,14 @@ async def handle_morning_period(ctx: PeriodHandlerContext) -> bool:
327335
mode=mode, reason=reason,
328336
outcome="period-start timed export started",
329337
)
338+
headroom_target_soc = max(
339+
DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
340+
100.0 - headroom_target_kwh / BATTERY_KWH * 100.0,
341+
)
330342
override_started = await start_timed_grid_export(
331343
period=PERIOD, reason=reason, duration_minutes=duration_minutes,
332344
now_utc=now_utc, battery_soc=soc, is_clipping_export=is_clipping_export,
333-
export_soc_floor=DAYTIME_TIMED_EXPORT_MIN_SOC_PERCENT,
345+
export_soc_floor=headroom_target_soc,
334346
)
335347
if override_started:
336348
s["start_set"] = True

0 commit comments

Comments
 (0)