API RTE ecowatt

Bonjour,

J'ai un projet qui concerne la récupération de données sur l'API de RTE pour ecowatt (signal qui permet de savoir si le réseau FR est en surcharge ou non, pour ensuite faire du délestage).

J'utilise une carte Arduino MEGA avec un shield ethernet. J'ai déjà fait ce genre de manipulation avec la récupération de données météos sur openweathermap, mais ici je bloque.

L'API ecowatt utilise un token OAUTH pour s'identifier et ensuite faire notre requête. Je bloque à cette étape d'authentification. J'ai fais des tests sur SOAPUI avant et aucun problème :

Mais dès que je passe à la carte Arduino ma requête me renvoie cela :
Parametrage adresse MAC...
Parametrage adresse IP en DHCP...
Initialisation de la carte...
Fin de la configuration de la carte
Adresse IP de la carte Arduino est : 10.2.43.199 , Masque de sous reseau : 255.255.248.0
Get key
Serveur RTE connecte
Resultat recu : HTTP/1.0 302 Found
Location: https://digital.iservices.rte-france.com/token/oauth/
Server: BigIP
Connection: close
Content-Length: 0

Je suis donc dans une impasse j'ai du mal à comprendre le pourquoi ? (je ne suis pas du tout calé en requête HTTP ou en réseau, il est très possible que je n'utilise pas bonne méthode), si quelqu'un saurait me dépanner ou me donner des conseils cela m'aiderait fortement, merci.

Mon code est le suivant :

#include <SPI.h>       // Bibliothèque pour le shield ethernet qui passe par la COM SPI
#include <Ethernet.h>  // Bibliothèque pour shield ethernet

saisissez ou collez du code ici

#include <JsonListener.h>  // Bibliothèque Json qui permet de lire les réponses http
#include <ArduinoJson.h>   // idem

#include <time.h>  // Bibli pour gérer le temps réel sur la carte

int cpt = 1800;  // Compteur pour le nombre d'appel par jour de l'API

char serveur[] = "digital.iservices.rte-france.com";  // Nom de domaine du serveur à intéroger

byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x68, 0xFA };  // Adresse mac marquée sur le shield ethernet
IPAddress ip(10, 2, 46, 252);                         // IP adresse forcée si DHCP ne fonctionne pas

char RTEid[] = "ZDBmNGZkZWEtMzNhZi00ZTFjLTg2NDUtODIwZDdhN2FiN2RmOjNlYjQzNjU1LTg0NmItNDNjYi04N2IzLWFhMTQ5NjczNjNhMg==";//id fournie par RTE
EthernetClient client;  // Définie une variable pour le client ethernet

void setup() 
{
  Serial.begin(9600);  // Démarre le port série sur 9600bauds pour les tests

  char erreur = 0;  // On défini une variable d'erreur qui renvoie 0 si il y a erreu

  erreur = Ethernet.begin(mac);  // Démarre l'ethernet en DHCP donc seulement avec l'adresse mac

  Serial.print("Parametrage adresse MAC");  // Affiche un retour état sur l'écran
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.println(".");
  delay(1000);

  Serial.print("Parametrage adresse IP en DHCP");  // Affiche un retour état sur l'écran
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.println(".");
  delay(1000);

  if (erreur == 0)  // Si on a une erreur sur le paramètrage IP en DHC
  {
    delay(1000);
    Serial.println("Erreur IP en DHCP");                   // Affiche retour état sur l'écran
    Serial.println("Parametrage adresse MAC...");          // Affiche un retour état sur l'écran
    Serial.println("Parametrage IP forcee sans DHCP...");  // Affiche retour état sur l'écran
    Ethernet.begin(mac, ip);                               // Démarre la carte avec notre MAC en forçant l'IP
  }

  Serial.print("Initialisation de la carte");  // Affiche retour état sur l'écran
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.println(".");

  delay(2000);                                            // Pause de 2s le temps d'initialiser la carte
  Serial.println("Fin de la configuration de la carte");  // Affiche retour état sur l'écran
  delay(1000);

  Serial.print("Adresse IP de la carte Arduino est : ");  // Affiche retour état sur l'écran
  Serial.print(Ethernet.localIP());                       // Affiche l'IP en retour état sur l'écran
  Serial.print(" , Masque de sous reseau : ");
  Serial.println(Ethernet.subnetMask());
}

void loop() 
{
  delay(2000);  // Pause de 2s avant de démarrer le programe

  if (cpt >= 3)  // Si le compteur cpt est supérieur ou égale à 1800 (3 pour test)
  {
    getKey();   // On appelle la fonction pour récupérer le token d'identification 
    cpt = 0;    // On remet le compteur à 0
  } 
  else        // Sinon
  {
    cpt++;                        // On incrémente le compteur de 1
    Serial.print("Compteur = ");  // Affiche retour état sur l'écran du compteur
    Serial.println(cpt);          // Ecrit la variable du compteur
  }
}
/*
void getData()//servira que quand le toekn sera récupérer
{
  String result = ""; // Création d'une variable qui permet de stocker le résultat reçu
  EthernetClient client; // Définie l'ethernet en client

  const int httpPort = 80;  // Le port http sur 80

  if (!client.connect(serveur, httpPort))  // Si le client ethernet n'est pas connecté au site par le bon port on quitte le programme
  {
    Serial.println("Serveur RTE injoignable");
    return;  // On sort de la fonction
  }
  Serial.println("Serveur RTE connecte");

  String url = "/open_api/ecowatt/v3/signals";

  client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + serveur + "\r\n" + "Connection: close\r\n\r\n");  // Envoie de la requète au serveur suivant la construction demandé par le site WEB

  unsigned long timeout = millis();  // Compteur de temps pour faire une temporisation

  while (client.available() == 0)  // Tant que le client ne répond pas
  {
    if (millis() - timeout > 5000)  // Si le temps écoulé est supérieur à 5s
    {
      client.stop();  // On stope le client
      Serial.println("Le serveur RTE ne repond pas ");
      return;  // On sort de la fonction
    }
  }

  while (client.available())  // Tant que le client est disponible
  {
    result = client.readStringUntil("\r");  // Result prend la valeur de ce que l'on reçoit par le client tant que l'on a pas reçu \r qui marque la fin de la trame
  }
  Serial.print("Resultat sans decomposition : ");// On affiche un suivi l'écran
  Serial.println(result);// On affiche le résultat reçue par l'API web
  Serial.println("Test");
}
*/
void getKey()
{
  Serial.println("Get key");// test fonction

  String result = "";     // Création d'une variable qui permet de stocké le résultat reçu
  EthernetClient client;  // Définie l'ethernet en client

  const int httpPort = 80;//port http

  if (!client.connect(serveur, httpPort))  // Si le client ethernet n'est pas connecté au site par le bon port on quitte le programme
  {
    Serial.println("Serveur RTE injoignable");
    return;  // On sort de la fonction
  }
  Serial.println("Serveur RTE connecte");

  String url = "/token/oauth/";

  client.print(String("POST ") + url + " HTTP/1.1\r\n" + "Content-Type: application/json\r\n" + "Authorization: Basic " + RTEid + "\r\n" + "Content-Lenght: 0\r\n" + "Host: " + serveur + "\r\n" + "Connection: close\r\n\r\n");  // Envoie de la requète au serveur suivant la construction demandé par le site WEB
  
  //Serial.print("Requete envoyee :");
  //Serial.println(String("POST ") + url + " HTTP/1.1\r\n"+"Content-Type: application/json\r\n"+"Authorization: Basic " + RTEid + "\r\n"+"Content-Length: 0\r\n"+"Host: " + serveur + "\r\n" + "Connection: close\r\n\r\n");
  
  unsigned long timeout = millis();  // Compteur de temps pour tester le temps réponse serveur

  while (client.available() == 0)  // Tant que le client ne répond pas
  {
    if (millis() - timeout > 5000)  // Si le temps écoulé est supérieur à 5s
    {
      client.stop();  // On stope le client
      Serial.println("Le serveur RTE ne repond pas ");
      return;  // On sort de la fonction
    }
  }

  while (client.available())  // Tant que le client est disponible
  {
    result = client.readStringUntil("\r");  // Result prend la valeur de ce que l'on reçoit par le client tant que l'on a pas reçu \r qui marque la fin de la trame
  }
  
  Serial.print("Resultat recu : ");// On affiche un suivi l'écran
  Serial.println(result);// On affiche le résultat reçue par l'API web
  Serial.println("Test");

}

Bonne journée

vous envoyez une requête HTTP alors qu'on dirait qu'ils attendent une requête HTTPS

le shield ethernet V2 ne sait pas faire du TLS et la mega n'a pas les resources pour le faire non plus

Bonjour,

Merci de votre réponse. Existe-il une autre carte Arduino qui serait capable de gérer des requêtes HTTPS ?

L'objectif de mon projet est de sortir un contact en cas de surconsommation, seriez-vous me conseiller sur le type de carte à utiliser ?

Merci de votre aide

Bonne journée

Une MKR WiFi ou un ESP32 savent gérer le https en WiFi

Bonjour, je me suis procuré une carte ESP8266 pour les tests, j'ai vu que certains sur le forum avaient réussi avec cette carte à faire du HTTPS (ma MKR WIFI est toujours en commande).
J'essaie toujours de récupérer mon token d'identification pour mon signal RTE. Voici mon code :

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <JsonListener.h>
#include <time.h>

int cpt = 1800;
const int httpsPort = 443;

char serveur[] = "digital.iservices.rte-france.com";
char RTEid[] = "ZDBmNGZkZWEtMzNhZi00ZTFjLTg2NDUtODIwZDdhN2FiN2RmOjNlYjQzNjU1LTg0NmItNDNjYi04N2IzLWFhMTQ5NjczNjNhMg==";

const char* ssid = "SSID";
const char* password = "password";

String result;

void setup() 
{
  Serial.begin(9600);
  delay(1000);
  WifiSetup();
}

void loop() 
{
  delay(2000);

  if(cpt>3)
  {
    getKey();
    cpt=0;
  }
  else
  {
    cpt++;
    Serial.println(cpt);
  }
}

void getKey()
{
  WiFiClient client;
  delay(1000);
  if(client.connect(serveur, httpsPort))
  {
    Serial.println("Serveur  RTE connecte");
  }
  else
  {
    Serial.println("Probleme connexion serveur RTE");
  }

  String url = "/token/oauth";

  Serial.println(String("POST ") + url + " HTTP/1.1\r\n" + "Authorization: Basic " + RTEid + "\r\n" + "Host: " + serveur + "\r\n" + "Connection: close \r\n\r\n");
  client.print(String("POST ") + url + " HTTP/1.1\r\n" + "Authorization: Basic " + RTEid + "\r\n" + "Host: " + serveur + "\r\n" + "Connection: close \r\n\r\n");
  client.println();

  unsigned long timeout = millis();

  while(client.available()==0)
  {
    if(millis()-timeout>5000)
    {
      Serial.println("Serveur ne repond pas");
      client.stop();
      return;
    }
  }

  while(client.available())
  {
    result=client.readStringUntil('\r');
  }

  Serial.println(result);

}

void WifiSetup()
{
  Serial.printf("Connexion au reseau %s", ssid);
  WiFi.begin(ssid, password);

  while(WiFi.status()!=WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.print("Conncecte au reseau, IP : ");
  Serial.println(WiFi.localIP());
}

Le serveur me répond cela : "400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.

"

Je comprends bien que je dois avoir une erreur de construction de ma requête mais cela sort de mes compétences d'électricien.

Sauriez-vous m'éclairer sur mes erreurs et m'expliqué la marche à suivre pour bien construire mes requêtes https.

Merci beaucoup de votre aide.

Bonne journée

Un exemple de requests HTTPS

J'ai bien décortiqué votre documentation, et j'effectue exactement la même requête mais avec "post". Je ne vois pas pourquoi ma requête HTTP n'est pas reconnue. Je n'ai pas assez de connaissances dans ce domaine mais j'ai besoin de récupérer ces données. Voici ma requête :

client.print(String("POST ") + url + " HTTP/1.1\r\n" + "Authorization: Basic " + RTEid + "\r\n" + "Host: " + serveur + "\r\n" + "Connection: close \r\n\r\n");

Et cela me retourne cette erreur :
Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.

Si quelqu'un peut m'aider sur cette erreur, merci.

vous faites une requête HTTP (non encryptée) alors que le serveur attend une requête HTTPS (cryptée).

c'est pour cela que l'exemple donné plus haut utilise WiFiClientSecure.h et un certificat

D'accord merci beaucoup je commence à comprendre.

Pouvez-vous m'expliquer comment fonctionne un certificat ? Est-il le même sur chaque site ?

Merci de votre réponse

Non chaque site a sa propre identité numérique sous la forme d’un certificat. Il faut donc gérer cette partie de manière spécifique pour le site avec lequel vous voulez discuter.

Expliquer la sécurité et les certificats ne se fait pas en quelques lignes, vous pouvez commencer par lire Certificat électronique — Wikipédia par exemple

Ce post peut vous aider aussi peut être ?

Très bien merci, je vais essayer de comprendre vos documentations.

Petite question, je fais mes tests avec SOAPUI pour tester le retour API sur mon PC et cela fonctionne sans que j'ai eu besoin de fournir un certificat. Comme ci dessous :


Serait-il possible que vous m'expliquer très rapidement pourquoi ?

Sans doute parce que votre logiciel sait gérer le https pour vous (comme les navigateurs web)

image

Avec votre arduino il faut faire les choses « à la main » et lui dire comment valider la connexion et crypter la communication

(Je suis en déplacement - je répond depuis mon iPhone donc je ne peux pas tester ou vous proposer un code simplement)

D'accord, je vois la différence.

Pas de soucis, vous m'êtes déjà d'une très grande aide j'arrive à comprendre pourquoi ça ne marche pas.

Merci

Essayez de prendre le fingerprint de votre site web, cherchez les tutos il doit y en avoir

J'ai lu dans un de vos liens qu'il était possible à des fins de tests de ne pas utiliser de certificats en utilisant :

client.setInsecure(); // NOT RECOMMENDED

Est-ce réellement possible ? Comme j'ai du mal avec les certificats pour le moment, je me contenterai de ce test si cela fonctionne.

Merci de votre aide

Bonne journée

J'ai reçu mon Arduino MKR WIFI que l'on m'a conseillé. Et j'ai découvert que sur cette carte nous pouvions directement entrer un certificat d'un site :

How to add certificates to Wifi Nina/Wifi 101 Modules. – Arduino Help Center

J'espère que cela pourra aider des personnes qui cherchent à interroger un site sous HTTPS.

Dans mon cas, une fois le certificat entré, le site ne répond plus sans que je sache pourquoi.

Merci de votre aide

Bonne journée

Bonjour,

Je continu mes tests, je pense avoir trouvé pas mal de choses. Le lien sur mon post au dessus permet d'intégrer les certificats SSL dans le module WiFi MKR. Il y a également un code dans la bibliothèque WiFiNINA qui permet de tester le SSL. Je me suis servi de cette exemple pour créer mon code.


#include <SPI.h>
#include <WiFiNINA.h>

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key index number (needed only for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "digital.iservices.rte-france.com";    // name address for Google (using DNS)
char RTEid[] = "XXXXX";

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiSSLClient client;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }
  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to WiFi");
  printWiFiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 443)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("POST /token/oauth/ HTTP/1.1");
    client.println("Authorization: Basic XXXXX");
    client.println("Host: digital.iservices.rte-france.com");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.println("Connection: close");
    client.println();
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Cependant le serveur ne répond pas.

7:45:00.323 -> Attempting to connect to SSID: XIAOMI_10_Justin
7:45:00.333 -> Attempting to connect to SSID: XIAOMI_10_Justin
7:45:11.576 -> Connected to WiFi
7:45:22.068 -> SSID: XIAOMI_10_Justin
7:45:22.081 -> IP Address: 192.168.33.254
7:45:22.120 -> signal strength (RSSI):-51 dBm
7:45:22.135 -> 
7:45:22.137 -> Starting connection to server...
7:45:22.139 -> 
7:45:32.559 -> disconnecting from server.

Pour comprendre j'ai directement utiliser l'exemple WiFiSSLClient de la bibliothèque WiFiNINA, qui test une requête chez google.com et la j'ai exactement la même réponse alors que j'utilise l'exemple qui semble être le plus simple du monde. (Et logiquement les exemples de librairie sont forcément fonctionnels ?)

J'ai vérifié que ce n'était pas un soucis sur ma carte, j'ai tester une requête HTTP et cela fonctionne.

J'ai remarqué qu'un anglophone avait déjà eu ce problème sur le forum il y a un an et qu'il s'est "résolu de lui même".

Voila je pense que je ne suis pas loin de réussir mon projet, malgré tout je n'ai pas encore toutes les connaissances nécessaires pour comprendre l'erreur.

J'espère trouver de l'aide ici.

Merci

Bonne journée

Je n’ai pas ce type de carte sous la main pour tester …

J'espère qu'une personne qui possède ce type de carte passera par ici et pourra tester :grin:

Bonjour

espérons .... mais c'est une carte très peu utilisée par les personnes fréquentant ce forum. (carte d'un coût trop élevé, arrivée tard sur le marché, librairie WiFI Nina faiblement soutenue.....
(Il est peu probable qu'un participant actif de ce forum conseille son utilisation)

Les besoins en WIFI (HTTPS inclus) sont en général satisfaits avec des cartes diverses exploitant 'à fond' un ESP32 ou un ESP8266 et cela sous IDE Arduino.