From 621dde24787bdb9a427655c3b42d42ef51ef9123 Mon Sep 17 00:00:00 2001 From: Trefor Southwell Date: Wed, 17 Jun 2026 21:51:51 +0100 Subject: [PATCH 1/2] Fix issue with ge cloud reset --- .claude/settings.json | 8 ++++++++ apps/predbat/gecloud.py | 16 ++-------------- apps/predbat/predbat.py | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) create mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..e69826427 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(git -C /Users/treforsouthwell/source/batpred diff HEAD -- apps/predbat/predbat.py)", + "Bash(python3 -c ' *)" + ] + } +} diff --git a/apps/predbat/gecloud.py b/apps/predbat/gecloud.py index 0ab287481..29334142d 100644 --- a/apps/predbat/gecloud.py +++ b/apps/predbat/gecloud.py @@ -616,10 +616,8 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) - return False if ("inverter_max_output_active_power_percent" in ha_name) or ("ac_charge_upper_percent_limit" in ha_name) or ("_upper_soc_percent_limit" in ha_name): if "enable_" in ha_name: continue @@ -630,10 +628,8 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) - return False if "charge_up_to_percent" in ha_name: if not value or value < 100: self.log("GECloud: Setting {} to 100% for {}, previous value was {}".format(ha_name, device, value)) @@ -641,10 +637,8 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) - return False if "discharge_down_to_percent" in ha_name: if not value or value > 4: self.log("GECloud: Setting {} to 4% for {}, previous value was {}".format(ha_name, device, value)) @@ -652,10 +646,8 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) - return False # Reset AC charge start and end times to 00:00 to disable for charge_id in range(2, 11): if ( @@ -670,25 +662,21 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) - return False if "real_time_control" in ha_name: if value: self.log("GECloud: Real-time control already enabled for {}".format(device)) - return True + continue else: self.log("GECloud: Enabling real-time control for {} as current value is {}".format(device, value)) result = await self.async_write_inverter_setting(device, key, True) if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) - return True else: self.log("GECloud: Warn: Failed to enable real-time control for {}".format(device)) - return False - return False + return True async def publish_registers(self, device, registers, select_key=None): """ diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index ebb3ded37..25a81e35a 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -36,7 +36,7 @@ import requests import asyncio -THIS_VERSION = "v8.40.10" +THIS_VERSION = "v8.40.11" from download import predbat_update_move, predbat_update_download, check_install, resolve_predbat_repository, DEFAULT_PREDBAT_REPOSITORY from const import MINUTE_WATT From 835be31c3340d984b10261254a74f5ddc99459fb Mon Sep 17 00:00:00 2001 From: Trefor Southwell Date: Wed, 17 Jun 2026 22:06:02 +0100 Subject: [PATCH 2/2] Fix tests --- apps/predbat/gecloud.py | 11 ++++++++++- apps/predbat/tests/test_ge_cloud.py | 13 +++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/predbat/gecloud.py b/apps/predbat/gecloud.py index 29334142d..b4ce3e640 100644 --- a/apps/predbat/gecloud.py +++ b/apps/predbat/gecloud.py @@ -604,6 +604,8 @@ async def publish_meter(self, device, meter): self.dashboard_item(entity_name + "_grid_export_total", state=meter[key][subkey].get("export", 0), attributes=attribute_table.get("grid_export_total", {}), app="gecloud") async def enable_default_options(self, device, registers): + """Enable default options for the device.""" + changed = False for key in registers: reg_name = registers[key].get("name", "") value = registers[key].get("value", None) @@ -616,6 +618,7 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) if ("inverter_max_output_active_power_percent" in ha_name) or ("ac_charge_upper_percent_limit" in ha_name) or ("_upper_soc_percent_limit" in ha_name): @@ -628,6 +631,7 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) if "charge_up_to_percent" in ha_name: @@ -637,6 +641,7 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) if "discharge_down_to_percent" in ha_name: @@ -646,6 +651,7 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) # Reset AC charge start and end times to 00:00 to disable @@ -662,11 +668,13 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to set {} for {}".format(ha_name, device)) if "real_time_control" in ha_name: if value: self.log("GECloud: Real-time control already enabled for {}".format(device)) + changed = True continue else: self.log("GECloud: Enabling real-time control for {} as current value is {}".format(device, value)) @@ -674,9 +682,10 @@ async def enable_default_options(self, device, registers): if result and ("value" in result): registers[key]["value"] = result["value"] await self.publish_registers(device, self.settings[device], select_key=key) + changed = True else: self.log("GECloud: Warn: Failed to enable real-time control for {}".format(device)) - return True + return changed async def publish_registers(self, device, registers, select_key=None): """ diff --git a/apps/predbat/tests/test_ge_cloud.py b/apps/predbat/tests/test_ge_cloud.py index f89d5ce9b..573911eae 100644 --- a/apps/predbat/tests/test_ge_cloud.py +++ b/apps/predbat/tests/test_ge_cloud.py @@ -3401,7 +3401,7 @@ async def mock_write_fail(device, key, value): print("ERROR: enable_default_options should return False when write fails") return 1 - # Test 10: Multiple settings - should process first match only + # Test 10: Multiple settings - should process all matching settings write_calls = [] registers = {100: {"name": "Export_SOC_Percent_Limit", "value": 10, "validation_rules": []}, 102: {"name": "AC_Charge_Upper_Percent_Limit", "value": 80, "validation_rules": []}} @@ -3410,14 +3410,11 @@ async def mock_write_fail(device, key, value): result = await ge_cloud.enable_default_options("test123", registers) if not result: - print("ERROR: enable_default_options should return True after processing first match") + print("ERROR: enable_default_options should return True after processing all matches") return 1 - # Should only process the first matching setting (export SOC limit) - if len(write_calls) != 1: - print("ERROR: Should only process first matching setting, got {} calls".format(len(write_calls))) - return 1 - if write_calls[0]["key"] != 100: - print("ERROR: Should process first setting (key 100), got key {}".format(write_calls[0]["key"])) + # Should process all matching settings + if len(write_calls) != 2: + print("ERROR: Should process all matching settings, got {} calls".format(len(write_calls))) return 1 # Test 11: AC charge slot 2 start time needs resetting