macxq / foxess-ha

Home Assistant & FoxESS integration. Monitor you photovoltaic installation directly from HA ☀️ ⚡️
119 stars 37 forks source link

Unexpected error fetching FoxESS data: 'NoneType' object is not subscriptable #121

Open iancg opened 1 year ago

iancg commented 1 year ago

I'm running version 0.19 with dual inverters.

It has been working for several days, but at 05:20 today, the integration stopped retrieving data, and only started again once I restarted HA.

Looking in the HA log from before the restart I can see these error started at that time.

2023-02-27 05:20:56.437 ERROR (MainThread) [custom_components.foxess.sensor] Unexpected error fetching FoxESS data: 
'NoneType' object is not subscriptable
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 239, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 195, in _async_update_data
    return await self.update_method()
  File "/config/custom_components/foxess/sensor.py", line 143, in async_update_data
    if int(allData["addressbook"]["result"]["status"]) == 1 or int(allData["addressbook"]["result"]["status"]) == 2:
TypeError: 'NoneType' object is not subscriptable

I see there was a similar issues on an earlier version (e.g. #76 ) but that seems to have gone stale.

It isn't obvious from the trackback if allData is None or allData["addressbook"] or allData["addressbook"]["result"]

for now I've made a local code change to put each of these into separate lines

    addressbook = allData["addressbook"]
    result = addressbook["result"]
    status = int(result["status"])
    if status == 1 or status == 2:

And I'll update if it happens again.

FozzieUK commented 1 year ago

I've also seen this error, it usually only happens on systems that are very busy (never appears on lightly loaded systems) so i'm assuming it's a timeout (or timing).

The code that fails with nonetype subscriptable is the status = int(result["status"]) line.

A restart is the only thing that brings it back, but it doesn't stay that way for long.

FozzieUK commented 1 year ago

@iancg

Ok, turned full debugging on to catch it

2023-03-30 10:42:23.514 DEBUG (MainThread) [custom_components.foxess.sensor] FoxESS Addressbook data fetched correcly {"errno":41808,"result":null} 2023-03-30 10:42:23.515 ERROR (MainThread) [custom_components.foxess.sensor] Unexpected error fetching FoxESS data: 'NoneType' object is not subscriptable

The Addressbook call is throwing an error (41808 - I think is supposed to be token is invalid), i'll check for that error alongside 41809 and see if it re-establishes connection - i'm starting to wonder if Fox have reduced the timeout on the cloud - I only poll every 15 minutes.

test1

FozzieUK commented 1 year ago

@macxq

Ok none of this code works if the token expires (in fact getErnings doesn't exist), also the token expired error is 41808 (not 41809)

STANDARD CODE

async def getAddresbook(hass, headersData, allData, deviceID,username, hashedPassword,tokenRefreshRetrys):
    restAddressBook = RestData(hass, METHOD_GET, _ENDPOINT_ADDRESSBOOK +
                               deviceID, None, headersData, None, None, DEFAULT_VERIFY_SSL)
    await restAddressBook.async_update()

    if restAddressBook.data is None:
        _LOGGER.error("Unable to get Addressbook data from FoxESS Cloud")
        return False
    else:
        response = json.loads(restAddressBook.data)
        if response["errno"] is not None and response["errno"] == 41809:
                if tokenRefreshRetrys > 2:
                    raise UpdateFailed(f"Unable to refresh token in {tokenRefreshRetrys} retries")
                global token
                _LOGGER.debug(f"Token has expierd, re-authenticating {tokenRefreshRetrys}")
                token = await authAndgetToken(hass, username, hashedPassword)
                getErnings(hass, headersData, allData, deviceID, username, hashedPassword,tokenRefreshRetrys+1)
        else:
            _LOGGER.debug(
                "FoxESS Addressbook data fetched correcly "+restAddressBook.data)
            allData['addressbook'] = response

I've modified the code to change the token to None as the main loop will re-authenticate the token if it is none.

Works and tested on my system.

MODIFIED CODE

async def getAddresbook(hass, headersData, allData, deviceID,username, hashedPassword,tokenRefreshRetrys):
    restAddressBook = RestData(hass, METHOD_GET, _ENDPOINT_ADDRESSBOOK +
                               deviceID, None, headersData, None, None, DEFAULT_VERIFY_SSL)
    await restAddressBook.async_update()

    if restAddressBook.data is None:
        _LOGGER.error("Unable to get Addressbook data from FoxESS Cloud")
        return False
    else:
        response = json.loads(restAddressBook.data)
        if response["errno"] is not None and response["errno"] == 41808:
                global token
                _LOGGER.debug(f"Token has expierd, re-authenticating {tokenRefreshRetrys}")
                token = None 
        else:
            _LOGGER.debug(
                "FoxESS Addressbook data fetched correcly "+restAddressBook.data)
            allData['addressbook'] = response

System logs when the token expires. 2023-03-30 20:03:25.264 DEBUG (MainThread) [custom_components.foxess.sensor] Updating data from https://www.foxesscloud.com/ 2023-03-30 20:03:25.607 DEBUG (MainThread) [custom_components.foxess.sensor] Token has expierd, re-authenticating 0 2023-03-30 20:03:25.608 ERROR (MainThread) [custom_components.foxess.sensor] Unexpected error fetching FoxESS data: 'addressbook' Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 239, in _async_refresh self.data = await self._async_update_data() File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 195, in _async_update_data return await self.update_method() File "/config/custom_components/foxess/sensor.py", line 143, in async_update_data if int(allData["addressbook"]["result"]["status"]) == 1 or int(allData["addressbook"]["result"]["status"]) == 2: KeyError: 'addressbook' 2023-03-30 20:03:25.619 DEBUG (MainThread) [custom_components.foxess.sensor] Finished fetching FoxESS data in 0.355 seconds (success: False) 2023-03-30 20:33:25.265 DEBUG (MainThread) [custom_components.foxess.sensor] Updating data from https://www.foxesscloud.com/ 2023-03-30 20:33:25.265 DEBUG (MainThread) [custom_components.foxess.sensor] Token is empty, authenticating for the firts time 2023-03-30 20:33:25.440 DEBUG (MainThread) [custom_components.foxess.sensor] Login succesfull{"errno":0,"result":

macxq commented 1 year ago

@FozzieUK thx for investigate 🫡 Can you create PR with fix ?

41809 - is invalid token error

guba91 commented 1 year ago

can close this? already merged