API RTE ecowatt

Bonjour,

Merci de votre réponse. Je comprend effectivement le coût est tout autre qu'un ESP. Cependant le fait que l'on puisse ajouter les certificats des sites web SSL directement par l'IDE facilite grandement les choses.

Je possède d'autres cartes notamment un ESP8266, je n'ai aucun impératif d'utiliser telle ou telle carte, juste un impératif de fonctionnement et de compréhension.

Pour mon niveau gérer les certificats des sites web "en dur" est assez compliqué. J'ai passé beaucoup de temps à lire les documentations que l'on m'a conseillé au dessus mais j'ai du mal à saisir pas mal de choses. C'est pour cela que je me suis replier sur la MKR qui pouvait présenter un avantage.

Je suis donc dans une sorte d'impasse dans mon projet, j'ai essayé énormément de choses pour très peu de résultat c'est assez frustrant même si j'ai beaucoup appris. Je continu mes recherches en espérant trouver les solutions.

Merci

dis moi pourquoi tu cherche a utiliser l'api ECOWATT?

c'est quoi ton projet, tu peux m'en dire plus?

Merci

Bonjour,

Je peux vous expliquer rapidement, je travaille dans une entreprise et RTE nous demande d'intégrer Ecowatt à nos supervisions de chauffage, éclairage, production... Dans le but de réduire drastiquement nos consommations quand RTE nous envoi l'information via cet API.

Cela semble assez simple sauf que nos supervisions sont encapsulées dans des réseaux et ne peuvent pas aller sur internet, pour des problématiques de cybersécurité. (Je ne maitrise pas ce domaine, je suis dans l'énergie).

Donc l'objectif est de récupérer cette donnée en WiFi avec Arduino et de la transmettre en contact sec sur un automate de nos supervision et de réagir en fonction.

J'espère que cela répond à ta question.

oui, merci
Comment tu fais pour reduire

lorsqu'il n'y a pas de probleme les systemes sont en pleine charge
et lorsque le systeme recoit une indication de ECOWATT, vous etes en demi charge par exemple..

C'est pas idiot comme api ecowatt,
j'y reflechis a la mettre en place dans le domaine de la domestique ( chez moi )
mais c'est plus compliqué dans une maison a mettre en place, a mon avis.

Ce projet est encore à l'étude. Mais par exemple baisser de quelques degrés les consignes de chauffe des bâtiments. Une fois que le signal est dans notre supervision, on peut tout imaginer pour faire des économies.

Certaines applications de domotique vont intégrer ce signal directement et si tu as un système de régulation connecté tu pourra baisser ton chauffage de façon automatique. Si tu as un système plus "ancien", tu devras sans doute baisser tes consignes à la main quand tu auras reçu le signal.

Est ce que n’importe qui peut accéder à l’API ECOWATT ?

J’ai vu (rapidement) cela

Mais pas comment créer un compte

——

Édit : j’avais pas vu qu’on pouvait scroller et créer un compte :wink: - je suis sur mon tel

Oui oui exactement, n'importe qui peut créer son compte et récupérer les différentes API de RTE.

Ecowatt utilise un token authentification OAUTH2, tout en bas du site dans aide ils expliquent comment leurs API sont construites.

vous avez un ESP32 pour jouer ?

j'ai lu la doc de leur API, c'est assez simple d'y accéder. je peux vous faire un code si vous voulez (je ne pourrais pas le tester car je suis sur mon téléphone, mais ça ne devrait pas être super compliqué)

Bonjour,

Je possède un ESP8266. C'est si simple que ça ? :sweat_smile:

Merci

Sur un ESP32 c'est simple parce qu'on peut définir le root certificate du site en format PEM directement pour authentifier la connection.

Sur un ESP8266 il faut passer par un fingerprint du root certificat (un hash du certificat) et le souci c'est que ce fingerprint expire en gros tous les ans et il faut recompiler l'application après avoir extrait le nouveau fingerprint. de plus toutes ces opérations de crypto sont coûteuses en temps de calcul et l'ESP8266 n'est pas le mieux placé.

On peut bien sûr passer par la méthode "non sécurisée" avec aucune validation du site distant, à voir cependant si cela est souhaitable dans votre cas puisque vous voulez piloter un site industriel mais vous pourriez être victime d'une arnaque avec un site qui se fait passer pour RTE et vous envoie de fausses informations.

C'est pour cela que je recommanderai un ESP32 pour votre cas et oui dans ce cas le code serait assez simple

  • on extrait le certificat racine (format PEM) de https://digital.iservices.rte-france.com

  • on définit une variable rootCaPem qui contient le texte

  • on crée une instance client de la classe WiFiClientSecure

  • on donne le certificat racine à ce client client.setCACert(rootCaPem);

  • on crée une instance http de la classe HTTPClient

  • on se connecte sur le site oauth de RTE (on fait un appel sur http.begin(client, "https://digital.iservices.rte-france.com/token/oauth/");

  • en suivant la doc RTE on voit qu'il faut faire une requête POST avec 2 éléments de headers particuliers, donc on les ajoute à la requête

  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.addHeader("Authorization", identificationRTE);
  • avec identificationRTE qui est "Basic " + ID Client et ID Secret en base 64 que vous avez extrait de l'interface d'admin de votre compte RTE

  • puis on balance la requête POST (http.POST(nullptr, 0);) pour obtenir le access token RTE valide 2 heures qui permet ensuite d'interroger la base ecowatt

  • en utilisant ArduinoJson on extrait le dit access token et on termine cette première partie

On recommence une seconde requête mais cette fois

  • on se connecte à l'API ecowatt (https://digital.iservices.rte-france.com/open_api/ecowatt/v4/signals)
  • en utilisant le token obtenu dans une requête GET nous dit la doc RTE ➜ il suffit d'un seul header Authorization qui comprend le mot "Bearer " suivi de l'access token obtenu précédemment
  • on balance la requête GET et on obtient un gros JSON en réponse.

si vous pouvez mettre la main sur un ESP32, je veux bien écrire un code de base qui fait ça, ça devrait prendre 10/15 minutes

comme dit plus haut, je suis moins chaud pour le faire sur ESP8266 car à mon avis ça ne répond pas à votre besoin

Bonjour,

Je vous remercie grandement pour vos explications extrêmement détaillées et précieuses. Je vais me procurer un ESP32 ce n'est pas un problème. Encore merci de votre aide.

Petite question suplémentaire si cela ne vous dérange pas. Sur ma carte Arduino MKR j'ai réussi à me connecter sur mon WiFi entreprise avec login et mot de passe. Cette manipulation est elle également possible sur ESP32 ? (Ce n'est pas un problème bloquant pour moi, si cela n'est pas possible je me procurerai une borne WiFi ou une box 5G)

Merci

Bonne journée

Sur ma carte Arduino MKR j'ai réussi à me connecter sur mon WiFi entreprise avec login et mot de passe. Cette manipulation est elle également possible sur ESP32 ?

C'est très probablement possible , mais reste à prouver dans le cas particulier de votre réseau d'entreprise :

Le Module U-blox NINA W-102 est un ESP32 'habillé' et 'tenu en laisse' par la librairie WiFi NINA , un ESP32 'libre' géré sous IDE Arduino avec les librairies ad-hoc devrait probablement faire l'affaire

Ok. tenez voici un code qui je pense devrait marcher. Je n'ai pas pu tester donc vous me direz si ça fonctionne :slight_smile:

il n'y a que 3 lignes à modifier pour adapter cela à votre environnement

const char* ssid =          "**********";
const char* password =      "**********";
#define identificationRTE   "*****************************=="  // ID Client et ID Secret en base 64
  • la première ligne c'est le nom de votre réseau Wi-Fi
  • la deuxième ligne c'est le mot de passe pour y accéder
  • la troisième, c'est ce que vous obtenez d'après la doc que j'ai pu consulter en créant une application dans l'interface web de RTE sous votre compte pour Ecowatt, puis en allant ensuite dans "Mes Applications" et en cliquant sur le bouton "copier en base 64" comme expliqué dans leur tuto vidéo

Puis dans le code j'ai mis l'URL pour la Sandbox (leur environnement de test) mais si vous voulez tester pour de vrai (une requête toutes les 15 minutes seulement) alors vous commentez le premier http.begin (celui de la sandbox) et vous dé-commentez le second.

  // si on veut tester le code sans être gêné par la limite d'un appel toutes les 15 minutes, on utilise la sandbox
   http.begin(client, signalsSandboxURI);

  // si on veut avoir l'information réelle, on utilise la vraie API. On est limité à un appel toutes les 15 minutes
  // http.begin(client, signalsURI);

➜ voici le code

/* ============================================
  KEEP THIS INFORMATION IF YOU USE THIS CODE

  This "API RTE ecowatt" demo code for ESP 32 is placed under the MIT license
  Copyright (c) 2022 J-M-L For the Arduino Forum

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// *****************************************
// *****************************************
//
//     ! ATTENTION ELEMENTS SECRETS !
//
// *****************************************
// *****************************************

const char* ssid =          "**********";
const char* password =      "**********";
#define identificationRTE   "*****************************************************************************=="  // ID Client et ID Secret en base 64

// *****************************************
// *****************************************


const char * idRTE = "Basic " identificationRTE; // le compilateur se charge de concaténer "Basic " + ID Client et ID Secret en base 64

// le certificat racine (format PEM) de https://digital.iservices.rte-france.com
const char* root_ca = \
                      "-----BEGIN CERTIFICATE-----\n" \
                      "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\n" \
                      "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\n" \
                      "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\n" \
                      "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\n" \
                      "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" \
                      "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\n" \
                      "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\n" \
                      "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\n" \
                      "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\n" \
                      "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\n" \
                      "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\n" \
                      "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\n" \
                      "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\n" \
                      "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\n" \
                      "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n" \
                      "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\n" \
                      "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\n" \
                      "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\n" \
                      "WD9f\n" \
                      "-----END CERTIFICATE-----\n";

const char* oauthURI =          "https://digital.iservices.rte-france.com/token/oauth/";
const char* signalsURI =        "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/signals";
const char* signalsSandboxURI = "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/sandbox/signals";


// obtention d'une transcription des codes d'erreurs spécifique à l'API RTE ou message général
String errorDescription(int code, HTTPClient& http) {
  switch (code) {
    case 401: return "l'authentification a échouée";
    case 403: return "l’appelant n’est pas habilité à appeler la ressource";
    case 413: return "La taille de la réponse de la requête dépasse 7Mo";
    case 414: return "L’URI transmise par l’appelant dépasse 2048 caractères";
    case 429: return "Le nombre d’appel maximum dans un certain laps de temps est dépassé";
    case 509: return "L‘ensemble des requêtes des clients atteint la limite maximale";
    default: break;
  }
  return http.errorToString(code);
}

// effectue une requête. Nécessite une connexion WiFi active.

bool getRTEData() {
  String oauthPayload;
  String signalsPayload;
  int codeReponseHTTP;
  const char* access_token;

  bool requeteOK = true;

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFI non disponible. Requête impossible");
    return false;
  }

  WiFiClientSecure client;
  HTTPClient http;

  client.setCACert(root_ca);
  http.begin(client, oauthURI);

  // Specify content-type header
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.addHeader("Authorization", idRTE);

  // Send HTTP POST request
  codeReponseHTTP = http.POST(nullptr, 0);

  if (codeReponseHTTP == HTTP_CODE_OK) {
    oauthPayload = http.getString();
    Serial.println(oauthPayload);

    StaticJsonDocument<192> doc;
    DeserializationError error = deserializeJson(doc, oauthPayload);

    if (error) {
      Serial.print("deserializeJson() failed: ");
      Serial.println(error.c_str());
      access_token = "";
      requeteOK = false;
    } else {
      access_token = doc["access_token"];
      Serial.print("access_token : "); Serial.println(access_token);
    }
  } else {
    Serial.print("erreur HTTP POST: ");
    Serial.println(errorDescription(codeReponseHTTP, http));
    requeteOK = false;
  }

  // on libère les resources
  http.end();

  if (!requeteOK) return false;

  // on a récupéré l'access_token, on peut l'utiliser pour faire notre requête GET sur l'API
  String signalsAutorization = "Bearer ";
  signalsAutorization += String(access_token);

  // si on veut tester le code sans être gêné par la limite d'un appel toutes les 15 minutes, on utilise la sandbox
   http.begin(client, signalsSandboxURI);

  // si on veut avoir l'information réelle, on utilise la vraie API. On est limité à un appel toutes les 15 minutes
  // http.begin(client, signalsURI);

  http.addHeader("Authorization", signalsAutorization.c_str());

  // On envoie la requête HTTP GET
  codeReponseHTTP = http.GET();

  if (codeReponseHTTP == HTTP_CODE_OK) {
    signalsPayload = http.getString();
    Serial.println("----------------------");
    Serial.println("       RTE JSON");
    Serial.println("----------------------\n");
    Serial.println(signalsPayload);
  } else {
    Serial.print("erreur HTTP GET: ");
    Serial.print(codeReponseHTTP);
    Serial.print(" => ");
    Serial.println(http.errorToString(codeReponseHTTP));
    requeteOK = false;
  }
  http.end();
  return requeteOK;
}


void setup() {

  Serial.begin(115200);
  delay(1000);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.write('.');
  }
  Serial.print("\nConnected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  getRTEData();
}

void loop() {}

Si vous chargez cela sur un ESP32, ouvrez le moniteur série à 115200 bauds vous devriez voir d'abord le JSON pour le token puis le JSON correspondant au message Ecowatt.


dites moi si ça fonctionne quand vous aurez reçu votre ESP.

Bonjour,

J'ai reçu mon ESP, je viens de tester votre code, il fonctionne parfaitement.

Je vous remercie grandement de votre aide précieuse.

super ! :slight_smile:

bonne nouvelle

Concernant le parsing avec le Json. Je suis habitué à la V5 de la librairie qui permet d'extraire comme ceci les données :

 StaticJsonBuffer<1024> json_buf;
  
  JsonObject &root = json_buf.parseObject(jsonArray);
  
  if (!root.success())
  {
    Serial.println("parseObject() failed");
  }
  
  String location = root["city"]["name"];

Je me suis documenté sur la nouvelle façon de faire avec la V6 et cela devrait se traduire par cela :

StaticJsonDocument<1024>doc;
  deserializeJson(doc, signalsPayload);

  String valeurjour = doc["signals"]["dvalue"];
  Serial.print("VALEUR DU JOUR ");
  Serial.println(valeurjour);

Cela me retourne NULL, surement du à une incompréhension de ma part de la nouvelle version de la librairie.

si vous n'êtes intéressé que par les valeurs prévues pour les jours, le plus simple c'est d'analyser le flux JSON sous jacent avec un filtre qui ne va extraire que les bonnes données (faudra passer en HTTP 1.0 pour la requête pour éviter le chunking comme expliqué ici).

ça a l'avantage de limiter la consommation mémoire puisqu'on n'a pas à stocker l'intégralité du JSON pour ensuite extraire ce qui nous intéresse.

Si le code précédent fonctionnait, celui ci doit fonctionner aussi, j'extrais normalement les données des jours à venir: la date, le code de ce jour et le message RTE associé

il faut bien sûr remettre comme pour l'autre code vos propres SSID et identifiants.

dites moi si ça fonctionne - je ne peux pas tester :slight_smile:

/* ============================================
  KEEP THIS INFORMATION IF YOU USE THIS CODE

  This "API RTE ecowatt" demo code for ESP 32 is placed under the MIT license
  Copyright (c) 2022 J-M-L For the Arduino Forum

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// *****************************************
// *****************************************
//
//     ! ATTENTION ELEMENTS SECRETS !
//
// *****************************************
// *****************************************

const char* ssid =          "**********";
const char* password =      "**********";
#define identificationRTE   "***************************=="  // ID Client et ID Secret en base 64

// *****************************************
// *****************************************

const char * idRTE = "Basic " identificationRTE; // le compilateur se charge de concaténer "Basic " + ID Client et ID Secret en base 64


// le certificat racine (format PEM) de https://digital.iservices.rte-france.com
const char* root_ca = \
                      "-----BEGIN CERTIFICATE-----\n" \
                      "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\n" \
                      "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\n" \
                      "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\n" \
                      "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\n" \
                      "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" \
                      "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\n" \
                      "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\n" \
                      "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\n" \
                      "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\n" \
                      "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\n" \
                      "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\n" \
                      "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\n" \
                      "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\n" \
                      "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\n" \
                      "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n" \
                      "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\n" \
                      "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\n" \
                      "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\n" \
                      "WD9f\n" \
                      "-----END CERTIFICATE-----\n";

const char* oauthURI =          "https://digital.iservices.rte-france.com/token/oauth/";
const char* signalsURI =        "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/signals";
const char* signalsSandboxURI = "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/sandbox/signals";


// obtention d'une transcription des codes d'erreurs spécifique à l'API RTE ou message général
String errorDescription(int code, HTTPClient& http) {
  switch (code) {
    case 401: return "l'authentification a échouée";
    case 403: return "l’appelant n’est pas habilité à appeler la ressource";
    case 413: return "La taille de la réponse de la requête dépasse 7Mo";
    case 414: return "L’URI transmise par l’appelant dépasse 2048 caractères";
    case 429: return "Le nombre d’appel maximum dans un certain laps de temps est dépassé";
    case 509: return "L‘ensemble des requêtes des clients atteint la limite maximale";
    default: break;
  }
  return http.errorToString(code);
}

// effectue une requête. Nécessite une connexion WiFi active.

bool getRTEData() {
  String oauthPayload;
  String signalsPayload;
  int codeReponseHTTP;
  const char* access_token;

  bool requeteOK = true;

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFI non disponible. Requête impossible");
    return false;
  }

  WiFiClientSecure client;
  HTTPClient http;

  client.setCACert(root_ca);
  http.begin(client, oauthURI);

  // Specify content-type header
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.addHeader("Authorization", idRTE);

  // Send HTTP POST request
  codeReponseHTTP = http.POST(nullptr, 0);

  if (codeReponseHTTP == HTTP_CODE_OK) {
    oauthPayload = http.getString();
    StaticJsonDocument<192> doc;
    DeserializationError error = deserializeJson(doc, oauthPayload);

    if (error) {
      Serial.print("deserializeJson() failed: ");
      Serial.println(error.c_str());
      access_token = "";
      requeteOK = false;
    } else {
      access_token = doc["access_token"];
      // Serial.print("access_token : "); Serial.println(access_token);
    }
  } else {
    Serial.print("erreur HTTP POST: ");
    Serial.println(errorDescription(codeReponseHTTP, http));
    requeteOK = false;
  }

  // on libère les resources
  http.end();

  if (!requeteOK) return false;

  // on a récupéré l'access_token, on peut l'utiliser pour faire notre requête GET sur l'API
  String signalsAutorization = "Bearer ";
  signalsAutorization += String(access_token);

  // cf https://arduinojson.org/v6/how-to/use-arduinojson-with-httpclient/#how-to-parse-a-json-document-from-an-http-response
  http.useHTTP10(true); // pour permettre à ArduinoJSON d'analyser directement le stream sous jacent sinon on a du chunking

  // si on veut tester le code sans être gêné par la limite d'un appel toutes les 15 minutes, on utilise la sandbox
  http.begin(client, signalsSandboxURI);

  // si on veut avoir l'information réelle, on utilise la vraie API. On est limité à un appel toutes les 15 minutes
  // http.begin(client, signalsURI);

  http.addHeader("Authorization", signalsAutorization.c_str());

  // On envoie la requête HTTP GET
  codeReponseHTTP = http.GET();

  if (codeReponseHTTP == HTTP_CODE_OK) {
    Serial.println("-----------------------");
    Serial.println("        ECOWATT        ");
    Serial.println("-----------------------\n");

    // version qui imprime toute le JSON
    // signalsPayload = http.getString();
    // Serial.println(signalsPayload);

    // version qui filtre le JSON obtenu 
    // on va filtrer pour ne conserver que la date et la valeur du jour et le message
    StaticJsonDocument<80> filtre;
    JsonObject filtreSignaux = filtre["signals"].createNestedObject();
    filtreSignaux["jour"] = true;
    filtreSignaux["dvalue"] = true;
    filtreSignaux["message"] = true;

    DynamicJsonDocument doc(1536);
    DeserializationError error = deserializeJson(doc, http.getStream(), DeserializationOption::Filter(filtre));

    if (error) {
      requeteOK = false;
      Serial.print("erreur de deserializeJson() -> ");
      Serial.println(error.c_str());
    } else {

      for (JsonObject signal : doc["signals"].as<JsonArray>()) {
        const char* date = signal["jour"];
        int code = signal["dvalue"];
        const char* message = signal["message"];

        Serial.print(date); Serial.print("\tcode ");
        Serial.print(code); Serial.print("\t(");
        Serial.print(message); Serial.println(").");
      }
    }
  } else {
    Serial.print("erreur HTTP GET: ");
    Serial.print(codeReponseHTTP);
    Serial.print(" => ");
    Serial.println(http.errorToString(codeReponseHTTP));
    requeteOK = false;
  }
  http.end();
  return requeteOK;
}


void setup() {

  Serial.begin(115200);
  delay(2000);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.write('.');
  }
  Serial.print("\nConnected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  getRTEData();
}

void loop() {}

@ukaguf13

PS - le code posté utilise la sandbox, modifier les commentaires ici

  // si on veut tester le code sans être gêné par la limite d'un appel toutes les 15 minutes, on utilise la sandbox
  http.begin(client, signalsSandboxURI);

  // si on veut avoir l'information réelle, on utilise la vraie API. On est limité à un appel toutes les 15 minutes
  // http.begin(client, signalsURI);

si vous voulez passer sur l'instance de production de RTE

Impeccable encore merci de votre aide. Je me suis peut-être mal exprimé mais ce n'est pas forcément les valeurs du jour qui nous intéressent, rien n'est encore réellement défini sur notre fonctionnement par heure ou par jour. Mais votre code est parfait pour tester en jour.

Si nous souhaitons passer en heure, je dois faire la même manipulation en descendant plus bas dans le Json en utilisant "values" puis "pas", c'est bien cela ?

(Je suis en déplacement en ce moment, je ne peux tester mon code que très rapidement)

Plus qu'à réussir à connecter à mon réseau d'entreprise et ce sera bon puis sortir les contacts :grin:

Encore merci de votre aide !

Bonne journée

Oui si l’info est disponible plus granulairement dans l’API il suffit de rajouter ce qu’il faut au filtre

Tant mieux si ça fonctionne et que ça peut être utile pour mieux gérer la consommation électrique