Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DeLonghi Coffee Link Adapter #664

Open
chrvidal opened this issue Sep 13, 2021 · 24 comments
Open

DeLonghi Coffee Link Adapter #664

chrvidal opened this issue Sep 13, 2021 · 24 comments

Comments

@chrvidal
Copy link

What kind of device or service you would like to see an adapter for?

De'Longhi Primo Donna Soul über Coffe Link App.
https://play.google.com/store/apps/details?id=it.delonghi&hl=de&gl=DE

Is an official API including documentation is available?
Nein, noch nichts gefunden

Are other libraries for an integration available?
Nein

Is this device already integrated in other Smart Home systems?
Nein

Is this device already integrated in homebridge? Might the ham adapter together with the homebridge plugin be sufficient?
Nein

Additional context
Kleiner Thread zum Adapterwunsch.
https://forum.iobroker.net/topic/45069/de-longhi-kaffeemaschine-mit-iobroker-starten?_=1631533653272

@AlCalzone
Copy link
Collaborator

Zusatzinfo: (Zumindest meine Maschine) kann per BLE angesteuert werden. Erste Entwicklungen habe ich bereits, aber die Zeit... 😅

@zonkAK
Copy link

zonkAK commented Jan 21, 2022

push

@Apollon77
Copy link
Collaborator

@zonkAK Where you want to push it to?

@zonkAK
Copy link

zonkAK commented Jan 21, 2022

into the capable hands of a developer (and coffee fancier) who wants to tell his/her Alexa to make the Delonghi brew some coffee while crawling out of bed :-)
Sorry that for myself I cannot contribute anything besides maybe testing later on :-|

@AlCalzone
Copy link
Collaborator

I'll have more time in ~3 months, planning to work on this again then.

@zonkAK
Copy link

zonkAK commented Jan 21, 2022

Sounds great :-) Thank you!

@th4git
Copy link

th4git commented Apr 27, 2022

Hi coffee friends (like @AlCalzone and @ldittmar81),

as a new owner of a "DeLonghi Primadonna Soul" I wish to make my initial contribution to a possible DeLonghi coffee machine adapter for iobroker.

Situation:

  • De'Longhi did not yet publish any public information about an API.
  • An Android (and iPhone) app "De'Longhi COFFEE LINK" is available used to control selected coffee machines via an API over WLAN/HTTPS - e.g. the machine "Primadonna Soul".
  • The app uses "certificate pinning" which makes it a bit more complicated to analyze its behavior (HTTPS traffic).

Approach:
Analyze the behavior of "De'Longhi COFFEE LINK" android app to learn how the undocumented API of De'Longhi works in order to support development of a possible iobroker adapter.

Proposed steps and initial hints to have more insights into the existing API:

  • Read and understand instructions "Intercepting HTTPS from a 3rd party app on non-rooted device":
    https://httptoolkit.tech/blog/intercepting-android-https/#intercepting-https-from-a-3rd-party-app-on-non-rooted-devices

  • Download and install "fiddler" for debugging/intercepting https connections (Windows/Mac/Linux):
    https://www.telerik.com/fiddler/fiddler-classic

    • Enable https decoding via "Tools/Options/HTTPS/"
      • "Capture HTTPS CONNECTs = enable"
      • "Decrypt HTTPS traffic = enable"
      • Export "fiddler root certificate" via "Tools/Options/HTTPS/Export root certificate to desktop" (will create "FiddlerRoot.cer" file)
    • Note the local/private IP of your system where you installed "fiddler"
  • Copy exported "FiddlerRoot.cer" file to your mobile phone (Android).

  • Install/trust "FiddlerRoot.cer" at your phone by open "settings" and search for "CA certificate", follow screen instructions to add it

  • Download and install "apk-mitm" (tool to remove apps' "certificate pinning") at your system where the Android App will be processed by it (Linux):
    https://github.com/shroudedcode/apk-mitm#apk-mitm
    Make sure Node.js (14+) and Java (8+) are already installed beforehand

  • Download android app "De'Longhi COFFEE LINK" via
    https://apkpure.com/de/de-longhi-coffee-link/it.delonghi/
    and place it on the system where you can process it (Linux)

  • Process DeLonghi-App with "apk-mitm" to remove "CA Certificate" pinning from it. See
    https://github.com/shroudedcode/apk-mitm#apk-mitm

  • Remove any previously installed DeLonghi-App from your mobile phone (Android)

  • Upload "processed DeLonghi-App" to your mobile phone (Android)
    Install it by allowing installation from "unsecure sources"

  • Modify your existing (and active) WLAN configuration at your mobile phone and set/enable a "Proxy".

    • Set "Proxy IP" to the local/private IP of your system where you installed "fiddler"
    • Set "Proxy port" to "8888" ("Fiddler's default")
  • Now start and use the "processed DeLonghi-App" at your phone while monitoring its traffic/activity at "fiddler"
    At "fiddler" you will see all activities initiated from the DeLonghi-App, like accesses to the DeLonghi cloud

[
  {
    "device": {
      "product_name": "AC000W02*****69",
      "model": "AY008ESP1",
      "dsn": "AC000W02*****69",
      "oem_model": "DL-millcore",
      "sw_version": "ADA 1.5.3 esp-idf-v3.3.1 2020-04-13 00:25:55 2cfd564",
      "template_id": 5651,
      "mac": "34865****84",
      "unique_hardware_id": null,
      "lan_ip": "192.168.178.xxx",
      "connected_at": "2022-04-25T10:49:47Z",
      "key": 1772503,
      "lan_enabled": true,
      "connection_priority": [
        "LAN"
      ],
      "has_properties": true,
      "product_class": null,
      "connection_status": "Offline",
      "lat": "50.1zzz",
      "lng": "8.9zzz",
      "locality": "67486",
      "device_type": "Wifi",
      "dealer": null
    }
  }
]
[
  {
    "property": {
      "type": "Property",
      "name": "d001_rec_espresso",
      "base_type": "string",
      "read_only": false,
      "direction": "output",
      "scope": "user",
      "data_updated_at": "2022-04-25T10:50:30Z",
      "key": 131130551,
      "device_key": 1772503,
      "product_name": "AC000W02*****69",
      "track_only_changes": false,
      "display_name": "001_rec_espresso",
      "host_sw_version": false,
      "time_series": false,
      "derived": false,
      "app_type": null,
      "recipe": null,
      "value": "0CWw8AEIAAABGAABAQEAFAAoALQbAAEEAgAEBQQAAAAZAAEBuZY=",
      "generated_from": "AYLA::device",
      "generated_at": 1650883000,
      "denied_roles": [],
      "ack_enabled": false,
      "retention_days": 30
    }
  },
...(additional 310 entries here!)...
  {
    "property": {
      "type": "Property",
      "name": "software_version",
      "base_type": "string",
      "read_only": false,
      "direction": "output",
      "scope": "user",
      "data_updated_at": "2022-04-25T10:50:29Z",
      "key": 131130859,
      "device_key": 1772503,
      "product_name": "AC000W02*****69",
      "track_only_changes": true,
      "display_name": "software_version",
      "host_sw_version": false,
      "time_series": false,
      "derived": false,
      "app_type": null,
      "recipe": null,
      "value": "Millcore_demo 2.0.0 Jun 18 2020 15:41:06",
      "generated_from": "AYLA::device",
      "generated_at": null,
      "denied_roles": [],
      "ack_enabled": false,
      "retention_days": 30
    }
  }
]
  • Additionally there is direct traffic from the DeLonghi-App to the local IP of your coffee machine like

    • POST http://192.168.178.xxx/local_reg.json (with local IP of coffee machine)
      {"local_reg":{"ip":"192.168.178.yyy","notify":0,"port":10275,"uri":"/local_lan"}} (with local IP of your mobile phone)
  • Additionally the app at your phone locally acts as a server and opens a local port (as announced above: 10275) and receives direct traffic from the local coffee machine like

  • Last but not least the coffee machine accesses parts of the DeLonghi cloud like

    • DL-millcore-229b963f-device.aylanetworks.com
    • ...
    • Problem: I did not get aware of this traffic's content, because the coffee machine uses HTTPS to connect to the cloud service and I could not yet get to be a "man-in-the-middle".

I hope my input helps a bit to find a skilled iobroker enthusiast with enough patience and passion to push things towards an adapter. Looking forwards to your feedback, additions and corrections!

@AlCalzone
Copy link
Collaborator

@th4git I currently don't have the capacity to continue with this project. Also, my machine is communicating with the App via Bluetooth, not WiFi, so my previous work would be of little help for the HTTP API. Maybe the commands are encoded similarly, if anyone needs the ones I've figured out (from decompiling the App), let me know.

@Bully85
Copy link

Bully85 commented Nov 28, 2022

Is there anyone who wants to take care of this now?

@Ilovegym66
Copy link

Ilovegym66 commented Aug 26, 2023

Some updates of this ?
Already in HA integrated:
https://github.com/Arbuzov/home_assistant_delonghi_primadonna

@shaarkys
Copy link

I believe it's not, it's by error.

Arbuzov/home_assistant_delonghi_primadonna#59

@Philmo67
Copy link

Philmo67 commented Feb 1, 2024

Hello,
did someone manage to communicate with some wifi only delonghi coffeelink enabled applicance ?
Here are some API docs https://docs.aylanetworks.com/reference/getting_started
auth_token determination is the key to success...

@duckwc
Copy link

duckwc commented Feb 7, 2024

Hello,
I was able to analyze a bit the traffic between the app and the Delonghi Cloud, thanks to @th4git explanations.
Here is what I identified so far.

Authenticating

the authentication to the API is a 2 steps process:

  1. You have to connect to Delonghi's IDP Gigya
    In my case, this was done while accessing this URL: https://fidm.eu1.gigya.com/oidc/op/v1.0/3_e5qn7USZK-QtsIso1wCelqUKAK_IVEsYshRIssQ-X-k55haiZXmKWDHDRul2e5Y2/authorize?client_id=1S8q1WJEs-emOB43Z0-66WnL&response_type=code&redirect_uri=https://google.it&scope=openid%20email%20profile%20UID%20coffee&nonce=1707250274134

  2. Using the code from the IDP, you transform it to a temporary token by sending it to this URL: https://fidm.eu1.gigya.com/oidc/op/v1.0/3_e5qn7USZK-QtsIso1wCelqUKAK_IVEsYshRIssQ-X-k55haiZXmKWDHDRul2e5Y2/token

  3. You can finally use this token to sign-in to Ayla using this URL: https://user-field-eu.aylanetworks.com/api/v1/token_sign_in
    This will get you a refresh_token that could be saved and used to generate the access_token required to send all requests to https://ads-eu.aylanetworks.com/apiv1

Extracting data

My main purpose would be to monitor the status of the coffee machine.
It seems that most of the information is in the JSON obtained at this URL: https://ads-eu.aylanetworks.com/apiv1/dsns/AC000W02*****69/properties.json

The thing is that most of the information about the status is aggregated in the 'd302_monitor' entry.
Some other values are stored as integer and are easier to retrieve ('d700_tot_bev_b' for example seems to contain the amount of beverages made so far...)

Looking into the APK helped me a bit decyphering the data from 'd302_monitor', but it's still a work in progress.

Just a short addition here, in case it can help someone to go further.

@Philmo67
Copy link

Philmo67 commented Feb 7, 2024

Very nice ! Did you see any chance to directly talk to the coffee machine, through its local IP ? Mine seems to have an open http port.

@duckwc
Copy link

duckwc commented Feb 9, 2024

Very nice ! Did you see any chance to directly talk to the coffee machine, through its local IP ? Mine seems to have an open http port.

As a mater of fact, there is some important local trafic, which seems to include all actions sent to the machine. I was able to capture a bit of it, but everything is encrypted using some RSA keys shared at some point.

The traffic is based on Ayla solution, so I think that understanding the Ayla protocol will be necessary to move further: https://content.aylanetworks.com/Archive/Ayla-Mobile-SDK-Developers-Guide.pdf

To be followed

@duckwc
Copy link

duckwc commented Feb 11, 2024

Well, another update on my debug.
I was finally able to start a local LAN discussion with the machine.

Here is basically the process to do so:

  1. Getting the LAN key shared between the app and the machine. It is saved on the Ayla cloud and can be retrieved using the command https://ads-eu.aylanetworks.com/apiv1/devices/AC00xxxxxxx15/connection_config.json

  2. Establishing a LAN session starts by exchanging keys required to secure it.

  • Sending the command http://xxx/local_reg.json to the machine will trigger this exchange.
  • The machine will contact the described service on /local_lan/key_exchange.json endpoint and send values random_1 and time_1, waiting in return a random_2 and time_2 value.
  1. The exchanged values are used to generate several keys:
  • appCryptoKey (app AES key)
  • appSignKey (app HMAC signing key)
  • appIvSeed (1st IV for AES)
  • devCryptoKey (machine AES key)
  • devSignKey (machine HMAC signing key)
  • devIvSeed (1st IV for AES)
  1. If the keys are correctly received by the machine, next time it receives a call on http://xxx/local_reg.json, it'll interrogate the app on /local_lan/commands.json. My guess is that commands are stacked on the app and sent to the machine that way.
  • Message looks like this

{"seq_no":2,"data":{"properties":[{"property":"base_type":"string","dsn":"AC00xxxxxxx15","name":"device_connected","value":"1707570437"}}]}}

  • The message is then encrypted using AES/CBC with the appCryptoKey (and appIvSeed for the 1st message), signed, and send back to the machine, looking like this:

{"enc":"vjpe0AE/GkckjJCYhO3pLzh/arNEAHoIpRT1otoIODWQy3JrYcYMtD/N59FkYf3q/KJWpY3iKJGoku63T/gEE5VQjPN9TWsjKRCX7toHlL7aPV3puSglnh9p/748riKWquCckQp1RHl3J9/+VZZlHNbWRLdibW4EB8dhUKd5ylvFO5kYRy8XMhBhY1zKTIG6","sign":"kJfMtwuxiJ7WNTd0mJjhVoLgfpihWpVVSZGbF9ev72A="}

This is how far I have been able to push for now.
It looks also like updates to the cloud are also transiting through the app, or are at least initiated by the app.
I spent a lot of time figuring out the way the encryption was working.

I should now be able to debug further and send commands to the machine...

To be continued...

@duckwc
Copy link

duckwc commented Feb 13, 2024

Ahaa, getting closer to the Graal...

So, I found that the commands.json call could return 3 types of messages to command the machine:

{"seq_no":x,"data":{"cmds":[{"cmd":{"cmd_id":2,"data":"","method":"GET","resource":"property.json?name=d302_monitor","uri":"/local_lan/property/datapoint.json"}}]}}

This asks the machine to return the value of the requested property (d302_monitor here)

{"seq_no":x,"data":{"properties":[{"property":{"base_type":"string","dsn":"AC000W030661915","name":"device_connected","value":"1707839356"}}]}}

I don't know yet the usage for this command

{"seq_no":x,"data":{"properties":[{"property":{"base_type":"string","dsn":"AC000W030661915","name":"data_request","value":"xxxxxxxxx\n"}}]}}

This asks the machine to exectute the command xxxxxxxxx.

It seems that these commands follow the same syntax as bluetooth signals.
I was able to wake up the machine by sending 'DQeEDwIBVRJly498\n' string (0d 07 84 0f 02 01 55 12 65 cb 8f 7c) and the bluetooth code I found was [0x0d, 0x07, 0x84, 0x0f, 0x02, 0x01, 0x55, 0x12], so quite close with a short trailing...

I'll now need to wait a bit to get thirsty in order to try the different coffees and get the values. :)

@shaarkys
Copy link

Nice progress @duckwc !

@duckwc
Copy link

duckwc commented Feb 14, 2024

Well here is a small python code that I wrote. webserver.txt
It's basically a small HTTP Requests Handler that includes the following features:

  • Gets local refresh_key or asks the user to first identify to Delonghi's IDP to retrieve it
  • Uses the refresh key to get the LAN key used for encrypting the local traffic between the server and the coffee machine
  • Opens a web server locally (http://127.0.0.1:10280/xxx). The web server should be on the same network as the machine and handles communication with it. I also implemented a couple endpoints to control it:

I'm not a developper, so the code does the job, but is awful. Sorry about it...

If someone with better coding skill than me is interested to take over from here, that would be very nice.

@duckwc
Copy link

duckwc commented Feb 14, 2024

Well, it seems the turn on signal doesn't work anymore. I'll need to figure out the trailing I guess...
The core of the exchange won't probably change a lot...

@behold81
Copy link

If any testing is needed I’m happy to run some tests. Unfortunately I have an iOS device so tracing is a pain.

@oksibutch
Copy link

Wow! It's great that there are people who also want to be able to operate our coffee machine!

I really want to help, but I don't know how

@duckwc
Copy link

duckwc commented Feb 16, 2024

Well, it seems the turn on signal doesn't work anymore. I'll need to figure out the trailing I guess... The core of the exchange won't probably change a lot...

Little addition: the power_on signal bits are 0x0d07840f02015512, and the trailing 0x65cb8f7c seems to simply be the current timestamp.

@duckwc
Copy link

duckwc commented Feb 25, 2024

For those interested in testing and completing the tool, I created a small repository here: https://github.com/duckwc/ECAMpy
It's ugly and messy, but functionnal.
All you need to do is edit the SRV_IP in webserver.py and set your IP in the local network.
You may need to send the commands several times before the machine gets it and executes it.
Feel free to send me any comment about new findings or issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests