Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .cspell/custom-dictionary-workspace.txt
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ deadbanding
deadbeefdeadbeef
dedup
dedupe
deepcopied
dend
denorm
derate
Expand Down Expand Up @@ -282,6 +283,7 @@ hainterface
halfhourly
hanchu
hanchuess
handback
hanres
HAOS
harvi
Expand Down Expand Up @@ -441,6 +443,10 @@ nocharge
NODETAIL
nodischarge
nohup
nonboolean
nonfeasible
nonfinal
nonfinite
noopener
nord
nordpool
Expand Down Expand Up @@ -561,6 +567,7 @@ replayer
resetmidnight
resultid
resultmid
retrievalstatus
retryable
reweight
reweighted
Expand Down Expand Up @@ -710,6 +717,7 @@ unflushed
unindexed
unnormalised
unparseable
unpassed
unpickled
unpickles
unpushed
Expand All @@ -735,6 +743,7 @@ vvwwxxabcdefyyzzuu
waf
waitpid
Wallbox
wallclock
weakref
weblink
welink
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Predbat

> Experimental [joint EV/home-battery planning](docs/joint-site-planning.md)
> is opt-in and shadow-only. It never replaces the executable native plan.

![image](https://github.com/springfall2008/batpred/actions/workflows/code-quality.yml/badge.svg)
![image](https://github.com/springfall2008/batpred/actions/workflows/publish-docs.yml/badge.svg)
![image](https://github.com/springfall2008/batpred/actions/workflows/pages/pages-build-deployment/badge.svg)
Expand Down
1 change: 1 addition & 0 deletions apps/predbat/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,7 @@

# Apps.yaml validation schema
APPS_SCHEMA = {
"joint_site": {"type": "dict"},
"currency_symbols": {"type": "string|string_list"},
"db_enable": {"type": "boolean"},
"db_days": {"type": "integer"},
Expand Down
8 changes: 8 additions & 0 deletions apps/predbat/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,14 @@ def apply_inverter_rates(self, inverter, intent, notify_charge=True, notify_disc
inverter.adjust_discharge_rate(int(discharge_rate), notify=notify_discharge)

def execute_plan(self):
# Joint apply owns this cycle only after an explicit opt-in. It dispatches
# exact current intents through the same Inverter entry point, rather than
# allowing legacy window merging to erase hold/charge transitions.
from joint_site_apply import execute_joint_site

joint_status = execute_joint_site(self)
if joint_status is not None:
return joint_status
# Per-inverter detail segments, assembled into the status text after the headline status is
# resolved - see build_status_extra() for why they can't be concatenated inline.
status_extra_parts = []
Expand Down
4 changes: 3 additions & 1 deletion apps/predbat/ha.py
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,9 @@ def update_state_item(self, item, entity_id, nodb=False):
last_changed = item.get("last_changed", item.get("last_updated", None))
if "state" in item:
state = item["state"]
self.state_data[entity_id] = {"state": state, "attributes": attributes, "last_changed": last_changed}
# Preserve observation freshness separately from a state transition.
# An unchanged SOC may have a fresh device timestamp/attribute update.
self.state_data[entity_id] = {"state": state, "attributes": attributes, "last_changed": last_changed, "last_updated": item.get("last_updated", last_changed)}
if not nodb and self.db_enable and ((self.db_mirror_ha and (entity_id in self.db_mirror_list)) or self.db_primary):
# Instead of appending to a local mirror_updates list, call the database manager to schedule the update
if last_changed:
Expand Down
Loading