Aldes Connect API

[EDIT 01/11/2021]

Bonjour,
Attention, Aldes a récemment effectué une mise à jour de son API (MaJ non identifiée pour le moment) avec beaucoup d’instabilité : la sauvegarde des consignes thermostats n’est pas « stable », elle change sans raison. Ma procédure (topic du 15 aout) reste quand d’actualité mais, il faut trouver une « bidouille » pour conserver les consignes.
Cordialement


Bonsoir,
Vu que Aldes ne propose pas d’API, je me suis amusé à prendre l’APK Aldes Connect.
J’ai décompilé l’APK, et avec un éditeur de code, je cherche comment se connecter à l’API via Postman.
J’ai récupéré les informations suivantes :

URL : https://aldesiotsuite-aldeswebapi.azurewebsites.net/oauth2/token?grant_type=password
Header Content-Type : application/x-www-form-urlencoded

J’ai bien entendu un compte pour tester via Postman. Justement, dans Postman, il me retourne une erreur du type : "The mandatory ‹ grant_type › parameter is missing’. Quand je passe en paramètre ‹ grant_type › et une valeur bidon, toujours le même message.

J’ai également récupéré le code Java de ce qui pour moi est la fonction d’authentification, si ca peut aider :

.class public interface abstract Lcom/keyrus/aldes/data/net/apis/authentication/AuthApi;
.super Ljava/lang/Object;
.source "AuthApi.kt"


# annotations
.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Lcom/keyrus/aldes/data/net/apis/authentication/AuthApi$DefaultImpls;
    }
.end annotation

.annotation runtime Lkotlin/Metadata;
    bv = {
        0x1,
        0x0,
        0x3
    }
    d1 = {
        "\u0000$\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\u0008\u0003\n\u0002\u0018\u0002\n\u0002\u0008\u0006\u0008f\u0018\u00002\u00020\u0001J,\u0010\u0002\u001a\u0008\u0012\u0004\u0012\u00020\u00040\u00032\u0008\u0008\u0001\u0010\u0005\u001a\u00020\u00062\u0008\u0008\u0001\u0010\u0007\u001a\u00020\u00062\u0008\u0008\u0001\u0010\u0008\u001a\u00020\u0006H\'JP\u0010\t\u001a\u000e\u0012\n\u0012\u0008\u0012\u0004\u0012\u00020\u00010\n0\u00032\u0008\u0008\u0001\u0010\u000b\u001a\u00020\u00062\u0008\u0008\u0001\u0010\u000c\u001a\u00020\u00062\u0008\u0008\u0001\u0010\r\u001a\u00020\u00062\u0008\u0008\u0001\u0010\u000e\u001a\u00020\u00062\u0008\u0008\u0003\u0010\u000f\u001a\u00020\u00062\u0008\u0008\u0003\u0010\u0008\u001a\u00020\u0006H\'\u00a8\u0006\u0010"
    }
    d2 = {
        "Lcom/keyrus/aldes/data/net/apis/authentication/AuthApi;",
        "",
        "authentication",
        "Lio/reactivex/Single;",
        "Lcom/keyrus/aldes/data/database/models/Token;",
        "email",
        "",
        "password",
        "grantType",
        "authorization",
        "Lretrofit2/Response;",
        "clientId",
        "clientSecret",
        "productMacAddress",
        "redirectUri",
        "responseType",
        "app_aldesProdRelease"
    }
    k = 0x1
    mv = {
        0x1,
        0x4,
        0x0
    }
.end annotation


# virtual methods
.method public abstract authentication(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/reactivex/Single;
    .param p1    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "username"
        .end annotation
    .end param
    .param p2    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "password"
        .end annotation
    .end param
    .param p3    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "grant_type"
        .end annotation
    .end param
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "(",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            ")",
            "Lio/reactivex/Single<",
            "Lcom/keyrus/aldes/data/database/models/Token;",
            ">;"
        }
    .end annotation

    .annotation runtime Lretrofit2/http/FormUrlEncoded;
    .end annotation

    .annotation runtime Lretrofit2/http/POST;
        value = "/oauth2/token"
    .end annotation
.end method

.method public abstract authorization(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/reactivex/Single;
    .param p1    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "client_id"
        .end annotation
    .end param
    .param p2    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "client_secret"
        .end annotation
    .end param
    .param p3    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "product_mac_address"
        .end annotation
    .end param
    .param p4    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "redirect_uri"
        .end annotation
    .end param
    .param p5    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "response_type"
        .end annotation
    .end param
    .param p6    # Ljava/lang/String;
        .annotation runtime Lretrofit2/http/Field;
            value = "grant_type"
        .end annotation
    .end param
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "(",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            "Ljava/lang/String;",
            ")",
            "Lio/reactivex/Single<",
            "Lretrofit2/Response<",
            "Ljava/lang/Object;",
            ">;>;"
        }
    .end annotation

    .annotation runtime Lretrofit2/http/FormUrlEncoded;
    .end annotation

    .annotation runtime Lretrofit2/http/POST;
        value = "/oauth2/authorize"
    .end annotation
.end method

Bonjour,
C’est un appel oauth, protocol d’authentification connu.
Le type « password » est un des flow d’authentification possible avec oauth.
La valeur à passer est donc « password » en toute lettre puisque c’est ce que l’app utilise (ce qui est logique pour une app).

Je n’ai pas les liens sous la main (smartphone) mais une recherche sur internet et tu trouveras de la doc. C’est un peu complex a bien comprendre au début donc bien relire plusieurs fois et plusieurs source pour maîtriser les principes

Salut,

Merci pour ta réponse.
Je passe bien grant_type=‹ password › dans Postman, mais j’ai toujours le retour comme quoi le paramètre est manquant.
Ci-joint mon call :
https://aldesiotsuite-aldeswebapi.azurewebsites.net/oauth2/token/?username=XXX@XXXX.com&password=UYUYUYUY&grant_type=password

Il faut un clientId en principe.
As-tu lu de la doc sur le sujet comme recommandé?

Désolé, j’ai rapidement consulté quelques sites, je m’y penche ce soir.
Par contre, je ne connais pas mon clientID vu que j’ai rollback une APK Android.
Tu penses que je peux le récupérer quelques part.
Je vais me tenter un « truc » : monter un proxy, lancer l’apps sur mon smartphone et sniffer les flux http pour voir ce que je peux interpréter.

Oui ca va être le problème avec oauth, soit il faut « voler » le clientid de l’app en esperant qu’il n’y ait pas un certif pour protéger le clientsecret soit … c’est compliqué parce que c’est justement un des principes de oauth: chaque app doit être connue et identifiée donc tu ne peux pas avoir une app qui se connecte avec le mot de passe de quelqu’un si elle n’est pas de confiance;
c’est ce qui garanti en partie la sécurité du système.

1 « J'aime »

Bon, bon, j’ai mis en place le proxy, un exemple de flux capturé et je crois que je vais en rester la :

Je vais tenter de contacter Aldes, pour obtenir des infos (même si je n’espère rien), et également avoir plus de précisions sur la compatibilité avec Tydom.

Tiens d’ailleurs, quelqu’un a des infos : Aldes + Tydom ?

Merci

Salut,

Je viens de tester, il ne te manquait pas grand-chose. Il ne fallait juste pas passer les paramètres par l’url comme c’est un POST.

Exemple :

ça retourne bien un access_token. Merci en tout cas ça ma bien aidé :slightly_smiling_face:

1 « J'aime »

Salut,

Ah punaise, tu as réussi ?

Tu peux détailler stp ?

merci

Edit : j’ai réussi également, merci pour l’info.

Maintenant, tu sais comment « parser » l’API ?

Bonjour,
Pour information, j’ai réussi à communiquer avec l’API Aldes, merci à @tdugue pour l’indice sur l’authentification.
J’ai récupéré le swagger de l’API, j’implémente cela dans Jeedom, et tout devrait être opérationnel asap.
Je vais surement partager mes informations, j’hésite carrément à en faire un plugin Jeedom, mais je ne me sens pas capable de le faire.
Merci

1 « J'aime »

Bonjour,

Merci pour les infos partagées. j’ai également un T One et je suis intéressé pour récupérer les infos autrement que via l’application smartphone. J’ai également réussi à récupérer le token mais il y a une autre partie d’authentification et je serais intéressé de savoir si tu as réussi à la passer (visiblement il faut un client_id).
Merci

intéréssé aussi car j’ai un chauffe eau compatible Aldes Connect.

Bonsoir,

Voici « une procédure » qui fonctionne pour moi, et qui bien entendu est à optimiser.
Je rajoute à la suite de ce post des éléments supplémentaires (dans un nouveau post)
Je met pour exemple des scripts PHP avec CURL.

1 - Récupération du TOKEN (Bearer Token) à partir de vos identifiants Aldes Connect :

URL: https://aldesiotsuite-aldeswebapi.azurewebsites.net/oauth2/token/
Méthode : POST
Réponse : token (Bearer Token)
Précisions :

  • Je ne connais pas la durée de validité, je renouvelle tous les 24h
  • Votre token est à conserver pour la suite et à passer en paramètre dans tous les appels API
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://aldesiotsuite-aldeswebapi.azurewebsites.net/oauth2/token/',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => 'grant_type=password&username=VOTREEMAIL&password=VOTREMOTDEPASSE',
  CURLOPT_HTTPHEADER => array(
    'Content-Type: application/x-www-form-urlencoded'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

?>

2 - Récupération du USERID et du DEVICEID à partir du TOKEN

URL : https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/notification/preferences
Méthode : GET
Réponse :

 {
>     "userId": "XXXXX",
>     "userProductPreferences": [
>         {
>             "deviceId": "YYYYYYYY",
>             "receiveFilterAlert": false,
>             "receiveDysfunctionAlert": false,
>             "receiveFilterAlertSurvey": false
>         }
>     ],
>     "needUpdate": {
>         "message": "Your app is outdated please update it using the app store and try again",
>         "storeAndroid": "https://play.google.com/store",
>         "storeApple": "http://appstore.com/aldes"
>     }
> }

Précision :

  • Idem que pour le token, il faut récupérer USERSID et DEVICEID pour la suite

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/notification/preferences',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: Bearer VOTRETOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

?>

3 - Obtenir toutes les infos des produits sur votre compte ALDES CONNECT

URL : https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/products
Méthode : GET
Réponse :

 [
>     {
>         "slaves": [],
>         "masters": [],
>         "indicators": [
>             {
>                 "date": "2021-08-11T19:11:07.741Z",
>                 "type": "WATER_QUANTITY",
>                 "value": 75
>             },
>             {
>                 "date": "2021-08-11T19:11:07.741Z",
>                 "type": "TEMPERATURE",
>                 "value": 24.12
>             },
>             {
>                 "date": "2021-08-12T18:31:31.068Z",
>                 "type": "CLOUD_CONTROLLED",
>                 "value": null
>             },
>             {
>                 "date": "2021-08-12T18:31:31.253Z",
>                 "type": "SELF_CONTROLLED",
>                 "value": false
>             }
>         ],
>         "indicator": {
>             "fmist": 22.0,
>             "fmast": 31.0,
>             "cmast": 24.0,
>             "cmist": 16.0,
>             "date_debut_vac": null,
>             "date_fin_vac": null,
>             "hors_gel": false,
>             "qte_eau_chaude": 75,
>             "tmp_principal": 24.12,
>             "current_air_mode": "F",
>             "current_water_mode": "M",
>             "thermostats": [
>                 {
>                     "ThermostatId": 622,
>                     "Name": null,
>                     "Type": null,
>                     "Order": 0,
>                     "IconId": 0,
>                     "Number": 0,
>                     "TemperatureSet": 24,
>                     "CurrentTemperature": 24.12
>                 },
>                 {
>                     "ThermostatId": 623,
>                     "Name": null,
>                     "Type": null,
>                     "Order": 0,
>                     "IconId": 0,
>                     "Number": 1,
>                     "TemperatureSet": 25,
>                     "CurrentTemperature": 24.62
>                 },
>                 {
>                     "ThermostatId": 624,
>                     "Name": null,
>                     "Type": null,
>                     "Order": 0,
>                     "IconId": 0,
>                     "Number": 2,
>                     "TemperatureSet": 24,
>                     "CurrentTemperature": 24.18
>                 },
>                 {
>                     "ThermostatId": 625,
>                     "Name": null,
>                     "Type": null,
>                     "Order": 0,
>                     "IconId": 0,
>                     "Number": 3,
>                     "TemperatureSet": 24,
>                     "CurrentTemperature": 24.6
>                 },
>                 {
>                     "ThermostatId": 626,
>                     "Name": null,
>                     "Type": null,
>                     "Order": 0,
>                     "IconId": 0,
>                     "Number": 4,
>                     "TemperatureSet": 26,
>                     "CurrentTemperature": 24.43
>                 }
>             ],
>             "settings": {
>                 "dateTime": null,
>                 "people": 3,
>                 "currency": 0,
>                 "antilegio": 0,
>                 "kwh_creuse": 0.15,
>                 "kwh_pleine": 0.15
>             },
>             "indicatorType": "TONE_Indicator"
>         },
>         "thermostats": null,
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/products',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: Bearer VOTRE TOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

4 - Mise à jour des thermostats dans le cas d’un T-ONE ALDES

URL : https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/products/VOTREDEVICEID/updateThermostats
Méthode : PATH
Paramètres : [{« ThermostatId »: « 622 »,« TemperatureSet »: 25}]
Précisions :

  • Il faut récupérer le ThermostatId du point 3
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://aldesiotsuite-aldeswebapi.azurewebsites.net/aldesoc/v5/users/me/products/VOTREDEVICEID/updateThermostats',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_POSTFIELDS =>' [{"ThermostatId": "VOTRE THERMOSTAT","TemperatureSet": VOTRE TEMPERATURE}]',
  CURLOPT_HTTPHEADER => array(
    'Content-Type: application/json',
    'Authorization: Bearer VOTRETOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Pour les précisions complémentaires :

Pour vos tests, utilisez POSTMAN pour vous familiariser avec l’API et réaliser les tests en live sur vos installations.

Pour l’intégration dans Jeedom :

  • A l’aide du plugin Virtuel, j’ai défini chaque thermostats de la maison avec des actions + et - ainsi que la consigne

  • A l’aide du plugin script, j’ai rattaché à chaque thermostats un script PHP qui permet d’appeler l’URL de l’API permettant de mettre à jour les consignes

  • Toujours à l’aide du plugin script, j’ai un défini un script qui appelle un script PHP, permettant de faire un refresh des valeurs de l’API (à l’aide d’un scénario)

  • Point important : les temps de latences entre votre module Wifi et l’API, et l’API et le module Wifi, qui est de l’ordre de plusieurs minutes (entre 5 et 10), donc n’hésitez pas à mettre du délai dans les mises à jours

  • Autre point important : l’API n’apprécie pas vraiment des mises à jour multiples et à la chaine, donc idem, rajouter du délai dans les mises à jours

Je crois que j’ai tout dis, je finalise l’automatisation en fonction de la température extérieur, pour ajuster ma climatisation et je suis tout bon.
Par contre attention, il ne s’agit pas d’implémenter un thermostat dans Jeedom, car vous avez déjà des thermostats physiques.

L’idée géniale serait de créer un plugin, mais je ne suis pas du tout compétent pour le faire, du moins, je ne sais pas par ou commencer (je suis un papi développeur maintenant).

J’ai oublié un point, j’ai un semblant de swagger si cela vous interresse pour expérimenter de nouvelles URL. A utiliser avec des pincettes, car cela peut vite partir en cacahuète.Swagger.txt (268,2 Ko)

Bonjour,

Un GRAND, un ÉNORME MERCI à toi !! C’est vraiment super !
J’ai essayé de mon côté tout fonctionne également.
Mon but dans un premier temps c’est de récupérer les températures ambiantes et de les logger car je viens de faire construire une maison neuve et je veux voir comment ça réagit.

Encore merci !

1 « J'aime »

Salut,

Pour info,le token est valable 30 jours visiblement (car le paramètre expires_in est exprimé en secondes)
« expires_in »: 2592000
donc /3600/24 => 30

1 « J'aime »

Good, personne n’est chaud pour faire un plugin avec moi ? :slight_smile:

Ca serait un beau défi ! non ? et je ferai la « pige » à Aldes avec leur merdouille d’application Aldes Connect à 2 € (alors que leur matos coute plusieurs k€).

A plus sous le bus (#ringard)

3 « J'aime »

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.