Skip to content

Commit f052cd5

Browse files
CIclaude
andcommitted
fix(gecloud): parse the integer rating of 3-phase hybrid models (GIV-3HY-11) instead of falling back to max_charge_rate
Fixes #5136 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent d951201 commit f052cd5

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

‎apps/predbat/gecloud.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ def initialize(self, ge_cloud_direct, api_key, automatic, automatic_evc=False, e
609609
self.ems_slot_warned = set()
610610
# (device, key) registers whose option validation text could not be parsed, so the warning is logged once
611611
self.validation_parse_warned = set()
612+
# Hybrid model names whose inverter rating could not be parsed, so the fallback warning is logged once
613+
self.model_rate_warned = set()
612614
self.devices_dict = {}
613615
self.device_list = []
614616
self.ems_device = None
@@ -910,6 +912,8 @@ def get_max_inverter_rate_from_model(self, model, max_charge_rate=None):
910912
- GIV-HY3.6 - 3.6kW inverter
911913
- GIV-HY5.0 - 5.0kW inverter
912914
- GIV-HY-8.0-G3-HV. - 8kW inverter
915+
- GIV-3HY-11 - 11kW 3-phase hybrid (integer rating as its own segment after 3HY)
916+
- GIV-AIO-GW2 - Gateway variant, the trailing 2 is not a rating
913917
- Plant EMS - Not an inverter, should use the individual inverter values
914918
"""
915919

@@ -922,6 +926,17 @@ def get_max_inverter_rate_from_model(self, model, max_charge_rate=None):
922926
return max_inverter_rate
923927
except ValueError:
924928
pass
929+
930+
# Integer rating only as a whole segment straight after the 3-phase hybrid token (GIV-3HY-11),
931+
# bounded by '-' or end of string so suffixes such as GW2 / G3 are never read as a rating
932+
match = re.search(r"(?:^|-)3HY-(\d{1,2})(?=-|$)", model, re.IGNORECASE)
933+
if match:
934+
return int(match.group(1)) * 1000
935+
936+
# A hybrid with no parseable rating is using a battery rate as its AC rating, warn once per model
937+
if "HY" in model.upper() and model not in self.model_rate_warned:
938+
self.log("GECloud: Warn: Unable to determine inverter rating from model '{}', using max charge rate {}W instead - set inverter_limit in apps.yaml if this is wrong".format(model, max_charge_rate))
939+
self.model_rate_warned.add(model)
925940
return max_charge_rate
926941

927942
async def publish_account(self, account):

‎apps/predbat/tests/test_ge_cloud.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def __init__(self):
7575
self.gateway_device = None
7676
self.ems_slot_warned = set()
7777
self.validation_parse_warned = set()
78+
self.model_rate_warned = set()
7879
self._discovery_report = None
7980
self._now_utc_exact = datetime.now(timezone.utc)
8081
self.settings_from_cache = False
@@ -7521,6 +7522,16 @@ def _test_get_max_inverter_rate_from_model(my_predbat):
75217522
("Plant EMS", None, None, "Plant EMS => None (no number)"),
75227523
# No number, but max_charge_rate provided as fallback
75237524
("Gateway", 2600, 2600, "Gateway => fallback to max_charge_rate"),
7525+
# 3-phase hybrid carries an integer rating as its own segment after 3HY (GH#5136)
7526+
("GIV-3HY-11", 9984, 11000, "GIV-3HY-11 => 11kW, not the 9984W battery rate"),
7527+
("GIV-3HY-8", 7987, 8000, "GIV-3HY-8 => 8kW"),
7528+
("giv-3hy-5", 4000, 5000, "giv-3hy-5 => 5kW (case-insensitive)"),
7529+
# Integer suffixes that are not ratings keep the fallback
7530+
("GIV-AIO-GW2", 2600, 2600, "GIV-AIO-GW2 => fallback, GW2 is not a rating"),
7531+
("GIV-3HY-G3", 9984, 9984, "GIV-3HY-G3 => fallback, G3 is not a rating"),
7532+
("GIV-3HY-110", 9984, 9984, "GIV-3HY-110 => fallback, three digits is not a plausible rating"),
7533+
# Decimal pass still wins over the 3HY integer pass
7534+
("ALPS HY-6.0-GL", 3600, 6000, "ALPS HY-6.0-GL => 6kW"),
75247535
]
75257536

75267537
failed = 0
@@ -7533,6 +7544,20 @@ def _test_get_max_inverter_rate_from_model(my_predbat):
75337544
else:
75347545
print("OK {}: got {}".format(description, result))
75357546

7547+
# A hybrid model that cannot be parsed warns once per model, non-hybrids stay silent
7548+
ge_cloud.model_rate_warned = set()
7549+
ge_cloud.log_messages = []
7550+
ge_cloud.get_max_inverter_rate_from_model("GIV-HYX", 2600)
7551+
ge_cloud.get_max_inverter_rate_from_model("GIV-HYX", 2600)
7552+
ge_cloud.get_max_inverter_rate_from_model("Gateway", 2600)
7553+
ge_cloud.get_max_inverter_rate_from_model("GIV-3HY-11", 9984)
7554+
warnings = [message for message in ge_cloud.log_messages if "Unable to determine inverter rating" in message]
7555+
if len(warnings) != 1 or "GIV-HYX" not in warnings[0]:
7556+
print("ERROR expected exactly one fallback warning naming GIV-HYX, got {}".format(warnings))
7557+
failed += 1
7558+
else:
7559+
print("OK unparsed hybrid model warns once")
7560+
75367561
return 1 if failed else 0
75377562

75387563

0 commit comments

Comments
 (0)