cibernox / homeassistant-poolstation

HomeAssistant custom component for integrating the Poolstation platform.
MIT License
9 stars 4 forks source link

Reauthentication #10

Open straybiker opened 11 months ago

straybiker commented 11 months ago

Once in a while I need to reauthenticate the integration, which causes my automation to stop. Could you make the integration as such that it tries to reauthenticate itself?

cibernox commented 11 months ago

I'd love to, it's also driving me mad. I tried for a while it's quite hard to debug and replicate. Also the time that the integration stays logged is somewhat inconsistent. I've seen it stay authenticated for well over a month and I've seen asking for reauthentication twice in a single day. I suspect it's hitting some kind of API quota.

straybiker commented 11 months ago

Yes indeed, it seems a random period. If HA would be able to alert on this, it would be fine because reauthentication is not that urgent often. Does the call token = await account.login() fails?

cibernox commented 11 months ago

TBH i last looked at this last summer, so by now I don't remember anything.

straybiker commented 11 months ago

I added some logging in my local py file. Will look at it when it occurs again.

straybiker commented 11 months ago

It looks like the reauthentication funtion is never called.

cibernox commented 11 months ago

Thanks for investigating. TBH i copied this feature from another integration, I might have to check for how other integrations do it to see if I can spot what's wrong this implementation.

RienduPre commented 4 months ago

Any news on this subject?

lobmarib commented 1 month ago

Would be nice to have a configuration file where it could be the authentication data and reauthenticate automatically...

MattrixST commented 1 month ago

I can buy you a beer if this helps adding this, any Paypal account? ;)

straybiker commented 1 month ago

The problem seems to be that the code to authenticate again is never called. The problem is also hard to reproduce since it happens randomly. So even when it is stored in a config file, the data will never be read. Also going with this approach the secret file would be a better option.

straybiker commented 1 month ago

I was looking again at the code and noticed that in async def _async_update_data(self) -> None: """Fetch data from poolstation.net.""" try: await self.pool.sync_info() except AuthenticationException as err: raise ConfigEntryAuthFailed from err

Only an authentication error is handled. While comments the same while indicate that the error responses are not correct returned. Shouldn't other errors also try to reauthenticate?

sergio-scl commented 3 weeks ago

Any news with the problem of losing authentication and having to re-enter credentials?

Thanks in advance!

straybiker commented 3 weeks ago

Now that summer is coming, the problem seems to be worse. I tried to reduce the read frequency to 1min to check if it is related to the local connection point, but it doesn't seem to help. So it looks like this is a problem on the server side, I assume something related to the load and performance.

RienduPre commented 3 weeks ago

It’s getting worse over here too. I have several autentication issues a day. Very inconvinient , because I have several automations related to entities of this integration. I will do all I can to help solving the issue.🙏

straybiker commented 3 weeks ago

I think I traced back the error to the pypoolstation library by enabling the debug logging and adding looking at the traces. All ClientErrors are thrown as ClientAuthentication errors.

` async def post(self, url, data=""): try: resp = await self._session.post( url, data=f"Authorization=Bearer {self._token}" + data, headers={"accept": "application/json", "content-type": "application/x-www-form-urlencoded"} ) resp.raise_for_status() except ClientResponseError as err:

Unfortunately, the API is aweful and making a request with an expired token seems to trigger a generic 500 error.

        # For all I could find, there's not way of
        raise AuthenticationException("Request failed. Maybe token has expired.")
    return await resp.json()`

This means that a serverside timeout results in an Authentication error. I worked around this by ignoring the error. This means that I miss an update after a timeout, but up to know it seems to be working fine. I don't know how to catch real expired token errors. Are these returned with error code 500? Timeouts are returned as errorcode 504, so if Authentication errors are returned with a 500, it may be possible to differentiate. See the comment of cibernox.

@cibernox , how can I make local changes for testing to pypoolstation since this component is imported?

cibernox commented 3 weeks ago

Hi everyone. I haven't been able to make any changes or improvements on this project because a flood damaged my ethernet cable that connected the chlorinator, so so far this year I've been operating as if it was a dumb chlorinator. I don't feel like buying 100m of ethernet table and running the wire again, so I ordered a powerline adapter. The first and cheap one didn't work, possibly because it didn't had enough range, so I ordered a more reputable brand now and hopefully I'll get it working this time.

Now, back to the topic, about the timeout getting falsely mistaken for a 500 error, that's a boomer. The API is undocumented and while I wrote some of the developers at fluidra, the main company that develops this system, based near Barcelona, I didn't get a formal spec.

My initial solution would be to have some sort of counter of failures, and maybe allow three 500 errors before considering it an auth problem. PyPoolstation can be found in https://github.com/cibernox/PyPoolstation, you can just fork it and make changes. If you want I can also publish new "beta" versions to be used in this integration to verify they improve the situation.

I suspect that the problem with having to re-render the credentials is a separate issue. I believe that issue is in this project, not in pypoolstation, and I think the re-authentication logic is not triggering at all. I'm not particularly savvy in python and this was my very first homeassistant integration, possibly some of the built-in hooks for handling errors is not correct.

straybiker commented 2 weeks ago

I forked both projects already, but still figuring out how this import mechanism of pypoolstation works. Do you have any guidance on this?

I didn't look further why the re-authentiaction is not working as intended, but I can image that if the re-auth process is mistakenly started because a time-out error and the time-out occurs again during the re-auth, the dialog is shown. For me, re-entering the credentials because of a failing re-auth is not that big of an issue if the only happens rarely. So i'll focus first on proper client response handling.

straybiker commented 2 weeks ago

Created pull requests for a fix in PyPoolStation and Homeassistant-poolstation. The fix ran for a few days here without any issues. Was able to reproduce the issue by change the pw of my setup

RienduPre commented 2 weeks ago

That's good news:-)

cibernox commented 2 weeks ago

It's all merged now. Please, give it a go. I'm still without network conectivity on my chlorinator so I can't test it myself.

RienduPre commented 1 week ago

I still have the reauthentication issues with the latest build

straybiker commented 1 week ago

With the version of yesterday, or the one before? Not all required changes were merged in the first version.

RienduPre commented 1 week ago

Mine is 3 days old, I dont see a newer version

straybiker commented 1 week ago

The latest is 2 days old, from July 10

RienduPre commented 1 week ago

I re-downloaded it from HACS again yesterday This morning I had the error again (see screenshots)

How do I check if I use the latest version?

IMG_4207 IMG_4208 IMG_4209

straybiker commented 1 week ago

I also had it again once last night. The fix doesn't prevent any authentication errors but handles not all server errors, such as timeout, as authentication error. If the server still responds with an authentication, it is still treated as such.

straybiker commented 1 week ago

Btw, looking at the timing of your screenshot, I had the same error at the same moment. So I assume it was a serverside problem.