Skip to content

Commit 257acce

Browse files
Merge pull request #4288 from chalfontchubby/fix/simple-issues-batch
fix(web): use configured currency minor unit in Rates chart legend
2 parents 34dd554 + bd74c70 commit 257acce

2 files changed

Lines changed: 127 additions & 3 deletions

File tree

apps/predbat/inverter.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,10 +1492,23 @@ def update_status(self, minutes_now, quiet=False):
14921492
elif "charge_start_time" in self.base.args:
14931493
charge_start_time = time_string_to_stamp(self.base.get_arg("charge_start_time", index=self.id))
14941494
charge_end_time = time_string_to_stamp(self.base.get_arg("charge_end_time", index=self.id))
1495+
elif self.rest_api:
1496+
# A REST data source (givtcp_rest) is configured but hasn't returned anything this
1497+
# cycle - genuinely transient (a fetch hiccup, or before the first poll on a fresh
1498+
# start, e.g. GivEnergy cloud "no devices"), so fall through to the same safe-defaults/
1499+
# retry-next-update handling below as a configured-but-currently-unusable value,
1500+
# rather than crashing the whole plan for something that should resolve itself.
1501+
charge_start_time = None
1502+
charge_end_time = None
14951503
else:
1496-
self.log("Error: Inverter {} unable to read charge window time as neither REST, charge_start_time or charge_start_hour are set".format(self.id))
1497-
self.base.record_status("Error: Inverter {} unable to read charge window time as neither REST, charge_start_time or charge_start_hour are set".format(self.id), had_errors=True)
1498-
raise ValueError
1504+
# Neither a REST API nor a charge_start_time config value is configured at all - a
1505+
# permanent setup gap, not something that will resolve on its own. Retrying every
1506+
# cycle forever would be misleading, so don't pretend to make a plan Predbat can't
1507+
# actually deliver (maintainer call on #4288/#4179 - see PR review discussion).
1508+
message = "Error: Inverter {} unable to read charge window time as neither REST, charge_start_time or charge_start_hour are set".format(self.id)
1509+
self.log(message)
1510+
self.base.record_status(message, had_errors=True)
1511+
raise ValueError(message)
14991512

15001513
if charge_start_time is None or charge_end_time is None:
15011514
self.log("Warn: Inverter {} unable to read charge window time as charge_start_time or charge_end_time is None, will retry next update".format(self.id))

apps/predbat/tests/test_inverter.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,109 @@ def test_charge_window_none_value(test_name, my_predbat, dummy_items):
14441444
return failed
14451445

14461446

1447+
def test_charge_window_no_source_configured(test_name, my_predbat, dummy_items):
1448+
"""
1449+
Test charge window handling when neither a REST API (givtcp_rest) nor a charge_start_time/
1450+
charge_end_time config source is configured at all (issue #4179 / PR #4288 review). This is a
1451+
permanent setup gap, not a transient one, so update_status() should raise a clear, informative
1452+
ValueError (unlike the original bare `raise ValueError` with no message) rather than silently
1453+
retrying forever on a config gap that will never close itself - maintainer call on #4288.
1454+
"""
1455+
failed = False
1456+
print(f"**** Running Test: {test_name} ****")
1457+
1458+
inv = Inverter(my_predbat, 0)
1459+
inv.sleep = dummy_sleep
1460+
inv.inv_has_charge_enable_time = True
1461+
inv.rest_api = None
1462+
inv.rest_data = None
1463+
1464+
# Remove charge_start_time/charge_end_time from config entirely, so neither the REST nor the
1465+
# config-arg branch can produce a value
1466+
original_charge_start_time = my_predbat.args.pop("charge_start_time", None)
1467+
original_charge_end_time = my_predbat.args.pop("charge_end_time", None)
1468+
dummy_items["switch.scheduled_charge_enable"] = "on"
1469+
1470+
try:
1471+
inv.update_status(my_predbat.minutes_now)
1472+
print(f"ERROR: {test_name} - update_status should raise ValueError when no charge window source is configured at all")
1473+
failed = True
1474+
except ValueError as e:
1475+
if "neither REST, charge_start_time or charge_start_hour are set" not in str(e):
1476+
print(f"ERROR: {test_name} - ValueError message should explain the cause, got: {e}")
1477+
failed = True
1478+
if "Error: Inverter" not in my_predbat.current_status:
1479+
print(f"ERROR: {test_name} - current_status should reflect the error, got: {my_predbat.current_status}")
1480+
failed = True
1481+
finally:
1482+
# Restore config so this doesn't affect later tests
1483+
if original_charge_start_time is not None:
1484+
my_predbat.args["charge_start_time"] = original_charge_start_time
1485+
if original_charge_end_time is not None:
1486+
my_predbat.args["charge_end_time"] = original_charge_end_time
1487+
1488+
return failed
1489+
1490+
1491+
def test_charge_window_rest_configured_but_no_data_yet(test_name, my_predbat, dummy_items):
1492+
"""
1493+
Test charge window handling when a REST API (givtcp_rest) *is* configured but rest_data hasn't
1494+
successfully returned anything yet this cycle (issue #4179's actual production trigger -
1495+
GivEnergy cloud "no devices" or a fresh start before the first poll). Unlike the "nothing
1496+
configured at all" case above, this is genuinely transient - the data source is legitimate, it
1497+
just hasn't produced a value yet - so it should fall through to the same safe-defaults/
1498+
retry-next-update handling as a configured-but-currently-unusable value, not raise.
1499+
"""
1500+
failed = False
1501+
print(f"**** Running Test: {test_name} ****")
1502+
1503+
inv = Inverter(my_predbat, 0)
1504+
inv.sleep = dummy_sleep
1505+
inv.inv_has_charge_enable_time = True
1506+
inv.rest_api = "http://givtcp:6345"
1507+
inv.rest_data = None
1508+
1509+
original_charge_start_time = my_predbat.args.pop("charge_start_time", None)
1510+
original_charge_end_time = my_predbat.args.pop("charge_end_time", None)
1511+
dummy_items["switch.scheduled_charge_enable"] = "on"
1512+
1513+
try:
1514+
inv.update_status(my_predbat.minutes_now)
1515+
except ValueError as e:
1516+
print(f"ERROR: {test_name} - update_status should not raise while a configured REST source just hasn't returned data yet, got ValueError({e})")
1517+
failed = True
1518+
if original_charge_start_time is not None:
1519+
my_predbat.args["charge_start_time"] = original_charge_start_time
1520+
if original_charge_end_time is not None:
1521+
my_predbat.args["charge_end_time"] = original_charge_end_time
1522+
return failed
1523+
1524+
# Should set the same safe defaults as the "value is None" case
1525+
if inv.charge_enable_time != False:
1526+
print(f"ERROR: {test_name} - charge_enable_time should be False, got {inv.charge_enable_time}")
1527+
failed = True
1528+
if inv.charge_start_time_minutes != my_predbat.forecast_minutes:
1529+
print(f"ERROR: {test_name} - charge_start_time_minutes should be {my_predbat.forecast_minutes}, got {inv.charge_start_time_minutes}")
1530+
failed = True
1531+
if inv.charge_end_time_minutes != my_predbat.forecast_minutes:
1532+
print(f"ERROR: {test_name} - charge_end_time_minutes should be {my_predbat.forecast_minutes}, got {inv.charge_end_time_minutes}")
1533+
failed = True
1534+
if inv.track_charge_start != "00:00:00":
1535+
print(f"ERROR: {test_name} - track_charge_start should be '00:00:00', got {inv.track_charge_start}")
1536+
failed = True
1537+
if inv.track_charge_end != "00:00:00":
1538+
print(f"ERROR: {test_name} - track_charge_end should be '00:00:00', got {inv.track_charge_end}")
1539+
failed = True
1540+
1541+
# Restore config for later tests
1542+
if original_charge_start_time is not None:
1543+
my_predbat.args["charge_start_time"] = original_charge_start_time
1544+
if original_charge_end_time is not None:
1545+
my_predbat.args["charge_end_time"] = original_charge_end_time
1546+
1547+
return failed
1548+
1549+
14471550
def test_discharge_window_none_illegal_time(test_name, my_predbat, dummy_items):
14481551
"""
14491552
Test discharge window handling when time is illegal (e.g., 'unknown')
@@ -3175,6 +3278,14 @@ def run_inverter_tests(my_predbat_dummy):
31753278
if failed:
31763279
return failed
31773280

3281+
failed |= test_charge_window_no_source_configured("charge_window_no_source_configured", my_predbat, dummy_items)
3282+
if failed:
3283+
return failed
3284+
3285+
failed |= test_charge_window_rest_configured_but_no_data_yet("charge_window_rest_configured_but_no_data_yet", my_predbat, dummy_items)
3286+
if failed:
3287+
return failed
3288+
31783289
# Test discharge window None handling
31793290
failed |= test_discharge_window_none_illegal_time("discharge_window_illegal_time", my_predbat, dummy_items)
31803291
if failed:

0 commit comments

Comments
 (0)