Skip to content

Commit df09bc4

Browse files
Improve fox stability, force re-compute after dynamic load detection change (#2728)
* Improve fox stability Force re-compute after dynamic load detection change * Update customisation.md
1 parent a787689 commit df09bc4

4 files changed

Lines changed: 23 additions & 7 deletions

File tree

‎apps/predbat/fox.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
FOX_DOMAIN = "https://www.foxesscloud.com"
2727
FOX_LANG = "en"
2828
TIMEOUT = 60
29+
FOX_RETRIES = 10
2930
FOX_SETTINGS = ["ExportLimit", "MaxSoc", "GridCode", "WorkMode", "ExportLimitPower", "MinSoc", "MinSocOnGrid"]
3031
OPTIONS_WORK_MODE = ["SelfUse", "ForceCharge", "ForceDischarge", "Feedin"]
3132

@@ -130,7 +131,6 @@ async def start(self):
130131
await asyncio.sleep(1)
131132
count_seconds += 1
132133

133-
await self.client.close()
134134
print("Fox API: Stopped")
135135

136136
async def stop(self):
@@ -737,7 +737,7 @@ async def request_get(self, path, post=False, datain=None):
737737
Retry wrapper
738738
"""
739739
retries = 0
740-
while retries < 5:
740+
while retries < FOX_RETRIES:
741741
result = await self.request_get_func(path, post=post, datain=datain)
742742
if result is not None:
743743
return result
@@ -780,7 +780,7 @@ async def request_get_func(self, path, post=False, datain=None):
780780
msg = data.get("msg", "")
781781
if errno != 0:
782782
self.failures_total += 1
783-
if errno == 40400:
783+
if errno in [40400, 41200, 41203, 41935]:
784784
# Rate limiting so wait up to 10 seconds
785785
self.log("Fox: Rate limiting detected, waiting...")
786786
await asyncio.sleep(random.random() * 10 + 1)

‎apps/predbat/plan.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ def get(self):
3737

3838
class Plan:
3939
def dynamic_load(self):
40+
"""
41+
Adjust load prediction based on current load
42+
Return True if load status has changed and hence we need to re-plan
43+
"""
44+
prev_last_load_status = self.load_last_status
4045
# Last period load analysis
4146
self.load_last_status = "baseline"
4247
if self.load_last_period > self.battery_rate_max_discharge * MINUTE_WATT / 1000:
@@ -74,6 +79,9 @@ def dynamic_load(self):
7479
self.log("Dynamic load adjust is setting load minimum {:.2f}kW at {}".format(load_last_period, self.time_abs_str(minute_absolute)))
7580
have_printed = True
7681
self.dynamic_load_baseline[minute_absolute] = load_last_period
82+
if prev_last_load_status != self.load_last_status:
83+
return True
84+
return False
7785

7886
def find_price_levels(
7987
self,

‎apps/predbat/predbat.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
import requests
3737
import asyncio
3838

39-
THIS_VERSION = "v8.25.4"
39+
THIS_VERSION = "v8.25.5"
4040

4141
# fmt: off
4242
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"]
@@ -667,6 +667,7 @@ def update_pred(self, scheduled=True):
667667
"""
668668
Update the prediction state, everything is called from here right now
669669
"""
670+
recompute = False
670671
status_extra = ""
671672
self.had_errors = False
672673
self.dashboard_index = []
@@ -686,10 +687,11 @@ def update_pred(self, scheduled=True):
686687
self.fetch_config_options()
687688
self.fetch_sensor_data()
688689
self.fetch_inverter_data()
689-
self.dynamic_load()
690+
if self.dynamic_load():
691+
self.log("Dynamic load adjustment changed, will recompute the plan")
692+
recompute = True
690693

691-
recompute = False
692-
if not scheduled or not self.plan_valid:
694+
if not scheduled or not self.plan_valid or recompute:
693695
self.log("Will recompute the plan as it is invalid")
694696
recompute = True
695697
else:

‎docs/customisation.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ impact the real calculated costs and is only used for plan selection. Values of
144144

145145
## Scaling and weight options
146146

147+
**switch.predbat_metric_dynamic_load_adjust** is a toggle that when enabled allows Predbat to take into account your energy consumption within the last 5 minutes.
148+
If the load is above what your battery can deliver the plan is updated to predict this load will continue during the current 30-minute period, this preventing
149+
and type of forced export in the plan.
150+
If car charging is planned but the load indicates that the car is not charging then Predbat will assume the car will no longer charge during this 30-minute period
151+
thus allowing the plan to include potential export.
152+
147153
**input_number.predbat_battery_rate_max_scaling** is a percentage factor to adjust your maximum charge rate from that reported by the inverter.
148154
For example, a value of 0.95 would be 95% and indicate charging at 5% slower than reported. For GE inverters the charge rate reports the max
149155
AC rate and thus needs to be reduced by inverter losses.

0 commit comments

Comments
 (0)