From 094914de6589ff55ee5c6229d6ec0ae276d559af Mon Sep 17 00:00:00 2001 From: Francois Fernando Date: Fri, 19 Dec 2025 14:20:24 +1100 Subject: [PATCH 1/5] Support for operating in reduced API calls mode --- custom_components/foxess/__init__.py | 2 +- custom_components/foxess/manifest.json | 10 +++--- custom_components/foxess/sensor.py | 47 +++++++++++++++++++++----- hacs.json | 2 +- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/custom_components/foxess/__init__.py b/custom_components/foxess/__init__.py index a514572..8ff7621 100644 --- a/custom_components/foxess/__init__.py +++ b/custom_components/foxess/__init__.py @@ -1 +1 @@ -"""The Foxess cloud integration.""" \ No newline at end of file +"""The Foxess cloud integration with reduced api calls.""" \ No newline at end of file diff --git a/custom_components/foxess/manifest.json b/custom_components/foxess/manifest.json index 237de52..fc055c0 100644 --- a/custom_components/foxess/manifest.json +++ b/custom_components/foxess/manifest.json @@ -1,11 +1,11 @@ { "domain": "foxess", - "name": "HA & FoxESSCloud integration", - "codeowners": ["@macxq","@r-amado","@fozzieuk"], + "name": "HA & FoxESSCloud integration - Reduced API calls", + "codeowners": ["@francoisfernando"], "dependencies": ["rest"], - "documentation": "https://github.com/macxq/foxess-ha", + "documentation": "https://github.com/francoisfernando/foxess-ha", "iot_class": "local_polling", - "issue_tracker":"https://github.com/macxq/foxess-ha/issues", + "issue_tracker":"https://github.com/francoisfernando/foxess-ha", "requirements": ["random_user_agent"], - "version": "v0.4" + "version": "v0.5" } diff --git a/custom_components/foxess/sensor.py b/custom_components/foxess/sensor.py index debe517..481773f 100644 --- a/custom_components/foxess/sensor.py +++ b/custom_components/foxess/sensor.py @@ -89,6 +89,7 @@ CONF_GET_VARIABLES = "Restrict" CONF_V1_API = "Use_V1_Api" CONF_EVO = "Evo" +CONF_REDUCE_API_CALLS = "reduceAPICalls" RETRY_NEXT_SLOT = -1 RETRY_IN_5_MINS = 25 DNS_ERROR = 101 @@ -112,15 +113,40 @@ vol.Optional(CONF_GET_VARIABLES): cv.boolean, vol.Optional(CONF_V1_API): cv.boolean, vol.Optional(CONF_EVO): cv.boolean, + vol.Optional(CONF_REDUCE_API_CALLS, default=True): cv.boolean, } ) token = None +class ApiCallController: + def __init__(self, reduce_api_calls: bool = False): + self.reduce_api_calls = reduce_api_calls + self.api_call_count = 0 + + def should_do_main_poll(self, tslice: int) -> bool: + return tslice % 10 == 0 if self.reduce_api_calls else tslice % 5 == 0 + + def should_get_device_detail(self, tslice: int) -> bool: + return tslice == 0 if self.reduce_api_calls else tslice % 15 == 0 + + def should_get_battery_settings(self, tslice: int) -> bool: + return tslice == 0 + + def should_get_daily_generation(self, tslice: int) -> bool: + return tslice == 0 + + def should_get_monthly_report(self, tslice: int) -> bool: + return tslice == 0 if self.reduce_api_calls else tslice % 15 == 0 + + def increment_api_call_count(self): + self.api_call_count += 1 + + async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the FoxESS sensor.""" - global LastHour, timeslice, last_api, RestrictGetVar, xtzone, V1_Api, Evo + global LastHour, timeslice, last_api, RestrictGetVar, xtzone, V1_Api, Evo, callController Evo = False name = config.get(CONF_NAME) deviceID = config.get(CONF_DEVICEID) @@ -131,6 +157,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= RestrictGetVar = config.get(CONF_GET_VARIABLES) V1_Api = config.get(CONF_V1_API) Evo = config.get(CONF_EVO) + ReduceApiCalls = config.get(CONF_REDUCE_API_CALLS) + callController = ApiCallController(reduce_api_calls=ReduceApiCalls) _LOGGER.debug("API Key: %s", apiKey) _LOGGER.debug("Device SN: %s", devicesn) _LOGGER.debug("Device ID: %s", deviceID) @@ -169,16 +197,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= async def async_update_data(): _LOGGER.debug("Updating data from https://www.foxesscloud.com/") - global token, timeslice, LastHour + global token, timeslice, LastHour, callController hournow = datetime.now().strftime("%H") # update hour now _LOGGER.debug("Time now: %s, last %s", hournow, LastHour) tslice = timeslice[devicesn] + 1 # increment current device time slice timeslice[devicesn] = tslice - if tslice % 5 == 0: + if callController.should_do_main_poll(tslice): _LOGGER.debug("Main Poll, interval: %s, %s", devicesn, timeslice[devicesn]) # try the openapi see if we get a response geterror = False - if tslice % 15 == 0: + if callController.should_get_device_detail(tslice): # get device detail at startup, then every 15 minutes to save api calls if Evo: # Evo not currently in device detail, use list and fill partial blanks @@ -196,18 +224,18 @@ async def async_update_data(): _LOGGER.debug(" Statetest %s", statetest) if statetest in [1, 2]: allData["online"] = True - if tslice == 0: + if callController.should_get_battery_settings(tslice): # read in battery settings if fitted at startup, then every 60 mins await getOABatterySettings(hass, allData, devicesn, apiKey) await asyncio.sleep(1) # OpenAPI demand # main real time data fetch, followed by reports geterror = await getRaw(hass, allData, apiKey, devicesn) if not geterror: - if tslice % 15 == 0: # do at startup and every 15 minutes + if callController.should_get_monthly_report(tslice): # do at startup and every 15 minutes await asyncio.sleep(1) # OpenAPI demand limit geterror = await getReport(hass, allData, apiKey, devicesn) if not geterror: - if tslice == 0: + if callController.should_get_daily_generation(tslice): # get daily generation at startup, then every 60 minutes await asyncio.sleep(1) # OpenAPI demand geterror = await getReportDailyGeneration(hass, allData, apiKey, devicesn) @@ -734,7 +762,7 @@ def md5c(text="", _type="lower"): async def waitforAPI(): - global last_api + global last_api, callController # wait for openAPI, there is a minimum of 1 second allowed between OpenAPI query calls # check if last_api call was less than a second ago and if so delay the balance of 1 second now = time.time() @@ -746,6 +774,9 @@ async def waitforAPI(): _LOGGER.debug("API enforced delay, wait: %s", diff) now = time.time() last_api = now + + callController.increment_api_call_count() + return False diff --git a/hacs.json b/hacs.json index b7425f5..67081fb 100644 --- a/hacs.json +++ b/hacs.json @@ -1,3 +1,3 @@ { - "name": "FoxESS Cloud" + "name": "FoxESS Cloud Reduced API Calls", } From 25634961f2a8aea3304bff45ec82308c2b1c5474 Mon Sep 17 00:00:00 2001 From: Francois Fernando Date: Fri, 19 Dec 2025 14:30:11 +1100 Subject: [PATCH 2/5] Update package --- custom_components/{foxess => foxess_light}/__init__.py | 0 custom_components/{foxess => foxess_light}/manifest.json | 2 +- custom_components/{foxess => foxess_light}/sensor.py | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename custom_components/{foxess => foxess_light}/__init__.py (100%) rename custom_components/{foxess => foxess_light}/manifest.json (92%) rename custom_components/{foxess => foxess_light}/sensor.py (100%) diff --git a/custom_components/foxess/__init__.py b/custom_components/foxess_light/__init__.py similarity index 100% rename from custom_components/foxess/__init__.py rename to custom_components/foxess_light/__init__.py diff --git a/custom_components/foxess/manifest.json b/custom_components/foxess_light/manifest.json similarity index 92% rename from custom_components/foxess/manifest.json rename to custom_components/foxess_light/manifest.json index fc055c0..eb4d1f2 100644 --- a/custom_components/foxess/manifest.json +++ b/custom_components/foxess_light/manifest.json @@ -1,5 +1,5 @@ { - "domain": "foxess", + "domain": "foxess_light", "name": "HA & FoxESSCloud integration - Reduced API calls", "codeowners": ["@francoisfernando"], "dependencies": ["rest"], diff --git a/custom_components/foxess/sensor.py b/custom_components/foxess_light/sensor.py similarity index 100% rename from custom_components/foxess/sensor.py rename to custom_components/foxess_light/sensor.py From fe1ae8a012cd8bae58cae06a4f3f2015c50b9c25 Mon Sep 17 00:00:00 2001 From: Francois Fernando Date: Fri, 19 Dec 2025 14:33:14 +1100 Subject: [PATCH 3/5] rename domain --- custom_components/foxess_light/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/foxess_light/manifest.json b/custom_components/foxess_light/manifest.json index eb4d1f2..fc055c0 100644 --- a/custom_components/foxess_light/manifest.json +++ b/custom_components/foxess_light/manifest.json @@ -1,5 +1,5 @@ { - "domain": "foxess_light", + "domain": "foxess", "name": "HA & FoxESSCloud integration - Reduced API calls", "codeowners": ["@francoisfernando"], "dependencies": ["rest"], From 860c35bd4807fa5c931cdbf24ec5a24aff9b3bef Mon Sep 17 00:00:00 2001 From: Francois Fernando Date: Fri, 19 Dec 2025 19:23:07 +1100 Subject: [PATCH 4/5] fix json --- hacs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacs.json b/hacs.json index 67081fb..a94a810 100644 --- a/hacs.json +++ b/hacs.json @@ -1,3 +1,3 @@ { - "name": "FoxESS Cloud Reduced API Calls", + "name": "FoxESS Cloud Reduced API Calls" } From 51286ddc7ee586f414bc370be4279c46b51702ec Mon Sep 17 00:00:00 2001 From: Francois Fernando Date: Fri, 19 Dec 2025 20:40:30 +1100 Subject: [PATCH 5/5] remove customisations --- custom_components/foxess_light/__init__.py | 2 +- custom_components/foxess_light/manifest.json | 12 ++++++------ hacs.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/custom_components/foxess_light/__init__.py b/custom_components/foxess_light/__init__.py index 8ff7621..a514572 100644 --- a/custom_components/foxess_light/__init__.py +++ b/custom_components/foxess_light/__init__.py @@ -1 +1 @@ -"""The Foxess cloud integration with reduced api calls.""" \ No newline at end of file +"""The Foxess cloud integration.""" \ No newline at end of file diff --git a/custom_components/foxess_light/manifest.json b/custom_components/foxess_light/manifest.json index fc055c0..ccf2f94 100644 --- a/custom_components/foxess_light/manifest.json +++ b/custom_components/foxess_light/manifest.json @@ -1,11 +1,11 @@ { "domain": "foxess", - "name": "HA & FoxESSCloud integration - Reduced API calls", - "codeowners": ["@francoisfernando"], + "name": "HA & FoxESSCloud integration", + "codeowners": ["@macxq","@r-amado","@fozzieuk"], "dependencies": ["rest"], - "documentation": "https://github.com/francoisfernando/foxess-ha", + "documentation": "https://github.com/macxq/foxess-ha", "iot_class": "local_polling", - "issue_tracker":"https://github.com/francoisfernando/foxess-ha", + "issue_tracker":"https://github.com/macxq/foxess-ha/issues", "requirements": ["random_user_agent"], - "version": "v0.5" -} + "version": "v0.4" +} \ No newline at end of file diff --git a/hacs.json b/hacs.json index a94a810..b7425f5 100644 --- a/hacs.json +++ b/hacs.json @@ -1,3 +1,3 @@ { - "name": "FoxESS Cloud Reduced API Calls" + "name": "FoxESS Cloud" }