Fiabilité de la récupération des données

bonjour,

comme beaucoup, le plugin a beaucoup de mal a récupérer les données GRDF.

en me connectant sur le site, je remarque que les deux derniers jours ne sont jamais dispos et que le téléchargement ne marche pratiquement jamais.

j’utilise le plugin depuis peu, le site aurait changé ?

ci joint mon log
jazpar.txt (5,1 Mo)

Chez moi, dernière collecte : 2021-11-21 23:55:00

1 « J'aime »

j’ai la même … c’est souvent comme ca ? je veux dire de longs jours sans récup ?

Ça sent une modification chez GRDF.

1 « J'aime »

voilà ce que je crains…

En effet, il semble qu’il y ait eu un changement…
Il va falloir que je me penche sur le problème.
Je fais çà au plus vite mais je manque cruellement de temps en ce moment.
Merci pour votre patience.

3 « J'aime »

Aucune urgence, en ce qui me concerne.

Juste pour dire GRDF modifie son site en pleine saison froide, bravo… les pros

1 « J'aime »

Même pb que vous : dernière connexion et récupération de données le 21/11. :cold_sweat:
Dans les logs, voilà ce que j’ai:

[2021-11-27 11:59:43][INFO] : [Maison][Gaz Maison] 1ère étape d'authentification Jazpar
[2021-11-27 11:59:43][DEBUG] : [Maison][Gaz Maison] Session:
[2021-11-27 11:59:43][INFO] : [Maison][Gaz Maison] 2ème étape d'authentification Jazpar
[2021-11-27 11:59:43][DEBUG] : [Maison][Gaz Maison] JVWS (authent):
[2021-11-27 11:59:43][INFO] : [Maison][Gaz Maison] 3ème étape d'authentification Jazpar
[2021-11-27 11:59:43][DEBUG] : [Maison][Gaz Maison] Token:
[2021-11-27 11:59:43][WARNING] : [Maison][Gaz Maison] Erreur lors de la récupération des informations de session - Abandon - Prochain essai dans 1 heure
[2021-11-27 11:59:43][WARNING] : [Maison][Gaz Maison] Erreur connexion - Abandon - Prochain essai dans 1 heure
1 « J'aime »

meme leur truc n’est pas au point !!

facile de savoir ce qu’il se passe chez ma gamine a 200km …

1 « J'aime »

Pour info sur le forum GRDF… de l’Ambassadeur Royal.
Bonjour,
Il y a un souci technique avec le SI depuis le changement d’interface.
Ce souci est généralisé et concerne tous les clients…
Tout devrait rentrer dans l’ordre la semaine prochaine ou la suivante.
Bon mardi.

ah ben ils sont rassurant sur la rapidité de la maintenance !!! sont meilleurs s’il y a une fuite ?

Du nouveau. Du côté de Domoticz quelqu’un a réécrit un scipt permettant d’accéder au nouveau site de GRDF.

La discussion :

Le script :

1 « J'aime »

en ce qui me concerne, le compteur recommunique bien avec le site grdf mais le plugin ne donne toujours rien

1 « J'aime »

Bonjour

J’ai bien les infos sur le site…mais plus de remontée depuis le 22/11/21

On va attendre la MAJ

Merci pour votre travail

A+

1 « J'aime »

En attendant que quelqu’un ait le temps d’adapter le plugin aux lubies de GRDF, j’ai rapidement adapté le script initialement fait pour Domoticz (cf plus haut). C’est sale et fait dans l’urgence, mais ça fonctionne (enfin, quand le site de GRDF fonctionne). Aussi, si ça peut dépanner quelqu’un en attendant mieux (ne comptez pas sur moi, je n’ai absolument pas le temps de me pencher sur le sujet)…

Script python à faire fonctionner grâce au plugin script (remplacez userName et password par vos identifiants chez GRDF). Modifiez nbDaysImported si 10 jours d’historique ne vous conviennent pas. Le script génère un fichier XML contenant les données. Ne reste plus qu’à exploiter ces données avec un scenario pour alimenter un virtuel et faire ce que vous voulez avec…

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

# (C) v1.0   2021-11-29 Scrat
# (C) v1.2.2 2021-12-04 Scrat 
#  - Fix : Bad login is not detected #8
#  - Fix : Log file will grow indefinitely #7

#
# gazpar.script_python - Récupère les données de consommation sur le site de GRDF
#
# Source : https://github.com/Scrat95220/DomoticzGazpar
# 2021-12-04 - Adaptation pour utilisation avec le plugin Script de Jeedom
# 2021-12-05 - Ajout des corrections de la version v1.2.2

# Note : avant la première utilisation, s'assurer que tous les packages 
#        nécessaires sont bien installés =>
#        apt-get install python3 python3-dateutil python3-requests
#
# Note 2 : !! IMPORTANT !! Pour que le plugin script de Jeedom utilise python3,
#          le nom de fichier ne doit pas se terminer par .py ou .python ou
#          quoique ce soit contenant l'extension .python (même un 
#          .python_quelque_chose). Sinon c'est python2 qui est exécuté

"""Generates energy consumption JSON files from GRDf consumption data
collected via their  website (API).
"""

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import configparser
import os
import requests
import datetime
import logging
import sys
import json
from dateutil.relativedelta import relativedelta

# ---

# URLs
LOGIN_BASE_URI = 'https://login.monespace.grdf.fr/sofit-account-api/api/v1/auth'
API_BASE_URI = 'https://monespace.grdf.fr/'

# ---

# Initialisation des données utilisateurs
userName = ""
password = ""
#
# Nombre de jours de l'historique à importer. Max 1096
nbDaysImported = 10

# ---

script_dir=os.path.dirname(os.path.realpath(__file__)) + os.path.sep

# ---

class GazparServiceException(Exception):
    """Thrown when the webservice threw an exception."""
    pass

# ------------

# Date formatting 
def dtostr(date):
    return date.strftime("%Y-%m-%d")

# ----------

def login():
    """Logs the user into the GRDF API.
    """
    session = requests.Session()

    payload = {
               'email': userName,
                'password': password,
                'goto':'https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code%26scope=openid%20profile%20email%20infotravaux%20%2Fv1%2Faccreditation%20%2Fv1%2Faccreditations%20%2Fdigiconso%2Fv1%20%2Fdigiconso%2Fv1%2Fconsommations%20new_meg%20%2FDemande.read%20%2FDemande.write%26client_id=prod_espaceclient%26state=0%26redirect_uri=https%3A%2F%2Fmonespace.grdf.fr%2F_codexch%26nonce=7cV89oGyWnw28DYdI-702Gjy9f5XdIJ_4dKE_hbsvag%26by_pass_okta=1%26capp=meg', 
                'capp':'meg'
               }
    headers = {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'Referer': 'https://login.monespace.grdf.fr/mire/connexion?goto=https:%2F%2Fsofa-connexion.grdf.fr:443%2Fopenam%2Foauth2%2FexterneGrdf%2Fauthorize%3Fresponse_type%3Dcode%26scope%3Dopenid%2520profile%2520email%2520infotravaux%2520%252Fv1%252Faccreditation%2520%252Fv1%252Faccreditations%2520%252Fdigiconso%252Fv1%2520%252Fdigiconso%252Fv1%252Fconsommations%2520new_meg%2520%252FDemande.read%2520%252FDemande.write%26client_id%3Dprod_espaceclient%26state%3D0%26redirect_uri%3Dhttps%253A%252F%252Fmonespace.grdf.fr%252F_codexch%26nonce%3D7cV89oGyWnw28DYdI-702Gjy9f5XdIJ_4dKE_hbsvag%26by_pass_okta%3D1%26capp%3Dmeg&realm=%2FexterneGrdf&capp=meg'
                }
    
    resp1 = session.post(LOGIN_BASE_URI, data=payload, headers=headers)
    #print (resp1.text)
    if resp1.status_code != requests.codes.ok:
        print("Login call - error status :"+resp1.status_code+'\n');
        logging.error("Login call - error status :"+resp1.status_code+'\n')
        exit()

    j = json.loads(resp1.text)
    if j['state'] != "SUCCESS":
        print("Login call - error status :"+j['state']+'\n');
        logging.error("Login call - error status :"+j['state']+'\n')
        exit()

    #2nd request
    headers = {
                'Referer': 'https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code&scope=openid profile email infotravaux /v1/accreditation /v1/accreditations /digiconso/v1 /digiconso/v1/consommations new_meg /Demande.read /Demande.write&client_id=prod_espaceclient&state=0&redirect_uri=https://monespace.grdf.fr/_codexch&nonce=7cV89oGyWnw28DYdI-702Gjy9f5XdIJ_4dKE_hbsvag&by_pass_okta=1&capp=meg'
                }

    resp2 = session.get(API_BASE_URI, allow_redirects=True)
    if resp2.status_code != requests.codes.ok:
        print("Login 2nd call - error status :"+resp2.status_code+'\n');
        logging.error("Login 2nd call - error status :"+resp2.status_code+'\n')
        exit()

    return session
    
# ----------

def generate_xml(session, start_date, end_date):
    """Retreives monthly energy consumption data."""
    #print('start_date: ' + start_date)
    #print('end_date: ' + end_date)
    
    #3nd request- Get NumPCE
    resp3 = session.get('https://monespace.grdf.fr/api/e-connexion/users/pce/historique-consultation')
    if resp3.status_code != requests.codes.ok:
        print("Get NumPce call - error status :",resp3.status_code, '\n');
        logging.error("Get NumPce call - error status :",resp3.status_code, '\n')
        exit()
    #print(resp3.text)
    
    v_JSON_DATA = json.loads(resp3.text)
    numPce = v_JSON_DATA[0]['numPce']
    
    v_DATA = get_data_with_interval(session, 'Mois', numPce, start_date, end_date)
    
    v_JSON_DATA = json.loads(v_DATA)
   
    # ---

    # Création du début du contenu du fichier XML
    v_CONTENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
    v_CONTENT = v_CONTENT + "<ITEMS>\n"
    v_CONTENT = v_CONTENT + "   <TIME>" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "</TIME>\n" 

    # Extraction de l'historique des données
    for v_ITEM in v_JSON_DATA[str(numPce)]['releves']:
        v_DATE_RELEVE = v_ITEM['journeeGaziere']
        v_KWH = v_ITEM['energieConsomme']
        v_VOLUME = v_ITEM['volumeBrutConsomme']
        v_INDEX_M3_START = v_ITEM['indexDebut']
        v_INDEX_M3_END = v_ITEM['indexFin']
        
        v_CONTENT = v_CONTENT + "   <RELEVE>\n"
        v_CONTENT = v_CONTENT + "      <DATE_RELEVE>" + v_DATE_RELEVE + "</DATE_RELEVE>\n"
        v_CONTENT = v_CONTENT + "      <KWH>" + str(v_KWH) + "</KWH>\n"
        v_CONTENT = v_CONTENT + "      <VOLUME>" + str(v_VOLUME) + "</VOLUME>\n"
        v_CONTENT = v_CONTENT + "      <INDEX_M3_START>" + str(v_INDEX_M3_START) + "</INDEX_M3_START>\n"
        v_CONTENT = v_CONTENT + "      <INDEX_M3_END>" + str(v_INDEX_M3_END) + "</INDEX_M3_END>\n"
        v_CONTENT = v_CONTENT + "   </RELEVE>\n"

    v_CONTENT = v_CONTENT + "</ITEMS>\n"
    
    file = open(script_dir + "gazpar.xml", "w")
    file.write(v_CONTENT)
    file.close()
    logging.info("Fichier XML écrit")

# ----------

def get_data_with_interval(session, resource_id, numPce, start_date=None, end_date=None):
    r=session.get('https://monespace.grdf.fr/api/e-conso/pce/consommation/informatives?dateDebut='+ start_date + '&dateFin=' + end_date + '&pceList[]=' + str(numPce))
    if r.status_code != requests.codes.ok:
        print("Get data - error status :"+r.status_code+'\n');
        logging.error("Get data - error status :",r.status_code, '\n')
        exit()
    return r.text

# ----------

# Main script 
def main():
    #logging.basicConfig(filename=script_dir + '/domoticz_gazpar.log', format='%(asctime)s %(message)s', filemode='w', level=logging.INFO)
    logging.basicConfig(filename=script_dir + '/gazpar.log', format='%(asctime)s %(message)s', filemode='w', level=logging.INFO)

    try:
        # Importation des données utilisateurs et de la plage temporelle des données à récupérer
        #logging.info("Get configuration")
        #get_config()
        
        # Connection au site de GRDF
        logging.info("logging in as %s...", userName)
        token = login()
        logging.info("logged in successfully!")

        today = datetime.date.today()

        # Génération du XML
        logging.info("retrieving data...")
        generate_xml(token, dtostr(today - relativedelta(days=int(nbDaysImported))), dtostr(today))

        logging.info("got data!")

    except GazparServiceException as exc:
        logging.error(exc)
        sys.exit(1)

if __name__ == "__main__":
    main()

Pour exploiter le fichier XML, vous pouvez vous inspirer de ce scénario (naturellement, il faut le virtuel qui va bien) :

# Importe les données d'un compteur Gazpar dans Jeedom. 
# Ces données somt récupérées auprès de GRDF par le script '/var/www/html/plugins/script/data/gazpar/gazpar/gazpar.script_python' activé par le plugin Script
#
# 2021-12-05 - Création

# ----------

# Où trouver les données du compteur Gazpar
$FILE = '/var/www/html/plugins/script/data/gazpar/gazpar.xml';

$INDEX = 0;

# -------------

if ( file_exists($FILE) ) {
  $XML = simplexml_load_file($FILE);
  unset($FILE);
  
  ## Récupération des données du virtuel "compteur gazpar - virtuel"
  #
  # Identification de "compteur-gazpar - virtuel -> date dernier relevé"
  $VIRTUEL_DATE_DERNIER_RELEVE_ID = 1;
  $VIRTUEL_DATE_DERNIER_RELEVE = cmd::byId($VIRTUEL_DATE_DERNIER_RELEVE_ID)->execCmd();
  $VIRTUEL_DATE_DERNIER_RELEVE_TIMESTAMP = strtotime($VIRTUEL_DATE_DERNIER_RELEVE);
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> index"
  $VIRTUEL_INDEX_ID = 2;
  $VIRTUEL_INDEX = cmd::byId($VIRTUEL_INDEX_ID)->execCmd();
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> consommation kwh"
  $VIRTUEL_KWH_ID = 3;
  $VIRTUEL_KWH = cmd::byId($VIRTUEL_KWH_ID)->execCmd();
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> volume"
  $VIRTUEL_VOLUME_ID = 4;
  $VIRTUEL_VOLUME = cmd::byId($VIRTUEL_VOLUME_ID)->execCmd();
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> index m3 start"
  $VIRTUEL_INDEX_M3_START_ID = 5;
  $VIRTUEL_INDEX_M3_START = cmd::byId($VIRTUEL_INDEX_M3_START_ID)->execCmd();
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> index m3 end"
  $VIRTUEL_INDEX_M3_END_ID = 6;
  $VIRTUEL_INDEX_M3_END = cmd::byId($VIRTUEL_INDEX_M3_END_ID)->execCmd();
  #
  # Identification de la valeur du virtuel "compteur gazpar - virtuel -> coefficient conversion"
  $VIRTUEL_COEFF_CONVERSION_ID = 7;
  $VIRTUEL_COEFF_CONVERSION = cmd::byId($VIRTUEL_COEFF_CONVERSION_ID)->execCmd();
  
  # ---

  foreach ( $XML->RELEVE as $ELEMENT ) {
    $GRDF_DATE_RELEVE = (string)$ELEMENT->DATE_RELEVE;
    $GRDF_DATE_RELEVE_TIMESTAMP = strtotime($DATE_RELEVE);
    $GRDF_INDEX_M3_START = (string)$ELEMENT->INDEX_M3_START;
    $GRDF_INDEX_M3_END = (string)$ELEMENT->INDEX_M3_END;
    $GRDF_KWH = (string)$ELEMENT->KWH;
    $GRDF_VOLUME = (string)$ELEMENT->VOLUME;
    if ( $GRDF_KWH > 0 && $GRDF_VOLUME > 0 ) {
      $GRDF_COEFFICIENT_CONVERSION = round($GRDF_KWH / $GRDF_VOLUME, 2);
    } else {
      $GRDF_COEFFICIENT_CONVERSION = 0;
    }
    
    # ---
    
    # Mise à jour de l'historique (supposé vide ou ne contenant qu'une seule valeur)
    $DATE_DEBUT = $GRDF_DATE_RELEVE . ' 00:00:00';
    $DATE_FIN = $GRDF_DATE_RELEVE . ' 23:59:59';
    $DATE_HEURE_RELEVE = $GRDF_DATE_RELEVE . ' 07:00:00';
    #
    # kWh
    $VALEUR = history::getStatistique($VIRTUEL_KWH_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_KWH_ID);
      $CMD->addHistoryValue($GRDF_KWH, $DATE_HEURE_RELEVE);
    }
    #
    # Index
    $VALEUR = history::getStatistique($VIRTUEL_INDEX_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_INDEX_ID);
      $INDEX = $INDEX + $GRDF_KWH;
      $CMD->addHistoryValue($INDEX, $DATE_HEURE_RELEVE);
    } else {
      $INDEX = $VALEUR;
    }
    #
    # Volume
    $VALEUR = history::getStatistique($VIRTUEL_VOLUME_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_VOLUME_ID);
      $CMD->addHistoryValue($GRDF_VOLUME, $DATE_HEURE_RELEVE);
    }
    #
    # Index M3 Start
    $VALEUR = history::getStatistique($VIRTUEL_INDEX_M3_START_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_INDEX_M3_START_ID);
      $CMD->addHistoryValue($GRDF_INDEX_M3_START, $DATE_HEURE_RELEVE);
    }
    #
    # Index M3 End
    $VALEUR = history::getStatistique($VIRTUEL_INDEX_M3_END_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_INDEX_M3_END_ID);
      $CMD->addHistoryValue($GRDF_INDEX_M3_END, $DATE_HEURE_RELEVE);
    }
    #
    # Coefficient de convertion
    $VALEUR = history::getStatistique($VIRTUEL_COEFF_CONVERSION_ID, $DATE_DEBUT, $DATE_FIN)["max"];
    if ( ! isset($VALEUR) || empty($VALEUR) ) {
      $CMD = cmd::byID($VIRTUEL_COEFF_CONVERSION_ID);
      $CMD->addHistoryValue($GRDF_COEFFICIENT_CONVERSION, $DATE_HEURE_RELEVE);
    }
    
    # ---
    
    # Mise à jour du Virtuel
    # À gérer plus tard -> if ( $DATE_RELEVE_TIMESTAMP > $VIRTUEL_DATE_DERNIER_RELEVE_TIMESTAMP ) { 
      cmd::byId($VIRTUEL_DATE_DERNIER_RELEVE_ID)->event($DATE_HEURE_RELEVE);
      cmd::byId($VIRTUEL_KWH_ID)->event($GRDF_KWH, $DATE_HEURE_RELEVE);
      cmd::byID($VIRTUEL_VOLUME_ID)->event($GRDF_VOLUME, $DATE_HEURE_RELEVE);
      cmd::byID($VIRTUEL_INDEX_ID)->event($INDEX, $DATE_HEURE_RELEVE);
      cmd::byID($VIRTUEL_INDEX_M3_START_ID)->event($GRDF_INDEX_M3_START, $DATE_HEURE_RELEVE);
      cmd::byID($VIRTUEL_INDEX_M3_END_ID)->event($GRDF_INDEX_M3_END, $DATE_HEURE_RELEVE);
      cmd::byID($VIRTUEL_COEFF_CONVERSION_ID)->event($GRDF_COEFFICIENT_CONVERSION, $DATE_HEURE_RELEVE);    }
  #}
  unset($XML);
}

PS oui, mon code est dégueux. Pas le temps de faire mieux.

2 « J'aime »

J’ai avancé et devrais pouvoir fournir une nouvelle version d’ici 2 semaines

8 « J'aime »

hello @hugoKs3,
je viens de tester la beta, j’ai shooté tous les histo et j’ai relancé (en mode recuperation des anciennes valeurs pour remettre mes histo)
le plugin recupere bien les valeurs (les plus anciennes et les plus récentes) tjs en fonction de ce que permet grdf (souvent bien en retard !)
c’est top ! pour le moment, pas de bug et je verrai si j’ai des logs bizarre dans les prochains jours !
merci !

1 « J'aime »

Bonjour
J’ai reinstallé le plugin apres suppression de la version precedente.
J’ai deux messages d’erreur

  1. 500 Internal error serveur lors de chaque sauvegarde de mon équipement
  2. Erreur sur la fonction cron du plugin : Call to a member function getId() on bool
    Par contre il semble bien fonctionner
    Est ce normal ?
    Merci de vos conseils