From 0379d22d1c6253fcc8bbb24b7c2953e465409338 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Mon, 22 Jan 2024 17:40:41 +0100 Subject: [PATCH 1/2] Raise an error with the data included if retrieving data from Kiosk fails --- custom_components/fusion_solar/sensor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/custom_components/fusion_solar/sensor.py b/custom_components/fusion_solar/sensor.py index 333b74b..e720bf2 100644 --- a/custom_components/fusion_solar/sensor.py +++ b/custom_components/fusion_solar/sensor.py @@ -19,7 +19,7 @@ PARAM_DEVICE_TYPE_ID_STRING_INVERTER, PARAM_DEVICE_TYPE_ID_GRID_METER, PARAM_DEVICE_TYPE_ID_RESIDENTIAL_INVERTER, \ PARAM_DEVICE_TYPE_ID_POWER_SENSOR, PARAM_DEVICE_TYPE_ID_EMI, PARAM_DEVICE_TYPE_ID_BATTERY from .fusion_solar.kiosk.kiosk import FusionSolarKiosk -from .fusion_solar.kiosk.kiosk_api import FusionSolarKioskApi +from .fusion_solar.kiosk.kiosk_api import FusionSolarKioskApi, FusionSolarKioskApiError from .fusion_solar.openapi.openapi_api import FusionSolarOpenApi from .fusion_solar.energy_sensor import FusionSolarEnergySensorTotalCurrentDay, \ FusionSolarEnergySensorTotalCurrentMonth, FusionSolarEnergySensorTotalCurrentYear, \ @@ -76,7 +76,10 @@ async def async_update_kiosk_data(): _LOGGER.debug(DOMAIN) _LOGGER.debug(kiosk.id) - data[f'{DOMAIN}-{kiosk.id}'] = await hass.async_add_executor_job(api.getRealTimeKpi, kiosk.id) + try: + data[f'{DOMAIN}-{kiosk.id}'] = await hass.async_add_executor_job(api.getRealTimeKpi, kiosk.id) + except FusionSolarKioskApiError as error: + raise IntegrationError(f'Could not fetch data from FusionSolar: {error}') return data From 91350e16771cc6497afe3bc759e1e82eb56cc2f7 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Mon, 22 Jan 2024 18:09:16 +0100 Subject: [PATCH 2/2] Better handling for errors from OpenAPI / Northbound --- .../fusion_solar/device_real_kpi_coordinator.py | 7 +++++-- .../fusion_solar/fusion_solar/kiosk/kiosk_api.py | 5 ++--- .../fusion_solar/openapi/openapi_api.py | 7 +++++-- custom_components/fusion_solar/sensor.py | 16 +++++++++++----- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/custom_components/fusion_solar/device_real_kpi_coordinator.py b/custom_components/fusion_solar/device_real_kpi_coordinator.py index f275568..7311413 100644 --- a/custom_components/fusion_solar/device_real_kpi_coordinator.py +++ b/custom_components/fusion_solar/device_real_kpi_coordinator.py @@ -11,7 +11,7 @@ from .fusion_solar.const import ATTR_DEVICE_REAL_KPI_DEV_ID, ATTR_DEVICE_REAL_KPI_DATA_ITEM_MAP, \ PARAM_DEVICE_TYPE_ID_STRING_INVERTER, PARAM_DEVICE_TYPE_ID_EMI, PARAM_DEVICE_TYPE_ID_GRID_METER, \ PARAM_DEVICE_TYPE_ID_RESIDENTIAL_INVERTER, PARAM_DEVICE_TYPE_ID_BATTERY, PARAM_DEVICE_TYPE_ID_POWER_SENSOR -from .fusion_solar.openapi.openapi_api import FusionSolarOpenApiAccessFrequencyTooHighError +from .fusion_solar.openapi.openapi_api import FusionSolarOpenApiError, FusionSolarOpenApiAccessFrequencyTooHighError _LOGGER = logging.getLogger(__name__) @@ -61,6 +61,8 @@ async def _async_update_data(self): except FusionSolarOpenApiAccessFrequencyTooHighError as e: self.skip = True return False + except FusionSolarOpenApiError as error: + raise UpdateFailed(f'OpenAPI Error: {error}') for response_data in response: key = f'{DOMAIN}-{response_data[ATTR_DEVICE_REAL_KPI_DEV_ID]}' @@ -86,7 +88,8 @@ def device_ids_grouped_per_type_id(self): station_from_registry = device_registry.async_get_device(identifiers={(DOMAIN, device.station_code)}) if station_from_registry is not None and station_from_registry.disabled: - _LOGGER.debug(f'Device {device.name} ({device.device_id}) linked to a disabled station ({device.station_code}).') + _LOGGER.debug( + f'Device {device.name} ({device.device_id}) linked to a disabled station ({device.station_code}).') continue if device.type_id not in device_ids_grouped_per_type_id: diff --git a/custom_components/fusion_solar/fusion_solar/kiosk/kiosk_api.py b/custom_components/fusion_solar/fusion_solar/kiosk/kiosk_api.py index fb23bb7..41f25e2 100644 --- a/custom_components/fusion_solar/fusion_solar/kiosk/kiosk_api.py +++ b/custom_components/fusion_solar/fusion_solar/kiosk/kiosk_api.py @@ -29,9 +29,8 @@ def getRealTimeKpi(self, id: str): response = get(url, headers=headers) jsonData = response.json() - if not jsonData[ATTR_SUCCESS]: - raise FusionSolarKioskApiError( - f'Retrieving the data failed with failCode: {jsonData[ATTR_FAIL_CODE]}, data: {jsonData[ATTR_DATA]}') + if ATTR_SUCCESS not in jsonData or not jsonData[ATTR_SUCCESS]: + raise FusionSolarKioskApiError(f'Retrieving the data failed. Raw response: {response.text}') # convert encoded html string to JSON jsonData[ATTR_DATA] = json.loads(html.unescape(jsonData[ATTR_DATA])) diff --git a/custom_components/fusion_solar/fusion_solar/openapi/openapi_api.py b/custom_components/fusion_solar/fusion_solar/openapi/openapi_api.py index 5df8799..ba4ef49 100644 --- a/custom_components/fusion_solar/fusion_solar/openapi/openapi_api.py +++ b/custom_components/fusion_solar/fusion_solar/openapi/openapi_api.py @@ -195,6 +195,9 @@ def _do_call(self, url: str, json: dict): f'Retrieving the data for {url} failed with failCode: {json_data[ATTR_FAIL_CODE]}, message: {json_data[ATTR_DATA]}' ) + if ATTR_DATA not in json_data: + raise FusionSolarOpenApiError(f'Retrieving the data failed. Raw response: {response.text}') + return json_data except KeyError as error: @@ -206,9 +209,9 @@ class FusionSolarOpenApiError(Exception): pass -class FusionSolarOpenApiAccessFrequencyTooHighError(Exception): +class FusionSolarOpenApiAccessFrequencyTooHighError(FusionSolarOpenApiError): pass -class FusionSolarOpenApiErrorInvalidAccessToCurrentInterfaceError(Exception): +class FusionSolarOpenApiErrorInvalidAccessToCurrentInterfaceError(FusionSolarOpenApiError): pass diff --git a/custom_components/fusion_solar/sensor.py b/custom_components/fusion_solar/sensor.py index e720bf2..7c7c9b8 100644 --- a/custom_components/fusion_solar/sensor.py +++ b/custom_components/fusion_solar/sensor.py @@ -9,7 +9,7 @@ from homeassistant.const import CONF_NAME, CONF_URL, CONF_HOST, CONF_USERNAME, CONF_PASSWORD from homeassistant.exceptions import IntegrationError from homeassistant.helpers import device_registry as dr -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .fusion_solar.const import ATTR_REALTIME_POWER, ATTR_TOTAL_CURRENT_DAY_ENERGY, \ ATTR_TOTAL_CURRENT_MONTH_ENERGY, ATTR_TOTAL_CURRENT_YEAR_ENERGY, ATTR_TOTAL_LIFETIME_ENERGY, \ @@ -20,7 +20,7 @@ PARAM_DEVICE_TYPE_ID_POWER_SENSOR, PARAM_DEVICE_TYPE_ID_EMI, PARAM_DEVICE_TYPE_ID_BATTERY from .fusion_solar.kiosk.kiosk import FusionSolarKiosk from .fusion_solar.kiosk.kiosk_api import FusionSolarKioskApi, FusionSolarKioskApiError -from .fusion_solar.openapi.openapi_api import FusionSolarOpenApi +from .fusion_solar.openapi.openapi_api import FusionSolarOpenApi, FusionSolarOpenApiError from .fusion_solar.energy_sensor import FusionSolarEnergySensorTotalCurrentDay, \ FusionSolarEnergySensorTotalCurrentMonth, FusionSolarEnergySensorTotalCurrentYear, \ FusionSolarEnergySensorTotalLifetime @@ -79,7 +79,7 @@ async def async_update_kiosk_data(): try: data[f'{DOMAIN}-{kiosk.id}'] = await hass.async_add_executor_job(api.getRealTimeKpi, kiosk.id) except FusionSolarKioskApiError as error: - raise IntegrationError(f'Could not fetch data from FusionSolar: {error}') + raise UpdateFailed(f'Kiosk API Error: {error}') return data @@ -600,7 +600,10 @@ async def async_update_station_real_kpi_data(): if station_codes is None or len(station_codes) == 0: return data - response = await hass.async_add_executor_job(api.get_station_real_kpi, station_codes) + try: + response = await hass.async_add_executor_job(api.get_station_real_kpi, station_codes) + except FusionSolarOpenApiError as error: + raise UpdateFailed(f'OpenAPI Error: {error}') for response_data in response: data[f'{DOMAIN}-{response_data[ATTR_STATION_CODE]}'] = response_data[ATTR_STATION_REAL_KPI_DATA_ITEM_MAP] @@ -682,7 +685,10 @@ async def async_update_station_year_kpi_data(): if station_codes is None or len(station_codes) == 0: return data - response = await hass.async_add_executor_job(api.get_kpi_station_year, station_codes) + try: + response = await hass.async_add_executor_job(api.get_kpi_station_year, station_codes) + except FusionSolarOpenApiError as error: + raise UpdateFailed(f'OpenAPI Error: {error}') for response_data in response: key = f'{DOMAIN}-{response_data[ATTR_STATION_CODE]}'