SonnenladenGmbH / APsystems-EZ1-API

The APsystems EZ1 Python library offers a streamlined interface for interacting with the local API of APsystems EZ1 Microinverters.
MIT License
54 stars 7 forks source link

Unexpected error fetching APSystems Data data #18

Closed ccMatrix closed 2 months ago

ccMatrix commented 3 months ago
2024-04-04 09:10:43.569 ERROR (MainThread) [custom_components.apsystemsapi_local] Unexpected error fetching APSystems Data data
Traceback (most recent call last):
  File "/config/custom_components/apsystemsapi_local/__init__.py", line 103, in _async_refresh
    self.data = await self._async_update_data()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/apsystemsapi_local/__init__.py", line 77, in _async_update_data
    data = await self.api.get_output_data()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/APsystemsEZ1/__init__.py", line 163, in get_output_data
    return ReturnOutputData(**response["data"]) if response else None
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: ReturnOutputData.__init__() missing 6 required positional arguments: 'p1', 'e1', 'te1', 'p2', 'e2', and 'te2'

This is related to the following line of code, where the data is mapped to a ReturnOutputData object if response exists. But it seems that it can happen, that the response was not successful and the data object is None instead of the expected object.

https://github.com/SonnenladenGmbH/APsystems-EZ1-API/blob/e2c83482944a1342287070fbcd05e0e0107b85df/APsystemsEZ1/__init__.py#L165

It might be useful to check for the response.message if it is "SUCCESS" and only then map the data to the object. It could then gracefully handle the error case by either retrying the request or throwing a meaningful exception that can be handled in the Home Assistant integration.

This is an error response from the getOutputData endpoint which will trigger the above TypeError:

{
    "data": {},
    "message": "FAILED",
    "deviceId": "E0700XXXXXXX"
}
mawoka-myblock commented 3 months ago

My take on this: Does this really need more error handling? I mean, this error is so unexpected that I think it's fine if the library crashes in this regard. Any other opinions are highly appreciated.

ccMatrix commented 3 months ago

At the moment it doesn't have any error handling whatsoever. You are just trying to map the return data if it is valid or not. Since there is a message field available in the response why not use it? If message is FAILED then raise an exception from the library with e.g. RequestFailedError("Could not retrieve data from API"). I can see 6 occurrences of this error today between 13:40 and 19:17 and 3 similar errors for get_device_power_status. So it does happen frequently enough to handle it properly.

How about just doing a check for message:

return ReturnOutputData(**response["data"]) if response and response.get("message") == "SUCCESS" else None