Skip to content

Commit f55c289

Browse files
fix(octopus): keep a charger's planned slots from octopus_intelligent_planned_slot while Smart Control is off (#5339)
Since the merge with main, a car's planned dispatches can come from octopus_intelligent_planned_slot (#5443) rather than the Octopus dispatch sensor. Those are the charger's own plan, not the plan Octopus keeps reporting after Smart Control is switched off, so the Smart Control filter no longer applies to them. Before this, a charger whose sensor does not tag its slots as the charger's schedule lost every planned slot while the switch was off. The Ohme component already tags its slots that way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 99065fa commit f55c289

3 files changed

Lines changed: 18 additions & 3 deletions

File tree

‎apps/predbat/fetch.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,7 @@ def fetch_sensor_data_cars(self, save=True):
18461846
completed = []
18471847
planned = []
18481848
started = []
1849+
planned_entity_id = None
18491850

18501851
if entity_id and "octopus_intelligent_slot_action_config" in self.args:
18511852
config_entry = self.get_arg("octopus_intelligent_slot_action_config", None, indirect=False)
@@ -1889,9 +1890,10 @@ def fetch_sensor_data_cars(self, save=True):
18891890
# Octopus keeps returning the plan it made before Smart Control was switched off, but nothing will act
18901891
# on it (#5339). Slots already delivered (completed) are real, so those are still counted above, as are
18911892
# the manual bump/boost charges the user asked for themselves. So is a charger's own schedule: the Ohme
1892-
# component wires that in when Octopus no longer drives the charger, and Smart Control has no say in it
1893+
# component wires that in when Octopus no longer drives the charger, and Smart Control has no say in it.
1894+
# Planned slots taken from octopus_intelligent_planned_slot are the charger's own plan too, not Octopus's
18931895
planned_used = planned
1894-
if self.octopus_smart_control_off(car_n, save=save):
1896+
if not planned_entity_id and self.octopus_smart_control_off(car_n, save=save):
18951897
planned_used = [slot for slot in (planned or []) if isinstance(slot, dict) and (slot.get("source") or (slot.get("meta") or {}).get("source")) in OCTOPUS_MANUAL_DISPATCH_SOURCES + (DISPATCH_SOURCE_CHARGER_SCHEDULE,)]
18961898
if planned_used and (not self.octopus_intelligent_ignore_unplugged or self.car_charging_planned[car_n] or self.car_charging_now[car_n]):
18971899
# We only count planned slots if the car is plugged in or we are ignoring unplugged cars. A car

‎apps/predbat/tests/test_octopus_smart_control.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"car_charging_loss",
4848
"car_charging_limit_model",
4949
)
50-
ARG_KEYS = ("car_charging_loss", "car_charging_soc", "car_charging_limit", "octopus_intelligent_slot", "octopus_intelligent_smart_control")
50+
ARG_KEYS = ("car_charging_loss", "car_charging_soc", "car_charging_limit", "octopus_intelligent_slot", "octopus_intelligent_smart_control", "octopus_intelligent_planned_slot")
5151

5252

5353
def _setup(my_predbat):
@@ -205,6 +205,18 @@ def run_octopus_smart_control_tests(my_predbat):
205205
failed |= _check("t10b schedule kept", kwh == [5.0, 10.0], "kwh {}".format(kwh))
206206
_setup(my_predbat)
207207

208+
print("Test 10c: planned slots from octopus_intelligent_planned_slot are the charger's own, so are kept while Smart Control is off")
209+
attributes = copy.deepcopy(items[SLOT_SENSOR])
210+
attributes["planned_dispatches"][0]["charge_in_kwh"] = 7.0
211+
attributes["completed_dispatches"] = []
212+
my_predbat.ha_interface.set_state(CUSTOM_SENSOR, "off", attributes=attributes)
213+
my_predbat.args["octopus_intelligent_planned_slot"] = CUSTOM_SENSOR
214+
items[SWITCH] = "off"
215+
kwh = _slots(my_predbat)
216+
failed |= _check("t10c charger plan kept", kwh == [5.0, 7.0], "kwh {}".format(kwh))
217+
my_predbat.args.pop("octopus_intelligent_planned_slot", None)
218+
_setup(my_predbat)
219+
208220
print("Test 11: the state is case-insensitive, and an odd state string is no evidence")
209221
my_predbat.args["octopus_intelligent_slot"] = SLOT_SENSOR
210222
items[SWITCH] = "OFF"

‎docs/car-charging.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ It holds the entity ID of the switch, not a value, so Predbat follows the switch
149149
If you set up `apps.yaml` before this item existed, add it to pick up the change. If the switch cannot be found, planned slots are used as normal.
150150
If `octopus_intelligent_slot` points at your charger's own integration (for example Ohme) rather than the Octopus Energy integration, comment out `octopus_intelligent_smart_control`,
151151
otherwise the charger's own planned slots are ignored whenever Octopus Smart Control is off.
152+
Planned slots taken from **octopus_intelligent_planned_slot** are the charger's own plan rather than Octopus's, so they are still used while Smart Control is off.
152153
For **multiple IOG-enrolled vehicles**, set this to a list with one switch per car.
153154

154155
- **octopus_intelligent_planned_slot** - Optional, see [Taking planned slots from another sensor](#taking-planned-slots-from-another-sensor).

0 commit comments

Comments
 (0)