dlarrick / hass-kumo

Home Assistant module interfacing with Mitsubishi mini-split units
MIT License
99 stars 22 forks source link

Login credentials don't work #40

Closed zacs closed 1 year ago

zacs commented 4 years ago

Running HA 0.115 in a pretty vanilla docker container.

I've tried adding via configuration.yaml and also via the UI. I've also changed both my login name and password on the Kumo Cloud service, and tried both methods again, but no love. The error when trying to add via config is pretty ambiguous:

Logger: homeassistant.setup
Source: setup.py:138 
First occurred: 3:22:23 PM (1 occurrences) 
Last logged: 3:22:23 PM

Setup failed for kumo: Integration failed to initialize.

I crafted a request as defined in https://github.com/dlarrick/hass-kumo/blob/8e5a40b7f4c2ce393ad17c035e0a4171457c6db6/custom_components/kumo/kumo_cloud_setup.py#L20 manually, and got a 200 response with all the details of my setup, so I don't think there's any issues in Mitsu's auth.

Let me know what else I might be able to do to debug.

dlarrick commented 4 years ago

You might get more help posting on the Kumo thread in the HomeAssistant forum.

It certainly sounds to me like your password is being mishandled. If you can narrow down which special character might break it, we might be able to figure out why. As far as I know the code isn't doing anything unusual with the password string so it's likely to be more of a general HA password-handling issue than something specific to the integration.

zacs commented 4 years ago

Thanks, I will cross-post there. I agree that I suspect HA is malforming the password. I did change to a purely alphanumeric and it didn't help, sadly.

omriasta commented 3 years ago

Another thing to check would be that you can ping the internal IP of the Kumo unit from the homeassistant machine. Several users including myself have seen issues with the Kumo unit randomly blocking communication from certain IP's/devices which may cause this. For me, restarting the entire network usually resolves this. I have not been able to pin it down, it may also be due to the wifi hardware (google wifi for me).

zacs commented 3 years ago

Quick update that I just can't wrap my head around. I followed @dlarrick advice on just trying to load the account in a Python shell, and even that doesn't work (so nothing is wrong with the HA plugin).

>>> from pykumo import KumoCloudAccount
>>> account = KumoCloudAccount.Factory()
Kumo Cloud username: my.email@email.com
Password: xxxx
>>> account.try_setup()
False

The username and pass work to login to the Kumo app, and I've tried resetting the password to all alphanumeric, etc. Super bizarre.

I can ping the device just fine on the network, I just can't get credentials to do anything with that. Ah well, I guess I'll try a factory reset, if that's even possible on the Kumo device.

omriasta commented 3 years ago

should be:

account = KumoCloudAccount("your_email@address.com", "your_password")
account.try_setup()

and make sure they are both (email and pass) in quotes... that probably will not give you a response so you may want to do: print(account.try_setup())

dlarrick commented 3 years ago

The Factory method is for just what @zacs is trying, in that it will prompt interactively for username & password.

One question I have, what region are you in? Do you know what Kumo server the app talks to? This might be easier to determine by using the webapp as seen in https://github.com/dlarrick/hass-kumo/issues/55 and browser-based devtools to look at the network activity.

If as you said in the first message of this issue you can get a 200 with those same credentials, that's definitely odd and in your shoes I might try to work up the chain from your working manual request, making it look more & more like the actual code HA uses until it doesn't work anymore.

zacs commented 3 years ago

Thanks for the pointer to the new webapp. I'm in the US so can't imagine that mattering too much. Just tried it out and everything works as expected, including the 200 on getDeviceUpdates. I did also notice that the getInfrequentDeviceUpdates has a password property, is that at all useful in communicating with the device?

I suppose it's time to start digging into pykumo code, thanks for the pointers!

image

danielgoepp commented 2 years ago

@zacs this is probably stale at this point, okay to close this issue?

zacs commented 2 years ago

@danielgoepp Certainly. The issue persists but I will open a new issue when I get around to debugging what is going on.

danielgoepp commented 2 years ago

Neah, if you are still having the issue, I'm curious ;) I was just going through some tickets looking for some comments I had remembered, and I saw this one, related to the issues some folks had. When this thread started you were running an older version, I'm assuming you have upgraded HA since then, but the problem persists? Seems you had the auth issue, but then you posted you are getting a 200 okay. What is the current issue that persists? Is it consistent or just some of the time?

zacs commented 2 years ago

Yah, I'm fully up-to-date on the plugin, and on HA 2011.11.5.

However, I will now eat crow, because I gave it another shot and it worked just fine. Couldn't find an IP so the nice setup UI asked me to enter that, but otherwise it appears to be working great. I'm guessing I must have upgraded but never tried re-adding since it had never worked before -- my bad!

Thanks for motivating me to try again!

danielgoepp commented 2 years ago

Fantastic! I'm glad it's working for you now.

zacs commented 1 year ago

Ugh, I hate bringing this one back up. I recently got a second mini split, but the unit never showed in the integration. I thought perhaps deleting and re-adding would help. Unhappy surprise that now the Invalid credentials, Wrong user or password is all that comes up when I try to re-add the integration.

I still get a 200 when I use curl, and I now get a True when testing in a Python shell:

➜ python3.11           
Python 3.11.3 (main, Apr  7 2023, 20:13:31) [Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pykumo import KumoCloudAccount
>>> account = KumoCloudAccount.Factory()
Kumo Cloud username: xyz
Password: 
>>> account.try_setup()
True

However, when I look to fetch the devices this is what happens:

Exception fetching {"c":{"indoorUnit":{"status":{}}}}: can only concatenate str (not "NoneType") to str
Living Room: Error retrieving status from {'r': {}}: 'indoorUnit'
Exception fetching {"c":{"indoorUnit":{"status":{}}}}: can only concatenate str (not "NoneType") to str
Zac Office: Error retrieving status from {'r': {}}: 'indoorUnit'

I'm running latest HA (2023.4.6) and have the latest version of this component installed. No special characters in the password. Any way for me to debug what is going on?

edit: Both of my units were off, and I thought maybe that empty status field was because of that. I turned them both on, and still get the same NoneType error.

edit2: Re-ran from python shell and now I get this response, sad:

>>> account.try_setup()
False
zacs commented 1 year ago

Very mixed results as I prod at it more, I am now getting this error from the shell.

>>> account.try_setup()
True
>>> kumos = account.make_pykumos()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/homebrew/lib/python3.11/site-packages/pykumo/py_kumo_cloud_account.py", line 257, in make_pykumos
    kumos[name] = kumo_class(name, self.get_address(unitSerial),
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pykumo/py_kumo.py", line 42, in __init__
    super().__init__(name, addr, cfg_json, timeouts, serial)
  File "/opt/homebrew/lib/python3.11/site-packages/pykumo/py_kumo_base.py", line 29, in __init__
    'password': base64.b64decode(cfg_json["password"]),
                                 ~~~~~~~~^^^^^^^^^^^^
TypeError: 'NoneType' object is not subscriptable
dlarrick commented 1 year ago

Sorry to not be much help here. Just a couple general comments:

If it works sometimes and doesn't work other times, something is different. Maybe you're getting different results from the Kumo servers. Maybe you're doing something subtly different.

Standard debugging advice applies: be methodical, take notes, verify your assumptions. In this case I'd probably be saving off the KumoCloud responses to files so I can diff them.

zacs commented 1 year ago

Yah apologies for kind of keeping running notes here. Trying to do exactly like you say and figure out what is changing when try_setup() works or doesn't work.

Debugging a bit using the very helpful get_raw_json method. The JSON is missing the address field, but it seems like the component handles that fine. Pasting the complete raw JSON in case it is helpful, although it doesn't seem to be problematic. I'm trying to figure out why try_setup() frequently returns False (an empty array of units) for me (it's True maybe 25% of the time).

JSON dump if it's at all useful

zacs commented 1 year ago

It looks like the problem is that get_credentials() doesn't return anything for my units ever. Neither does get_address() which seems fine, but weirdly get_unit_type() also returns nothing. Name, MAC return as expected. At this point I am assuming that the kumo cloud JSON is malformed and messing with the parsing assumptions in the library. @dlarrick is it normal for any of these methods to be empty (other than the address one)?

It seems like the internal _units in my case is missing cryptoSerial, unitType, and address fields. The crypto and unit types exists in the raw JSON though, so I'm not sure why it wouldn't make it over into the units object. One of the units has a None unitType in the raw JSON which might be worth noting.

>>> account.get_all_units()
dict_keys(['9934P008K100307F', '3134P008D100236F'])
>>> account.get_indoor_units()
['9934P008K100307F', '3134P008D100236F']
>>> account.get_unit_type('9934P008K100307F')
>>> account.get_credentials('9934P008K100307F')
>>> account.get_name('9934P008K100307F')
'Living Room'
>>> account.get_credentials('9934P008K100307F')
>>> account._fetch_if_needed()
>>> account.get_credentials('9934P008K100307F')
>>> creds = account.get_credentials('9934P008K100307F')
>>> print(creds)
None
>>> account.get_mac('9934P008K100307F')
'd4:53:83:2a:2e:1d'
>>> account.get_address('9934P008K100307F')
>>> account.get_address('3134P008D100236F')
>>> account.get_name('3134P008D100236F')
'Zac Office'
>>> account.get_mac('3134P008D100236F')
'24:cd:8d:17:27:1e'
>>> account.get_credentials('3134P008D100236F')
>>> account.is_indoor_unit('3134P008D100236F')
True
>>> account._units
{'9934P008K100307F': {'password': 'a_password', 'label': 'Living Room', 'serial': '9934P008K100307F', 'mac': 'd4:53:83:2a:2e:1d'}, '3134P008D100236F': {'password': 'another_password', 'label': 'Zac Office', 'serial': '3134P008D100236F', 'mac': '24:cd:8d:17:27:1e'}}

Relevant bits of the raw JSON:

    'children': [{
        'lastScheduleChange': 0,
        'zoneTable': {
            '9934P008K100307F': {
                'serial': '9934P008K100307F',
                'mac': 'd4:53:83:2a:2e:1d',
                'label': 'Living Room',
                'unconfigured': True,
                'port': 80,
                '_isNew': True,
                'unitType': None,
...
                'ledDisabled': False,
                'cryptoSerial': 'foobar',
                'cryptoKeySet': 'F',
                'timezone': 'America/Los_Angeles',
                'success': [],
                '$$hashKey': 'object:583',
                'lastAdapterUpdate': '2023-04-27 02:36:28.588649',
                'firmwareVersion': '02.06.10',
                'autoModeEnabled': False,
                'roomTempOffset': 0,
                'password': 'a_password_is_here',
...
                'optimalStart': False
            },
            '3134P008D100236F': {
                'serial': '3134P008D100236F',
                'mac': '24:cd:8d:17:27:1e',
                'label': 'Zac Office',
                'port': 80,
                '_isNew': True,
                'unitType': 'ductless',
...

                'ledDisabled': False,
                'password': 'another_password',
                'cryptoSerial': 'foobar',
                'cryptoKeySet': 'F',
...
            }
        },
        'children': [],
        'label': 'Home',
        'level': 2,
zacs commented 1 year ago

I tried about a million things here, and while it isn't totally deterministic, I believe what allowed me to add mine (again) was to have all units:

  1. Powered on
  2. Powered on for a significant (in my case it was overnight) amount of time

Totally doesn't make sense to me, but it ended up working.