Contexte
Les machines a cafe connectees De’Longhi (gamme ECAM) utilisent le cloud Ayla Networks pour la communication WiFi et le Bluetooth Low Energy pour le controle local. Aucune documentation publique n’existe sur le protocole. L’application officielle De’Longhi Coffee Link est la seule interface disponible.
La machine cible : une De’Longhi Eletta Explore ECAM 450.65.S, connectee en WiFi au reseau local, avec un firmware ADA 1.6 base sur esp-idf v3.3.1 (ESP32).
L’objectif : creer une integration Home Assistant pour controler la machine sans dependre de l’app officielle.
Methodologie
1. Decompilation de l’APK Android
L’application De’Longhi Coffee Link pour Android a ete decompilee avec jadx. L’analyse du code Java/Kotlin a revele :
- Le format de commande brew utilise le prefixe
0x83avec des paires parametre ID/valeur - Le flux d’authentification : SSO via Gigya (SAP CDC) → token JWT → echange contre un token Ayla
- La structure des messages BLE et la couche de chiffrement AES
- Les endpoints API cloud :
ads-eu.aylanetworks.com(EU) etads-field.aylanetworks.com(US)
Pour contourner le certificate pinning, l’APK a ete patchee avec apktool et resignee. Cela a permis l’interception HTTPS.
2. Interception du trafic cloud
En configurant mitmproxy avec un certificat custom installe sur un appareil de test, j’ai capture le flux d’authentification complet :
- Authentification Gigya :
POST accounts.eu1.gigya.com/accounts.login→ retourne unid_tokenJWT - Echange de token :
POST user-field-eu.aylanetworks.com/api/v1/token_sign_in.jsonavec le JWT → retourne unaccess_tokenAyla - Listing des devices :
GET ads-eu.aylanetworks.com/apiv1/devices.json→ retourne le DSN (Device Serial Number) et les proprietes - Envoi de commandes :
POST ads-eu.aylanetworks.com/apiv1/dsns/{DSN}/properties/app_data_request/datapoints.json
Le format de chaque commande WiFi est :
[ECAM_bytes] + [4 bytes timestamp big-endian (Unix)] + [4 bytes app_id: 0x20 0x40 0x35 0xEF]
Le tout encode en Base64 et envoye comme valeur du datapoint.
3. Reverse du format de commande 0x83
Le format de commande brew a ete le plus complexe a reverser. Il a fallu croiser la decompilation jadx avec 9 captures MITM de differentes boissons pour comprendre la conversion recette → brew :
Format Recipe (0xA6) — stocke dans l’app :
[0xD0][len][0xA6][0xF0][profile][bev_id][param_pairs][CRC-16]
Format Brew (0x83) — envoye a la machine :
[0x0D][len][0x83][0xF0][bev_id][action][param_pairs][profile_save][CRC-16]
Les parametres sont encodes en paires ID/valeur :
- 8-bit :
[param_id][value](2 octets) — ex: intensite, temperature - 16-bit :
[param_id][value_hi][value_lo](3 octets) — pour COFFEE(1), MILK(9), HOT_WATER(15)
Regles de conversion decodees :
- Extraire le
bev_idde la recette - Parser les param pairs
- Exclure le parametre VISIBLE(25)
- Pour les boissons glacees : exclure COFFEE/MILK/HOT_WATER, ajouter ICED(31)
- Ajouter RINSE(39)=1
- CRC : CRC-16/SPI-FUJITSU
La conversion a ete validee byte-for-byte sur 9 captures MITM : espresso, hot_water, tea, iced americano, iced cappuccino, cold brew original, cold brew intense, cold brew to mix, americano froid.
4. Analyse BLE
Avec nRF Connect sur Android, j’ai capture les echanges BLE entre l’app et la machine. Les commandes suivent un format structure avec :
- Un header de commande (type + longueur)
- Le payload chiffre en AES-256-CBC
- Un key exchange initial sur le port 6682 pour le mode LAN
Le protocole BLE/LAN n’est pas encore implemente dans l’integration (en cours de developpement).
Resultats
Integration Home Assistant
L’integration finale expose :
| Type | Nombre | Exemples |
|---|---|---|
| Capteurs | 30 | Temperature, compteur cafes, progression detartrage, filtre |
| Capteurs binaires | 19 | Plateau plein, reservoir vide, porte ouverte, module lait absent |
| Boutons | 50+ | Un par boisson, auto-decouverts depuis la machine |
| Switch | 1 | Power on/off |
Chaque commande brew inclut des pre-brew safety checks : machine eteinte/occupee/en detartrage, reservoir vide, bac a marc plein, grains vides, plateau absent, accessoire lait manquant pour les boissons au lait.
Compatibilite
Testee et validee par la communaute sur :
- De’Longhi Eletta Explore ECAM 450.65.S
- De’Longhi PrimaDonna Soul
- Plusieurs autres modeles ECAM (retours utilisateurs en cours)
L’integration supporte les regions EU et US (endpoints Ayla differents), et est traduite en 16 langues.
Communaute & Contributeurs
Ce projet n’aurait pas atteint ce niveau sans les retours et tests de la communaute :
| Contributeur | Contribution |
|---|---|
| MattG-K | Documentation protocole independante (dlghiot) — algorithme CRC-16/SPI-FUJITSU, table de request IDs, commande standby. A economise des heures de reverse. |
| silvanverschuur | Premier testeur externe — a valide power on/off sur Eletta Explore, confirme la reactivite superieure a l’app officielle (#1) |
| geekofweek | A expose le probleme multi-region en capturant les appels DNS depuis l’app officielle — a mene au support US (#2) |
| agarthand | Tests sur PrimaDonna Soul, retours compteurs manquants (#3), signalement rate limiting cloud (#9) |
| jostrasser | A aide a decouvrir les noms de proprietes legacy (data_request vs app_data_request) sur PrimaDonna Soul (#5) |
Publication
Le code est publie en open-source :
- Repository : github.com/sk7n4k3d/delonghi-ha — 17 stars
- Installation : via HACS (Home Assistant Community Store) ou copie manuelle
- Licence : MIT
Outils utilises
| Outil | Usage | Lien |
|---|---|---|
| jadx | Decompilation APK Android | github.com/skylot/jadx |
| apktool | Patch APK (bypass cert pinning) | apktool.org |
| mitmproxy | Interception HTTPS | mitmproxy.org |
| nRF Connect | Analyse BLE | nordicsemi.com |
| Wireshark | Analyse de paquets | wireshark.org |
| Python | Integration Home Assistant | python.org |
| CRC RevEng | Identification CRC-16 | reveng.sourceforge.io |