Skip to content
38 changes: 24 additions & 14 deletions apps/predbat/inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1985,8 +1985,9 @@ def adjust_force_export(self, force_export, new_start_time=None, new_end_time=No
self.write_and_poll_switch("scheduled_discharge_enable", self.base.get_arg("scheduled_discharge_enable", indirect=False, index=self.id), True)
self.log("Inverter {} Turning on scheduled export".format(self.id))

if ((new_end != old_end) or (new_start != old_start) or (force_export != old_discharge_enable)) and self.inv_time_button_press:
self.press_and_poll_button()
if (new_end != old_end) or (new_start != old_start) or (force_export != old_discharge_enable):
if self.inv_time_button_press:
self.press_and_poll_button()

# Force export, turn it on after we change the window
if force_export:
Expand Down Expand Up @@ -2050,9 +2051,13 @@ def disable_charge_window(self, notify=True):

self.base.log("Inverter {} Turning off scheduled charge".format(self.id))

# Reset charge window to midnight if there is no charge enable time
if not self.inv_has_charge_enable_time:
self.adjust_charge_window(self.base.midnight_utc, self.base.midnight_utc, self.base.minutes_now)
# Reset charge window to midnight if there is no charge enable time
if not self.inv_has_charge_enable_time:
self.adjust_charge_window(self.base.midnight_utc, self.base.midnight_utc, self.base.minutes_now)
else:
# Press button if needed
if self.inv_time_button_press:
self.press_and_poll_button()

# Updated cached status to disabled
self.charge_enable_time = False
Expand Down Expand Up @@ -2306,6 +2311,11 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now):
old_charge_schedule_enable = self.base.get_arg("scheduled_charge_enable", "on", index=self.id)
else:
self.log("Warn: Inverter {} unable read charge window as neither REST or discharge_start_time".format(self.id))
old_charge_schedule_enable = "off"

# Normalize old charge schedule enable
if old_charge_schedule_enable in ["off", "disable"]:
old_charge_schedule_enable = "off"
Comment on lines +2317 to +2318

Copilot AI Nov 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The normalization only handles 'off' and 'disable' but doesn't handle other possible values like 'enable' or 'on'. Consider adding an else clause to normalize 'enable'/'on' to a consistent 'on' value, or documenting the expected values to ensure robust handling across different states.

Suggested change
if old_charge_schedule_enable in ["off", "disable"]:
old_charge_schedule_enable = "off"
if str(old_charge_schedule_enable).lower() in ["off", "disable"]:
old_charge_schedule_enable = "off"
elif str(old_charge_schedule_enable).lower() in ["on", "enable"]:
old_charge_schedule_enable = "on"

Copilot uses AI. Check for mistakes.

# Apply clock skew
charge_start_time += timedelta(seconds=self.base.inverter_clock_skew_start * 60)
Expand Down Expand Up @@ -2379,8 +2389,8 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now):
self.base.call_notify("Predbat: Inverter {} Charge window change to: {} - {} at {}".format(self.id, new_start, new_end, self.base.time_now_str()))
self.base.log("Inverter {} Updated start and end charge window to {} - {} (old {} - {})".format(self.id, new_start, new_end, old_start, old_end))

if old_charge_schedule_enable == "off" or old_charge_schedule_enable == "disable" or have_disabled:
# Enable scheduled charge if not turned on
if (old_charge_schedule_enable == "off" or have_disabled) and (new_start != new_end):
# Enable scheduled charge if not turned on, unless the start and end are the same (disabled)
if self.rest_data:
self.rest_enableChargeSchedule(True)
elif "scheduled_charge_enable" in self.base.args:
Expand All @@ -2391,20 +2401,20 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now):
else:
self.log("Warn: Inverter {} unable write charge window enable as neither REST or scheduled_charge_enable are set".format(self.id))

if new_start != old_start or new_end != old_end or (self.inv_charge_time_format in ["H M", "H:M-H:M"]):
# For Solis inverters and fox we also have to press the update_charge_discharge button to send the times to the inverter
if self.inv_time_button_press:
self.press_and_poll_button()

# Only notify if it's a real change and not a temporary one
if (old_charge_schedule_enable == "off" or old_charge_schedule_enable == "disable") and self.base.set_inverter_notify:
if old_charge_schedule_enable == "off" and self.base.set_inverter_notify:
self.base.call_notify("Predbat: Inverter {} Enabling scheduled charging at {}".format(self.id, self.base.time_now_str()))

self.charge_enable_time = True

if old_charge_schedule_enable == "off" or old_charge_schedule_enable == "disable":
if old_charge_schedule_enable == "off":
self.base.log("Inverter {} Turning on scheduled charge".format(self.id))

if (new_start != old_start) or (new_end != old_end) or (old_charge_schedule_enable == "off"):
# For Solis inverters and fox we also have to press the update_charge_discharge button to send the times to the inverter
if self.inv_time_button_press:
self.press_and_poll_button()

def press_and_poll_button(self):
"""
Press charge/discharge update button(s) for the inverter.
Expand Down
2 changes: 1 addition & 1 deletion apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import requests
import asyncio

THIS_VERSION = "v8.27.1"
THIS_VERSION = "v8.27.2"

# fmt: off
PREDBAT_FILES = ["predbat.py", "config.py", "prediction.py", "gecloud.py","utils.py", "inverter.py", "ha.py", "download.py", "unit_test.py", "web.py", "web_helper.py", "predheat.py", "futurerate.py", "octopus.py", "solcast.py","execute.py", "plan.py", "fetch.py", "output.py", "userinterface.py", "energydataservice.py", "alertfeed.py", "compare.py", "db_manager.py", "db_engine.py", "plugin_system.py", "ohme.py", "components.py", "fox.py", "carbon.py", "web_mcp.py"]
Expand Down
Loading