home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
73.89k stars 30.96k forks source link

lamarzocco Integration: Setup fail with http error 400 #131180

Open martingruening opened 1 day ago

martingruening commented 1 day ago

The problem

Steps to reproduce:

Resultat: integration is not working, reporting in the UI "Request to endpoint https://cms.lamarzocco.io/oauth/v2/token failed with status code 400"

Strangely, afterwards the login in the app is not working anymore. Seems like the account has been locked. Password change is then the only way to get it going again.

What version of Home Assistant Core has the issue?

core-2024.11.2

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant OS

Integration causing the issue

lamarzocco

Link to integration documentation on our website

https://www.home-assistant.io/integrations/lamarzocco

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

Debug log:
`2024-11-21 12:35:59.156 DEBUG (MainThread) [homeassistant.components.lamarzocco.coordinator] Request to endpoint https://cms.lamarzocco.io/oauth/v2/token failed with status code 400
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/lamarzocco/coordinator.py", line 127, in _async_handle_request
    await func(*args, **kwargs)
  File "/usr/local/lib/python3.12/site-packages/lmcloud/lm_device.py", line 132, in get_config
    raw_config = await self._cloud_client.get_config(self.serial_number)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/lmcloud/client_cloud.py", line 166, in get_config
    return await self._rest_api_call(url=url, method=HTTPMethod.GET)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/lmcloud/client_cloud.py", line 118, in _rest_api_call
    access_token = await self.async_get_access_token()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/lmcloud/client_cloud.py", line 58, in async_get_access_token
    return await self._async_get_access_token()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/lmcloud/client_cloud.py", line 72, in _async_get_access_token
    return await self.__async_get_token(data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/lmcloud/client_cloud.py", line 105, in __async_get_token
    raise RequestNotSuccessful(
lmcloud.exceptions.RequestNotSuccessful: Request to endpoint https://cms.lamarzocco.io/oauth/v2/token failed with status code 400`

Additional information

La Marzocco Linea Micra

home-assistant[bot] commented 1 day ago

Hey there @zweckj, mind taking a look at this issue as it has been labeled with an integration (lamarzocco) you are listed as a code owner for? Thanks!

Code owner commands Code owners of `lamarzocco` can trigger bot actions by commenting: - `@home-assistant close` Closes the issue. - `@home-assistant rename Awesome new title` Renames the issue. - `@home-assistant reopen` Reopen the issue. - `@home-assistant unassign lamarzocco` Removes the current integration label and assignees on the issue, add the integration domain after the command. - `@home-assistant add-label needs-more-information` Add a label (needs-more-information, problem in dependency, problem in custom component) to the issue. - `@home-assistant remove-label needs-more-information` Remove a label (needs-more-information, problem in dependency, problem in custom component) on the issue.

(message by CodeOwnersMention)


lamarzocco documentation lamarzocco source (message by IssueLinks)

zweckj commented 1 day ago

@martingruening Can you please try what happens if you enter an IP address?

martingruening commented 1 day ago

@zweckj Connection refused ('Verbindung fehlgeschlagen').

Nothing in the debug log.


Von: Josef Zweck @.> Gesendet: Donnerstag, November 21, 2024 4:42:00 PM An: home-assistant/core @.> Cc: Martin Grüning @.>; Mention @.> Betreff: Re: [home-assistant/core] lamarzocco Integration: Setup fail with http error 400 (Issue #131180)

@martingrueninghttps://github.com/martingruening Can you please try what happens if you enter an IP address?

— Reply to this email directly, view it on GitHubhttps://github.com/home-assistant/core/issues/131180#issuecomment-2491577021, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AIXWEHRCNNO5RAKFI6OZIST2BX5MDAVCNFSM6AAAAABSHHN4RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOJRGU3TOMBSGE. You are receiving this because you were mentioned.Message ID: @.***>

zweckj commented 1 day ago

that's weird. it should log something on error level in this case (coming from lmcloud)

martingruening commented 1 day ago

Sorry, my mistake. I grepped for the wrong keyword.

2024-11-21 20:33:15.209 ERROR (MainThread) [lmcloud.client_local] Local API returned 403.


From: Josef Zweck @.> Sent: Thursday, November 21, 2024 8:50:56 PM To: home-assistant/core @.> Cc: Martin Grüning @.>; Mention @.> Subject: Re: [home-assistant/core] lamarzocco Integration: Setup fail with http error 400 (Issue #131180)

that's weird. it should log something on error level in this case (coming from lmcloud)

— Reply to this email directly, view it on GitHubhttps://github.com/home-assistant/core/issues/131180#issuecomment-2492129502, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AIXWEHQPPYNUTOLKYK6LTWD2BY2SBAVCNFSM6AAAAABSHHN4RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOJSGEZDSNJQGI. You are receiving this because you were mentioned.Message ID: @.***>

zweckj commented 1 day ago

Hm. I'm a bit clueless tbh. I don't have any of those issues. You're machine is correctly added to your account in the app?

martingruening commented 1 day ago

Yes, it is. Looks like an authentication problem to me.


From: Josef Zweck @.> Sent: Thursday, November 21, 2024 10:15:48 PM To: home-assistant/core @.> Cc: Martin Grüning @.>; Mention @.> Subject: Re: [home-assistant/core] lamarzocco Integration: Setup fail with http error 400 (Issue #131180)

Hm. I'm a bit clueless tbh. I don't have any of those issues. You're machine is correctly added to your account in the app?

— Reply to this email directly, view it on GitHubhttps://github.com/home-assistant/core/issues/131180#issuecomment-2492352036, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AIXWEHQ7XQ4PJQ546NALBJD2BZEQJAVCNFSM6AAAAABSHHN4RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOJSGM2TEMBTGY. You are receiving this because you were mentioned.Message ID: @.***>

zweckj commented 1 day ago

Oh no wait. For that 403 I got an idea. Try to setup the integration with local IP again, but only after you connected (successfully) to it with the official app. Wait a bit between the official app login and integration setup.

martingruening commented 1 day ago

I restarted the app, connected to the machine, switched on the boiler, waited for some time (3 minutes) and then retried the integration setup. Same result with error codes 400 and 403.

My HA instance and the Linea Micra are on different subnets with a router/firewall in between. The firewall rules have been checked multiple times. The Micra can connect to anything via TCP. The HA instance is allowed to connect to port 8081 on the Micra via TCP. My mobile is on a third subnet and has appropriate firewall rules. I can see those connections to port 8081 happening from HA and my mobile phone. I see no blocked connections to/from the Micra IP address. So that should not be the issue, right?

Gateway Firmware is v3.6-RC4 and machine firmware is 1.17

zweckj commented 1 day ago

It sure sounds like. What I don't understand is why you are the first one having those issues and it seems to be working fine for everybody else (including me).

Bit of technical background: The local 403 is sometimes happening if the local API is stilled locked, which needs a cloud command after machine restart to be unlocked, which the integration currently doesn't give on setup, but that also shouldn't be an issue if you have connected with the app before...

For the cloud block I'm wondering whether they started blocking consecutive login attempts (the integration does setup in cloud only mode but then fail right?), but again why only you then?

martingruening commented 1 day ago

I agree - impacting only me is strange. My machine and my account are fairly new (3 days old). Maybe they have changed API settings, but keep compability for older accounts (would seem weird).

http 400 means: Bad Request: The request was malformed or invalid. Check the syntax and parameters of the request.

So a http 400 in request for the oauth token could mean they have changed authentication somehow for newer user accounts. A check for that would be somebody that has a working setup deleting the old user account and creating a fresh one.

Edit: I will try to debug the request to https://cms.lamarzocco.io/oauth/v2/token myself. Is the client_id and client_secret the one reported here: https://github.com/rccoleman/lamarzocco or do I have to use mitmproxy to retrieve them for my individual account?

martingruening commented 1 day ago

I did this curl -d "@auth.txt" -X POST https://cms.lamarzocco.io/oauth/v2/token

auth.txt contains grant_type=password&client_id=7_1xwei9rtkuckso44ks4o8s0c0oc4swowo00wgw0ogsok84kosg&client_secret=2mgjqpikbfuok8g4s44oo4gsw0ks44okk4kc4kkkko0c8soc8s&username=user@domain.tld&password=notmyrealpassword

Response is

{"error":"user_manually_disabled","error_description":"User was deactivated by admin edit"}

Afterwards I deleted the account in the app, created a new one (user+lama@domain.tld), assigned the machine to it via the app. I first failed with the response {"error":"invalid_grant","error_description":"Invalid username and password combination"}. After replacing the + sign with the encoded version %2B it worked and I got an access token back.

{"access_token":"LONGTOKENHERE","expires_in":3600,"token_type":"bearer","scope":null,"refresh_token":"ANOTHERLONGTOKENHERE"}

So the problem with my account now seems to be solved. The integration still produces the same behaviour. There must be something different happening between my curl-command and the token request in lmcloud that makes the request fail. A nice first improvement could be to report the error_description back in HA when the token request fails.

zweckj commented 1 day ago

{"error":"user_manually_disabled","error_description":"User was deactivated by admin edit"}

that's interesting. I'm trying to add a logout after each login, to avoid sending consecutive logins with #131240. But admin edit sounds wild.

zweckj commented 1 day ago

Could be that it's just an encoding problem. If there's still a "+" in your username, the integration does not encode that. Edit: Have you tried putting your username in encoded version in the integration setup?

martingruening commented 1 day ago

Could be that it's just an encoding problem. If there's still a "+" in your username, the integration does not encode that.

A plus sign is valid in any email address, so the lmcloud client should encode that properly. When I use user%2Blama@domain.tld as the user name in the integration, then the connection fails immediately. When I enter a plain + sign as part of the username I can proceed to the next step where I can select the machine, but then the integration still fails requesting an oauth token.

I have now switched my username to lama@domain.tld to avoid any encoding problems. I immediately managed to get an oauth token via curl using that user. The app is connected as well. The integration lets me choose the machine and then the behaviour is the same (HTTP error 400). Strange - would be great to expose the error and error_description fields from the failed token request in lmcloud in the HA debug log.

zweckj commented 23 hours ago

I did add it to the library, but you will get those changes earliest in the next HA beta on wednesday. It would be easier tbh if you could install the library and test from there. If you could install pylamarzocco (name changed) through pip and run the following small Python script, that would help a lot in getting an actual fix in the next release

import asyncio
from pylamarzocco.client_cloud import LaMarzoccoCloudClient

async def main():
    cloud_client = LaMarzoccoCloudClient(username, password)
    fleet = await cloud_client.get_customer_fleet()
    config = await cloud_client.get_config(serial_number)

asyncio.run(main())
martingruening commented 19 hours ago
>>> username = "lama@domain.tld"
>>> password = "PASSWORD"
>>> serial_number = "MR025146"
>>> import asyncio
>>> from pylamarzocco.client_cloud import LaMarzoccoCloudClient
>>>
>>> async def main():
...     cloud_client = LaMarzoccoCloudClient(username, password)
...     fleet = await cloud_client.get_customer_fleet()
...     config = await cloud_client.get_config(serial_number)
...
>>> asyncio.run(main())
>>>

No error message shown.

zweckj commented 19 hours ago
import asyncio
from pylamarzocco.client_cloud import LaMarzoccoCloudClient

async def main():
    cloud_client = LaMarzoccoCloudClient(username, password)
    fleet = await cloud_client.get_customer_fleet()
    config = await cloud_client.get_config(serial_number)
    cloud_client = LaMarzoccoCloudClient(username, password)
    fleet = await cloud_client.get_customer_fleet()
    config = await cloud_client.get_config(serial_number)

asyncio.run(main())

Thanks for helping! Let's see if two consecutive login attempts change something

martingruening commented 18 hours ago

Sure, I am happy to get your support too. Runs slightly longer, no error message.

zweckj commented 18 hours ago
import asyncio
from pylamarzocco.client_cloud import LaMarzoccoCloudClient
from pylamarzocco.client_local import LaMarzoccoLocalClient

serial_number = "LM000000000"
username = "username"
password = "password"
host = "192.168.1.42"

async def main():
    cloud_client = LaMarzoccoCloudClient(username, password)
    try:
        fleet = await cloud_client.get_customer_fleet()
        config = await cloud_client.get_config(serial_number)
    except Exception as ex:
        print(ex)
        exit(1)
    else:
        print(config)
    cloud_client = LaMarzoccoCloudClient(username, password)
    try:
        fleet = await cloud_client.get_customer_fleet()
        config = await cloud_client.get_config(serial_number)
    except Exception as ex:
        print(ex)
        exit(1)
    else:
        print(config)
    local_client = LaMarzoccoLocalClient(host, fleet[serial_number].communication_key)
    try:
        config = await local_client.get_config()
    except Exception as ex:
        print(ex)
        exit(1)
    else:
        print(config)

asyncio.run(main())

now I REALLY don't know what's going on. This should print your machine's status 3 times to the console. I'm not interested in that content, I just wanna see if it's able to get it.

martingruening commented 2 hours ago
>>> asyncio.run(main())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "<stdin>", line 10, in main
  File "/usr/lib/python3.11/dataclasses.py", line 1273, in asdict
    raise TypeError("asdict() should be called on dataclass instances")
TypeError: asdict() should be called on dataclass instances
zweckj commented 1 hour ago

sorry, mixed up the functions, fixed the script above