Skip to content

Releases: springfall2008/batpred

Much faster planning, support for up to 8 cars, inverter fixes

Choose a tag to compare

@springfall2008 springfall2008 released this 16 Aug 19:20
e86772e

What's Changed

Planning performance

This release is mostly about speed. Three independent rounds of optimisation land here, and every one
of them is gated on the 20-scenario random benchmark producing byte-identical plans - same metric,
cost, both PV futures, final SoC, battery cycles and carbon. Nothing about how Predbat plans has
changed, only how long it takes.

change 20-scenario benchmark
Batch the prediction fan-out into one kernel call (#4540) 39.53s → 24.82s (37% faster)
Remove redundant scans and copies (#4549) 26.13s → 20.15s (23% faster)
Cache window bounds, drop deepcopy on window lists (#4536) 20.27s → 16.64s (18% faster)

Each step was measured separately against its own baseline, so the percentages don't simply multiply -
but end to end the same suite went from roughly 40 seconds to under 17 seconds. Heavy plans gain the
most, which is the point: the two slowest scenarios were 42% of the suite's runtime and both are around
25% faster on the last round alone.

CAUTION: threads in apps.yaml has changed meaning. It used to size a Python pool of worker
processes; it now sizes the C++ kernel's thread pool. The plan is identical at any setting, 0 and 1
both mean serial, and auto remains the default - so if you are running the shipped kernel binary,
there is nothing to do.

CAUTION: if you are not running the C++ kernel, planning is now single-threaded. The Python
multiprocessing pool has been removed rather than kept alongside the kernel, so whenever Predbat falls
back to the Python engine - no binary for your architecture, a binary rejected at load time, or
debug_enable set - the fan-out runs serially and threads has no effect at all. Predbat ships
binaries for x86_64, i686, aarch64, armv7l and both macOS architectures, which covers effectively every
normal install, and those are unaffected. If you are on an architecture with no binary, expect planning
to be slower than v8.48.3 on top of the Python engine's existing cost. Predbat logs
Warn: Prediction kernel ... - using Python engine when this happens, so check the log if planning
suddenly takes longer after upgrading.

Removing the pool also removes a failure mode of its own: its workers rebuilt state from a module global
populated only in the parent, so on any platform defaulting to spawn rather than fork (macOS since
Python 3.8) every worker started empty and every scenario died. That path is gone.

CAUTION: the C++ kernel ABI is bumped to 4 and the parity revision to 6. The binaries shipped in this
release are already rebuilt, but if you build the kernel yourself you must rebuild it. A stale
binary is now correctly rejected at load time and Predbat falls back to the Python engine - which, per
the note above, now also means serial planning, so a forgotten rebuild costs you twice. Previously an
ABI-3 binary would be accepted and then segfault on its first prediction, so the rejection is still very
much the better outcome.

  • perf: batch the prediction fan-out into one kernel call (35% faster planning) by @springfall2008 in #4540
  • perf: cut ~23% off planning by removing redundant scans and copies by @springfall2008 in #4549
  • perf: cache window bounds and replace deepcopy on window lists (-21% planning) by @springfall2008 in #4536

New features

Up to 8 cars are now supported, for people running several EVs or Octopus Intelligent devices on one
account. Cars 4-7 get their own car_charging_rate_* and car_charging_manual_soc_* entities, matching
cars 0-3. This follows on from the v8.48.3 fix that stopped a 5th car crashing Predbat outright.

Bug fixes

On multi-inverter systems the dashboard status was whichever inverter happened to be processed last,
which hid genuine disagreement between inverters. Real cross-charging - one inverter charging while
another discharges - is now surfaced explicitly instead of arbitrarily picking a side.

Solis users with high-voltage batteries were badly affected by a hard-coded 48V nominal voltage: every
derived power and capacity value was wrong by the ratio of the real pack voltage to 48V, around 11x on
a 533V pack (960W computed against ~10.7kW actual).

  • fix(execute): resolve multi-inverter status from all inverters, not just the last one processed by @chalfontchubby in #4466
  • fix(solis): derive nominal_voltage from live battery data instead of hard-coded 48V by @chalfontchubby in #4502
  • fix(inverter): skip the discharge target write on AC Coupled GivTCP inverters by @chalfontchubby in #4543
  • fix(sigenergy): map Sigenergy ESS max discharge limit to battery rate max by @mike-oakley in #4535
  • fix(load-ml): stop a training run that crosses midnight inflating the forecast by @mbuhansen in #4537
  • fix: add timeout to requests.get() in futurerate.py and octopus.py by @springfall2008 with @Copilot in #4539

Notes on two of those: the AC Coupled GivTCP fix completes the #4517/#4518 work for inverters where
Control.Discharge_Target_SOC_1 is absent entirely - GivTCP reported every write as successful but the
value never persisted, so Predbat rewrote it every cycle forever. The load ML fix addresses a fine-tune
that starts before midnight and finishes after it, where a stale load baseline was added on top of every
published forecast point - seen in the wild as a ~30 kWh spike against a 25 kWh actual day.

The requests.get() timeouts matter more than they look: a silent TCP stall on the Nord Pool fetch
raised no exception, so the existing handler never fired and the main prediction loop hung until manual
restart, leaving the inverter latched in its last commanded state.

Testing and documentation

Three feature flags were pinned off across all 20 benchmark scenarios, so anything behind them could be
broken without the gate noticing. set_export_low_power and iboost_enable are now varied across the
suite - and this was not theoretical: the iboost arm of export_window_allowed added in #4549 could not
be reached by any scenario in the repo, and is now exercised 126 times.

New Contributors

Full Changelog: v8.48.3...v8.48.4

Fix crash with more than 4 cars

Choose a tag to compare

@springfall2008 springfall2008 released this 15 Aug 14:54
7ae4318

What's Changed

  • test: give the debug cases and annual integration their own predbat instance by @springfall2008 in #4530
  • fix(fox): bump settings cache version to force-refresh fdpwr_max on upgrade by @springfall2008 in #4532
  • fix(car): clamp num_cars to supported maximum, exclude suspended Octopus devices by @springfall2008 in #4533

Full Changelog: v8.48.2...v8.48.3

PV90 and second pass enabled by default, bug fixes

Choose a tag to compare

@springfall2008 springfall2008 released this 15 Aug 12:52
9ae81c1

What's Changed

Planning changes

CAUTION: PV90 planning and second pass is now enabled by default, can be disabled only after turningon performance_tweaks toggle. These both give better/more-balanced plan results but add runtime, which. is largely made up for with all the recent speedup changes.

Also improved handling of late exports.

Bug fuixes

  • fix(axle): boost the import rate during an Axle export event by @springfall2008 in #4520
  • fix(fox): correct half-kW inverter capacity and round noisy production totals by @springfall2008 in #4527
  • fix(output): stop load_energy_predicted's whole-day total drifting through the day by @chalfontchubby in #4519
  • fix(inverter): re-assert timed charge/discharge current every cycle, not just on rate change by @chalfontchubby in #4437
  • fix(inverter): also prefer Control.Discharge_Target_SOC_1 when deciding whether to write by @chalfontchubby in #4518

Full Changelog: v8.48.1...v8.48.2

Planning improvements & bug fixes

Choose a tag to compare

@springfall2008 springfall2008 released this 13 Aug 20:04
c6702d0

What's Changed

Planning improvement

Major speed improvements due to optimisations.
Better clipping algorithm to remove dead slots (ones only needed for 10%/90% scenario).

  • feat(plan): model-based clipping — prune plan slots that are dead in the central forecast by @springfall2008 in #4491
  • perf(plan): skip disabled windows in remove_intersecting_windows (3.1x faster planning) by @springfall2008 in #4505
  • perf(prediction): build the kernel's ctypes arrays via array.array (1.9x faster planning) by @springfall2008 in #4509
  • chore(plan): make the planner log readable at default verbosity by @springfall2008 in #4510
  • fix(prediction): collision-safe simulation cache key + clip windows in the C++ kernel by @springfall2008 in #4508

WhatIf

  • feat(whatif): new edf export 12m v2 tariff (13p) by @Easen in #4503

Bug fixes

  • fix(inverter): settle before verifying a GivTCP discharge target write by @chalfontchubby in #4492
  • fix(output): apply load_scaling to the predicted load curve's future portion by @chalfontchubby in #4506
  • fix(output): apply load_scaling_dynamic and manual_load_adjust to today_remaining by @chalfontchubby in #4511
  • perf(plan): cache export-to-charge window collisions in the optimiser (1.5x faster planning) by @springfall2008 in #4507
  • fix(solis): guard battery_scaling against a documented 0% SOH API response by @chalfontchubby in #4500
  • fix(octopus): split a slot around a fully-contained overlap instead of losing its remainder by @chalfontchubby in #4504

PredBat Gateway

  • feat(gateway): sync internal-DRAM fields into the shared status schema by @mgazza in #4495
  • fix(gateway): pin EV charger entity ids to the charge point id by @mgazza in #4489

Full Changelog: v8.48.0...v8.48.1

Planning algorithm tweaks including PV90 support (when enabled), Misc fixes

Choose a tag to compare

@springfall2008 springfall2008 released this 12 Aug 07:44
9dbbecd

What's Changed

Improvements to planning

When enabled with switch.predbat_calculate_pv90_plan Predbat will use the PV90 scenario (as well as the PV10) within its planning algorithm, this does take 20-30% more compute but will more correctly hedge scenarios for better solar/lower load days.

The battery value algorithm has also been changed for those with low/zero export rates to discourage over charging.

Please feedback

  • feat(plan): add a pv90 upside forecast scenario to balance the one-sided pv10 hedge by @springfall2008 in #4462
  • fix(plan): convert phantom export windows to freeze in clip_export_slots (#4453) by @springfall2008 in #4487
  • fix(plan): value left-over battery on the base tariff, not saving-session prices by @springfall2008 in #4488

Bug fixes and documentation updates

  • docs(ohme): energy sensor removed in HA 2026.8.0, recommend a Riemann sum helper by @chalfontchubby in #4465
  • fix(prediction): bound import/export kWh to end_record, not the full forecast horizon by @springfall2008 in #4470
  • feat: mirror gateway_status.proto wifi_ssid field (predbat-gateway sync) by @mgazza in #4467
  • feat(plan): show a rate range for merged plan cells, fix threshold wording by @chalfontchubby in #4362
  • fix(fetch): warn loudly when car_charging_energy is configured but has no data by @chalfontchubby in #4469
  • Update LuxPower template by @brickatius in #4475
  • fix(sigenergy): exit VPP explicitly before offboarding, and confirm it landed by @mgazza in #4477
  • fix(web): stop double-marking manually overridden plan rate cells by @chalfontchubby in #4479
  • fix(load): stop zeroing genuine load when import exceeds it for a bucket by @chalfontchubby in #4471
  • fix(inverter): only invoke discharge_freeze_service on an explicit freeze request by @chalfontchubby in #4472
  • Remove battery device_class from Fox SOH sensor to prevent HA low-battery false alerts by @springfall2008 with @Copilot in #4490

Full Changelog: v8.47.7...v8.48.0

EnPhase cloud scheduler fixes, Solis documentation update

Choose a tag to compare

@springfall2008 springfall2008 released this 08 Aug 17:39
2d15459

What's Changed

  • docs(solis): note that the inverter's own timezone must match Predbat's by @chalfontchubby in #4451
  • fix(enphase): retry POST-create on conflict, disambiguate HTTP logs, surface write failures by @springfall2008 in #4463

Full Changelog: v8.47.6...v8.47.7

GECloud Timezone, Sigenergy Cloud Axle, New downloader

Choose a tag to compare

@springfall2008 springfall2008 released this 08 Aug 09:43
df96f89

What's Changed

  • fix(solar): scale PV forecast by the detected slot length for all sources by @tieskuh in #4433
  • Sigenergy: stop Predbat and Axle fighting over the inverter, and make axle_control work by @mgazza in #4457
  • feat(update): verify downloaded files against GitHub checksums before installing by @springfall2008 in #4439
  • fix(config): give fractional-step input_number items a float default, not int by @chalfontchubby in #4441
  • feat(gecloud): use the customer account timezone for the start/end time registers by @springfall2008 in #4460

Full Changelog: v8.47.5...v8.47.6

Enphase cloud bug fixes, clip export windows when battery is empty

Choose a tag to compare

@springfall2008 springfall2008 released this 04 Aug 18:49
e950156

What's Changed

Full Changelog: v8.47.4...v8.47.5

Bug fixes for EnPhase Cloud, Gateway and misc other

Choose a tag to compare

@springfall2008 springfall2008 released this 03 Aug 11:29
48d7330

What's Changed

  • fix(gateway): dispatch MQTT publishes onto the owning event loop by @mgazza in #4422
  • fix(enphase): stop schedule conflicts wedging battery control by @springfall2008 in #4428
  • fix(car-charging): show car charging limit as % (with kWh) in debug logs, not mislabelled kWh-as-% by @chalfontchubby in #4420
  • fix(plan): widen forecast_minutes before building yesterday_load_step/yesterday_pv_step by @chalfontchubby in #4419

Full Changelog: v8.47.3...v8.47.4

Minor plan improvements, Whatif EDF, bug fixes

Choose a tag to compare

@springfall2008 springfall2008 released this 02 Aug 11:28
f2d87f5

What's Changed

Planning improvements

Bug fixes

  • fix(hass): don't misdetect an existing install as new on a transient predbat.status read failure by @chalfontchubby in #4409
  • feat(config): retry validate_config() after a failure, self-healing (#4379) by @chalfontchubby in #4394
  • fix(inverter): stop spurious "REST failed to setExportTarget" warnings by @springfall2008 in #4413

Whatif improvements

New Contributors

Full Changelog: v8.47.2...v8.47.3