cbrandlehner / homebridge-daikin-local

Supports Daikin Air Conditioners on HomeBridge
MIT License
93 stars 16 forks source link

CTXM15R5V1B and FTXM20R5V1B : New API? #123

Open jptoucas opened 3 years ago

jptoucas commented 3 years ago

Hello,

I have a CTXM15R5V1B and FTXM20R5V1B units, the pages called by the plugin doesn't exists on those units:

ERROR: Queued request to http://192.168.1.147/common/basic_info returned error Error: Not Found at Request.callback (/homebridge/node_modules/homebridge-daikin-local/node_modules/superagent/src/node/index.js:879:15) at IncomingMessage. (/homebridge/node_modules/homebridge-daikin-local/node_modules/superagent/src/node/index.js:1130:18) at IncomingMessage.emit (events.js:327:22) at endReadableNT (internal/streams/readable.js:1327:12) at processTicksAndRejections (internal/process/task_queues.js:80:21) { status: 404, response: [Response], retries: 0

I tried the url http://192.168.1.147/aircon/get_model_info and I got this message :

Page Not Found /aircon/get_model_info And with http://192.168.1.147/skyfi/aircon/get_model_info :

Page Not Found /skyfi/aircon/get_model_info I have another unit (FTXA50A2V1BW) that is working well with the plugin.

The wifi controler is new, the BRP069C4x, It looks like there is a full new api to discuss with it. I started to catch https calls from the Daikin Residential Controler : from France, we need to discuss with https://api.prod.unicloud.edc.dknadmin.be 4

First request on https://api.prod.unicloud.edc.dknadmin.be/v1/info 6 Second request on ***/v1/gateway-devices

Dont know yet how is done the authentication, I don’t know if there is a way to connect locally to each Daikin units ..

That would be great if we could get the compatibility of new units with homebridge, I will help if my skills are enough on this topic !

cbrandlehner commented 3 years ago

Hi @jptoucas Unfortunately your device is obviously using a different API. I am the author of this plugin but do not have access to a new device with the new / other API. Without access I see no way to reverse engineer the API.

If you can find out how your device works and you can provide a list of working URLs, preferred in CURL format, there is a chance that API can be added too.

jptoucas commented 3 years ago

Thanks for your feedback. I can try to catch calls done by the iOS app to the Daikin cloud, and find out what is needed. That could be better to catch call between the Daikin cloud and my unit, but I have no idea how to do it. Witch approach would you have in my situation?

rjcarlson49 commented 3 years ago

This may be that API your are dealing with:

https://backend.daikincomfort.com/docs/default-source/product-documents/residential/manuals/othermanual/im-dknapi.pdf?sfvrsn=b0e02426_6

jptoucas commented 3 years ago

This may be that API your are dealing with:

https://backend.daikincomfort.com/docs/default-source/product-documents/residential/manuals/othermanual/im-dknapi.pdf?sfvrsn=b0e02426_6

Yes it looks like to be the right one ! I will check my iOS traces to confirm that ASAP

rjcarlson49 commented 3 years ago

I have a plan to do a plugin for that API, but I have to finish another project first, an iOS app.

I can't believe how bad the DKN app is. It's an embarrassment.

jptoucas commented 3 years ago

I agree, the app is far from perfect :( I looked at a smart Ir remote but no states feedback is possible with it ... I’m glad you planned to work an a plug-in for this API, I’m not a developer but I can help if necessary in many ways if needed (tests, catch traces,...)

vanesp commented 3 years ago

I’ve run into the same problem...my brand new Daikins only talk the new protocol. Shit. I wanted to bind it to my domotica system. I’m in the Netherlands and trying to connect to Oauth2.0 but neither the end point in the docs nor the one you list above works for me...

vanesp commented 3 years ago

@jptoucas what is the full endpoint for the first call to authenticate?

vanesp commented 3 years ago

Oh by the way... if you look at the webpage of your WiFi controller, it looks like it’s got MQTT built in... that would be really interesting

jptoucas commented 3 years ago

The first request I see from iOS Is a POST to https://sentry.io/api/1860051/envelope/ then a GET with https://api.prod.unicloud.edc.dknadmin.be/v1/info I have to check at the dnk api doc to understand how is done the authentication, it looks that it has to be done in two steps to get a token.

The webpage shows FreeRTOS and mention "Eclipse Paho MQTT C/C++ client for Embedded platforms" : Only the port 80 is listening on my unit, I'm not sure there is MQTT capability here

vanesp commented 3 years ago

Interesting...

I've put this in a bit of code, conform the procedure listed in the API document above... but now with the URL you indicated:

import requests # pip install requests
url = 'https://sentry.io/api/1860051/envelope/'
headers = {
    'Accept': 'application/json',
    'Content-type': 'application/json',
}
payload = {'email':'email@email.com', 'password':'secret'}
r = requests.post(url, headers=headers, data=payload)
print(r.json())

I've used the e-mail address and password I'm using to authenticate the Daikin Residential Controller. The response I get makes a little more sense than with the Daikin URL from the document:

{'detail': 'missing authorization information'}

However, it looks like the authentication process does not conform with the API document.

vanesp commented 3 years ago

The Sentry also supports an OAuth process...

https://docs.sentry.io/product/integrations/integration-platform/

vanesp commented 3 years ago

If I run the same code with a link to: https://api.prod.unicloud.edc.dknadmin.be/v1/info then the response is:

{'code': 'UNAUTHORIZED', 'message': 'The given token is invalid. Check the value of the Authorization HTTP request header.'}

which makes sense because I do not yet have a token.

rospogrigio commented 3 years ago

Hi, I also have a pair of devices with the BRP069C4x adapter, I'm following this thread and open to do testing if needed. Thank you

jptoucas commented 3 years ago

I will do some new attempts on my side, there is a screenshot of the full trace:

Capture d’écran 2021-02-26 à 23 12 16
jptoucas commented 3 years ago

To complete my last message: During my first try, I missed a request before the sentry.io, sorry for that. The first request, as you can see on the screenshot, is a GET to api.prod.unicloud.edc.dknadmin.be

There is the curl command : curl -H 'Host: api.prod.unicloud.edc.dknadmin.be' -H 'accept: application/json' -H 'content-type: application/json' -H 'user-agent: Daikin/1.7.0.4696 CFNetwork/1220.1 Darwin/20.3.0' -H 'x-api-key: YYYYYY' -H 'if-none-match: XXXXXXX' -H 'accept-language: fr-fr' -H 'authorization: Bearer ZZZZZ' --compressed 'https://api.prod.unicloud.edc.dknadmin.be/v1/info'

There is a bearer token (replaced by ZZZZ) , an api-key (replaced by yyyy) and another string if-none-match (replaced by XXXX, it has to be different for another calls)

jptoucas commented 3 years ago

I also catch the first login traces in the Daikin Residential Controler: They use SAML to authenticate our user/pwd, the bearer is returned by the POST on daikin-unicloud-prod.auth.eu-west-1.amazoncognito.com//oauth2/token I'm definitely not skilled enough to do the plugin my self !

Capture d’écran 2021-02-26 à 23 30 30

vanesp commented 3 years ago

I tried to log the same with Charles Proxy however when I did I'm sure I must be doing something wrong. The Daikin app complains there is no network, and it won't find my airconditioning units. So I have no sensible values for XXXX, YYYY and ZZZ above. Could you perhaps mail me them at vanes.peter at google.com so that I can insert them into code and see if I can get a valid token.

We are getting closer: {'callId': '6ed15725c3ba49778e25f54332a814df', 'errorCode': 400093, 'errorDetails': 'Missing required parameter: ApiKey', 'errorMessage': 'Invalid ApiKey parameter', 'apiVersion': 2, 'statusCode': 400, 'statusReason': 'Bad Request', 'time': '2021-02-27T10:59:54.382Z'}

Then we also need the exact payload of the PUT and GET to daikin-unicloud... and api.prod.unicloud... as I think that is where the interaction is happening!

jptoucas commented 3 years ago

Hi, you need to enable SSL proxying in Charles, for each target hosts. I followed this tutorial : https://www.raywenderlich.com/1827524-charles-proxy-tutorial-for-ios#toc-anchor-004

I had the same issue in the iOS App (don’t forget to enable the full trust of the Charles certificate in your iOS devise in Settings/General/Informations/certificate settings, it was not on the tutorial)

Apollon77 commented 3 years ago

There is a bearer token (replaced by ZZZZ) , an api-key (replaced by yyyy) and another string if-none-match (replaced by XXXX, it has to be different for another calls)

The XXXX should be irrelevant and you could be able to remove that header. it is just the ETAG from last call to allow server side caching.

And the "bearer token" should have come from an earlier login into the cloud account? So maybe the best idea ois to try a "complete fresh app install". maybe I can try next days with my app, i never logged in into that cloud account, maybe so I can get a fresh capture

Apollon77 commented 3 years ago

Maybe also @rjcarlson49 or @LostInTheTrees ... I saw you created some time ago ca new homebrudget fork with a name like "cloud" :-) maybe you also have some notes ....

ImHereBecauseOfNewDaikinAPI commented 3 years ago

Hi guys,

I was following up this topic since I got a brand new Daikin HVAC coming with the new BRP069C4x controller. Unfortunately I cannot add it from my Home Assitant server because of the brand new cloud API using AWS.

I have done some tests, catching some traffic, and I was able to catch the request to obtain a bearer token composed of an id_token, an access_token, a refresh_token and an default expiration of 3600.

I've also catched something that is probably the whole configuration of my unit by using this URL https://api.prod.unicloud.edc.dknadmin.be/v1/gateway-devices

And, last but not least I was barely able to replay a ON action and a OFF action with a valid authorization from my laptop by using this URL https://api.prod.unicloud.edc.dknadmin.be/v1/gateway-devices/7f9245ed-26a0-4a01-ba61-5fb2145df510/management-points/climateControl/characteristics/onOffMode with this kind of argument: {"value":"on"} - {"value":"off"}.

I'm not copy/pasting things here since I'm not sure what should be obfuscated. I'm not a dev and I don't have skills regarding API but I'm just here to help if somebody wants to go a little bit further. I'll also take some time this week-end to do things on my side, I'll keep you in touch but it seems that we definitely could manage the unit if we have a valid token. Unfortunately nothing could be sent locally... Everything will goes through the AWS cloud. BTW I'm also working on a exhaustive URL and protocol list to restrict the outgoing traffic from the Daikin unit. I'll also keep you in touch with that.

Thanks,

Apollon77 commented 3 years ago

I have done some tests, catching some traffic, and I was able to catch the request to obtain a bearer token composed of an id_token, an access_token, a refresh_token and an default expiration of 3600.

Were you also able to get the call to get the access/refresh tokens before? (normally happens when you login into the cloud account)

If you like (and are ok with someone else looking at the traffic I would be happy to get your infos via email (not that public) to github@fischer-ka.de (and to tell why I ask that ... I develop the nodejs daikin lib daikin-controller

ImHereBecauseOfNewDaikinAPI commented 3 years ago

That's not clear at this point but I'll sent you required info tonight since I'm not focused at the moment I'm just doing things in background.

I was also able to retrieve new access token by using the refresh token and send commands to the unit like changing the temperature with the new generated access token succesfully.

vanesp commented 3 years ago

I was also able to retrieve new access token by using the refresh token and send commands to the unit like changing the temperature with the new generated access token.

That's really good, because that is what is needed to keep this going. And as @Apollon77 says, we need to know how to start up the exchange for a particular device.

rospogrigio commented 3 years ago

Hi, I would like to test my device as well, may I ask you some questions? How can I signup for a cloud account? Which is the URL I should refer to? Great job guys, something is moving here! 👍

Apollon77 commented 3 years ago

In my eyes it is all about getting the app traffic. So ideally utilize Charles Proxy, setup for ssl sniffing and certs in the mobile device.

Then ideally uninstall the app and install again and then gettraffic started with the veeery first start (because some apps register themself on first start and get an id or such). ANd then regioster the new adapter and then wee see what happens there.

I'm also at that process right now with one other user, but also here the "startpoint" is missing ... lets see :-) but yes it incorporates trust to us, so I only excahnge that via email.

When we then understood it we can make it public (so not data but "how to do it") :-)

rjcarlson49 commented 3 years ago

Maybe also @rjcarlson49 or @LostInTheTrees ... I saw you created some time ago ca new homebrudget fork with a name like "cloud" :-) maybe you also have some notes ....

Those are both me. I have not gotten to this project yet. I did another plugin first since this one will be a lot more complicated. I am also working on an unrelated iOS app that is almost done. I suspect I'll start this one in about a month.

I have 6 Daikin Vista indoor units that mount in the ceiling. They connect to 2 compressors outdoors. Having lived with them awhile I have learned a lot. First, I think their controls are godawful bad. The app they made is pathetic, so I am dying to get them into Homekit so I have decent control. For just one example, we cannot get them to heat unless all three indoor units on a compressor are set to identical settings and then cycled off then on. Even then, one of the systems will not heat.

rjcarlson49 commented 3 years ago

I'm not sure why you think you need to capture the app traffic. The API doc looked pretty good to me. My plan was to get a good OAUTH2 package and let that do the login. Then once the security is taken care of, the API should define how to control the devices.

I've done a lot of wifi and ethernet capturing in my life and when encryption is happening it's quite difficult. I would use it only as a last resort.

vanesp commented 3 years ago

Because the API doc referenced above fails on the first call. Unless you have a different doc?

ImHereBecauseOfNewDaikinAPI commented 3 years ago

OK guys just to summarize what I have done this evening.

I was able to obtain a "login_token" from this URL "https://cdc.daikin.eu/accounts.login" by providing a Daikin cloud loginID (email), password, APIKey and other parameters but I came up against issue when I try to obtain an SAML response from this URL https://cdc.daikin.eu/saml/v2.0/ by using the obtained "login_token" (InvalidsamlContext).

If I have a proper SAML response then I could try to obtain an logincode from this URL https://daikin-unicloud-prod.auth.eu-west-1.amazoncognito.com/saml2/idpresponse and then use this authorization code with my client id to authenticate against https://daikin-unicloud-prod.auth.eu-west-1.amazoncognito.com/oauth2/token to obtain this kind of answer:

{"id_token":"xxx","access_token":"xxx","refresh_token:"xxx","expires_in":3600,"token_type":"Bearer"}

Instead of this one:

{"error":"invalid_grant"}

Then it's game over because you just have to use this access token to directly (I mean passing through the AWS cloud) launch actions on the unit with this URL https://api.prod.unicloud.edc.dknadmin.be. For info if the token is expired and you try to launch an action you will have this error message:

{"code": "UNAUTHORIZED", "message":"The given token is invalid. Check the value of the Authorization HTTP request header."}

Then you just need to refresh it to obtain a new access token. This is the way the Daikin Residential Controller app is refreshing the access token when you're already logged on in the app.

{"ClientId":"xxx","AuthFlow":"REFRESH_TOKEN_AUTH","AuthParameters":{"REFRESH_TOKEN":"xxx"}}

At the moment I'm totally able to control the unit and I'm also able to modify schedules configured in the app and retrieve values like outdoor and indoor temp. The "only" problem is still to obtain a valid access token by simulating the authentication behavior of Daikin Residential Controller app.

Thanks,

Apollon77 commented 3 years ago

@ImHereBecauseOfNewDaikinAPI Hey that sounds great ... could you share the requests in code or in curl, because then this could be a good basis to go forward.

I await a Charles file from one contact to hopefully see the same as you already "decrypted" :-)

And @rjcarlson49 exactly as @vanesp said OAuth stuff normally is secured by some secret stuff too, so in fact mimic the "how the App is doing it" make sure it is harder for Daikin to get around that.

vanesp commented 3 years ago

I presume that the Daikin airconditioner/controller contact some server periodically to get their settings and control. After all, we did not have to open something in the firewall.

I was thinking of how the app adds the devices. First the app creates an account. Then you attach your device to the Access Point of the Daikin controller, and then use the app to set your own wireless network to the device.

Somewhere in that process the authentication of the App and the authentication of the Daikin airconditioner to be controlled get set up. In some way the Daikin to be controlled must be identified. I have two Daikin units in my app, making the whole process even more difficult.

jptoucas commented 3 years ago

Great work 👍🏻👍🏻 I can share here my Charles traces if the token expires, no security issues. I have 5 units will it be more difficult to work on ?

jptoucas commented 3 years ago

Could it be possible to reuse the open source code available on the Daikin app settings ? 034EB6F3-98D2-46D5-8660-66E517725F49

Apollon77 commented 3 years ago

Ok, I now got infos from Adrien and another Charles File.

My results are as follows: WTF :-))

And then all normal API requests start against https://api.prod.unicloud.edc.dknadmin.be using the bearer token. The API key is the same for all as it seems

And for refresh of tokens it is also question what is needed and against which server this is done.

I do not really see a way to "just" use an OAuth client because it is a very custom flow all in all from my perspective. For me it feels the best to do a proxy approach like I already did for Amazon Alex App stuff, then you can catch all cookies and all that stuff (but yes a bit more complex then Alexa because more domains used :-) )

So the code_verifier is the blocker in my eyes right now

Apollon77 commented 3 years ago

Could it be possible to reuse the open source code available on the Daikin app settings ?

No thats just other libs that they use internally. "react" is the forntend

Apollon77 commented 3 years ago

So the code_verifier is the blocker in my eyes right now

So, someone up for decompiling the Android App to get info on how they calculate the code_verifier? (thats honestly not my domain)

Apollon77 commented 3 years ago

I did one test more: Just open the start URL in your browser and you can login there and you exactly end up in the one redirect to that "daikin handler url" with the auth code on it. But then doing the call where we need to code_verifier I get back

{"error":"invalid_request"}

rjcarlson49 commented 3 years ago

I'm glad someone is finally digging into these Daikin units. I thought I was the only one interested. Are you going to fork off a new project?

ImHereBecauseOfNewDaikinAPI commented 3 years ago

My results are as follows: WTF :-))

Thank you @Apollon77 for this in depth analysis of authentication process.

I'm glad someone is finally digging into these Daikin units. I thought I was the only one interested. Are you going to fork off a new project?

@rjcarlson49 you're not alone and since Daikin is only producing new units with this new WiFi controller I guess other guys like us will want to find a way to communicate.

And for refresh of tokens it is also question what is needed and against which server this is done.

Refresh token is done against https://cognito-idp.eu-west-1.amazonaws.com

Since I could refresh the token on daily basis, I'm using a dumb python script to get a new access token. Here's the code to refresh the token:

url = 'https://cognito-idp.eu-west-1.amazonaws.com'

headers = {
    'Host': 'cognito-idp.eu-west-1.amazonaws.com',
    'Content-Type': 'application/x-amz-json-1.1',
    'x-amz-target': 'AWSCognitoIdentityProviderService.InitiateAuth',
    'Connection': 'close',
    'Accept': '*/*',
    'x-amz-user-agent': 'aws-amplify/0.1.x react-native',
    'Accept-Language': 'fr-fr',
    'Content-Length': '1840',
    'Accept-Encoding': 'gzip, deflate',
    'User-Agent': 'Daikin/1.6.1.4681 CFNetwork/1220.1 Darwin/20.3.0'
    }

data = {
    'ClientId': '***MY_CLIENT_ID***',
    'AuthFlow': 'REFRESH_TOKEN_AUTH',
    'AuthParameters': {
        'REFRESH_TOKEN': '***MY_REFRESH_TOKEN***'
        }
    }

response = requests.post(url, headers=headers, data=json.dumps(data))
accessToken = response.json()['AuthenticationResult']['AccessToken']

At the moment it's working like a charm and I get a fresh access token each time. I'm able to retrieve data like consumption and temperature and launch actions on my new Daikin indoor unit from my py script which is great.

@Apollon77 For the code verifier I have absolutely no idea how to generate it. Do you mean it could be useful to catch traffic from a Google Home or Alexa device in order to have a more common flow of authentication? I personnaly did not have those kind of evil recording devices but I can try to find one of them in order to test.

Apollon77 commented 3 years ago

For the code verifier from my POV the best chance is to look in the app code and hope it is done in the JavaScript part where generally there could be a Chance to understand what they are doing. If it is in native code then it becomes veeery bad.

As said above. This is the Blocker right now.

For the fork question I would be more for a general library approach where then multiple projects can use it. I did that for the local communication with my daikin-controller lib. So that would be my personal approach ;-))

And yes - if we get out the code verifier then this should work and would "just" be a matter of available time ;-)

Apollon77 commented 3 years ago

For refresh it is good to see that it works without all these cookies needed.

rjcarlson49 commented 3 years ago

A separate library would be great.

rospogrigio commented 3 years ago

Super progress!! But how do we get our client_id ?? Do we have to sniff the traffic or there is another way? Thank you, great job!

ImHereBecauseOfNewDaikinAPI commented 3 years ago

Super progress!! But how do we get our client_id ?? Do we have to sniff the traffic or there is another way? Thank you, great job!

Only way is to decrypt the traffic but it's - let's say - not so hard to do it. Here's how to do it:

  1. Install Burp community edition.
  2. Use an IOS device (Burp CA could not be trusted on a non-rooted Android device) and install root CA. https://portswigger.net/support/installing-burp-suites-ca-certificate-in-an-ios-device
  3. Configure Burp to act like a proxy by listening on all interfaces on port 8082 for example. https://portswigger.net/support/configuring-an-ios-device-to-work-with-burp
  4. Start the Daikin Residential App (even if you're already logged on).
  5. Catch the response of the POST request above against https://cognito-idp.eu-west-1.amazonaws.com to get a fresh access token and control your unit. You just have to replay this POST request via Python for example to get a new access token but at this point I don't know if the refresh token has an expiration time. On my side I'm using the same refresh token since Friday and for the moment everything works fine.
HTTP/1.1 200 OK
Date: Fri, 12 Mar 2021 15:23:06 GMT
Content-Type: application/x-amz-json-1.1
Content-Length: 2501
Connection: close
x-amzn-RequestId: 0bde942a-6e3c-4a02-b9c8-d5dad6044b78

{
    "AuthenticationResult": {
        "AccessToken":"****************",
        "ExpiresIn":3600,
        "IdToken":"****************",
        "TokenType":"Bearer"
    },
    "ChallengeParameters": {
    }
}
rospogrigio commented 3 years ago

I have a rooted android device, could it work? Thank you!

ImHereBecauseOfNewDaikinAPI commented 3 years ago

I have a rooted android device, could it work?

Yes of course! The only problem with a non-rooted Android device is the fact that the imported root CA of Burp is not really "trusted" but if you have a rooted device I assume you can trust a user CA to act as a "real" root CA. Just follow this procedure: https://portswigger.net/support/configuring-an-android-device-to-work-with-burp

vanesp commented 3 years ago
  1. Start the Daikin Residential App (even if you're already logged on).

The problem I have with this... whenever I do this, and start the Daikin App, it appears that it complains I don't have an internet connection, and it's forgotten all about the Daikin devices I've added... what oh what am I doing wrong??

ImHereBecauseOfNewDaikinAPI commented 3 years ago

The problem I have with this... whenever I do this, and start the Daikin App, it appears that it complains I don't have an internet connection, and it's forgotten all about the Daikin devices I've added... what oh what am I doing wrong??

Inspecting secure traffic is not always reliable and to be honest I was also facing random issues (slow logon, failed attempts, certificate issues) but after trying multiple times I was finally able to catch the traffic in clear and I was able to open the app and manage my indoor unit.

I'm using Burp v2021.2.1 build 5962 running on Windows as a proxy server with an up to date iPad (iOS 14.4) and a Daikin Residential App version 1.6.1.4681 as a client. Certificate of Burp (PortSwigger) is installed as a root CA on the iPad and fully trusted by the device.