Closed echauvet closed 2 years ago
Bonjour Eric. En effet, GRDF a changé le design du site. Le script gazpar.py doit être complètement revu. Je n'ai encore aucune idée de comment faire. Alors toute aide est la bienvenue et je te remercie pour ton message.
J'ai créé une branche 0.5 pour travailler sur ce redesign. Vous pourriez forker depuis cette branche.
Pour le moment l'authentification fonctionne. Il semble que ce soit plus simple qu'avec l'ancienne version... A confirmer.
Ca y est, je parviens à avoir la liste de mes PCE et mes conso jour par jour : Appel 1: session.get('https://monespace.grdf.fr/client/particulier/accueil') -> pour récupérer auth_nonce = session.cookies.get('auth_nonce') Appel 2: payload = { 'email': 'mail@mail.com', 'password': 'password', 'capp': 'meg', 'goto': 'https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code&scope=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&client_id=prod_espaceclient&state=0&redirect_uri=https%3A%2F%2Fmonespace.grdf.fr%2F_codexch&nonce=' + auth_nonce + '&by_pass_okta=1&capp=meg' } req = session.post(LOGIN_BASE_URI, data=payload, allow_redirects=False) -> Pour s'authentifier, mais cela ne suffit pas, il faut également : Appel 3: req = session.get('https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code&scope=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&client_id=prod_espaceclient&state=0&redirect_uri=https%3A%2F%2Fmonespace.grdf.fr%2F_codexch&nonce=' + auth_nonce + '&by_pass_okta=1&capp=meg') -> On récupère d'autres cookies Appel 4: req = session.get('https://monespace.grdf.fr/api/e-connexion/users/whoami') -> Toutes les données contractuelles en JSON Appel 5: req = session.get('https://monespace.grdf.fr/api/e-conso/pce') ->liste des pce Appel 6: req = session.get('https://monespace.grdf.fr/api/e-conso/pce/consommation/informatives?dateDebut=2018-11-27&dateFin=2021-11-27&pceList%5B%5D=NUMERO(S)_DE_PCE_DE_L_APPEL_PRECEDENT') -> Toutes les données entre ces dates jour par jour (3 ans max)
PoC: Voici le code modifié de login@gazpar.py pour démontrer la chaîne complète. Il suffit de remplacer MAIL, PASS et PCE pour obtenir de jolis JSON qui contiennent tout ce qu'il faut. J'ai l'impression que cela pourra être plus facile à maintenir car simple par rapport au client web qui télécharge les données. En tout cas, c'est beaucoup plus rapide :) Comment veux tu qu'on avance?
def login(username, password):
"""Logs the user into the Linky API.
"""
global JAVAVXS
session = requests.Session()
session.headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Mobile Safari/537.36',
'Accept-Encoding':'gzip, deflate, br',
'Accept':'application/json, */*',
'Connection': 'keep-alive'
}
#Get essential cookies
req = session.get('https://monespace.grdf.fr/client/particulier/accueil')
if not 'auth_nonce' in session.cookies:
raise GazparLoginException("Cannot get auth_nonce.")
auth_nonce = session.cookies.get('auth_nonce')
logging.info("auth_nonce: " + auth_nonce)
payload = {
'email': '***MAIL***',
'password': '***PASS***',
'capp': 'meg',
'goto': 'https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code&scope=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&client_id=prod_espaceclient&state=0&redirect_uri=https%3A%2F%2Fmonespace.grdf.fr%2F_codexch&nonce=' + auth_nonce + '&by_pass_okta=1&capp=meg'
}
req = session.post('https://login.monespace.grdf.fr/sofit-account-api/api/v1/auth', data=payload, allow_redirects=False)
if not 'XSRF-TOKEN' in session.cookies:
raise GazparLoginException("Login unsuccessful. Check your credentials.")
req = session.get('https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize?response_type=code&scope=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&client_id=prod_espaceclient&state=0&redirect_uri=https%3A%2F%2Fmonespace.grdf.fr%2F_codexch&nonce=' + auth_nonce + '&by_pass_okta=1&capp=meg')
req = session.get('https://monespace.grdf.fr/api/e-connexion/users/whoami')
req = session.get('https://monespace.grdf.fr/api/e-conso/pce')
logging.info("PCEs:")
logging.info(req.text)
req = session.get('https://monespace.grdf.fr/api/e-conso/pce/consommation/informatives?dateDebut=2018-11-27&dateFin=2021-11-27&pceList%5B%5D=**PCE***')
logging.info("CONSO:")
logging.info(req.text)
return session
Bonjour Eric D'abord merci pour tout ton travail, c'est vraiment top ! Je vais essayer de me libérer de mes contraintes perso pour intégrer ton script en fin de soirée. J'aurais un peu plus de temps en début de semaine prochaine. Par contre, je m'interroge sur la pérennité des devs puisque le site GRDF est encore en train d'évoluer. Je crains qu'on se retrouve bloqué par l'authentification. Encore merci
Je pense que le backend ne change pas souvent. Si le site évolue, cela n'a pas d'impact car on se fait que récupérer des cookies en première partie (le parcours obligatoire) avec de simple gets et 1 post avec les crédits. De mon point de vue, cela me paraît être une solution facilement très facile à faire évoluer comparé au pilotage de la WebView. Cela paraîtrait fou de revoir le backend d'ici peu... L'avantage est de n'avoir qu'à éventuellement corriger les URL des web services si ils venaient à évoluer... Je suis assez optimiste vu la profondeur de la refonte qui vient d'être faite. J'aime beaucoup la mise en base que tu as faite pour enedis qui pourrait totalement être pertinente pour éviter de recharger tout l'historique pour sortir des stats d'évolution. Si le jour ne contient pas de données de consommation plus de N fois, on ne tente plus la mise à jour... Donc a partir d'une date donnée au fur et à mesure. Pour les données manquantes, nous pouvons également extrapoler avec le taux moyen de conversion et les index. Tiens moi au courant du bon fonctionnement pour toi du PoC. Edit: Le goto peut être simplement 'goto': 'https://sofa-connexion.grdf.fr:443/openam/oauth2/externeGrdf/authorize' Je constate que l'appel 3 peut être omis et que l'appel 4 ne fonctionnera pas le premier coup, mais le deuxième coup... Si besoin de faire évoluer, je ne pense pas que cela me prendra du temps. Avec un peu plus d'investigation sur le site, je pourrais peut être simplifier un peu plus si je comprends la logique de récupération des cookies.
J'ai exécuté ton bout de code et je suis tombé sur un callback du captcha de google :
2021-11-27 20:38:47,958 auth_nonce: e851a3ab76ff56cd940e651e5f0ca242
2021-11-27 20:38:48,126 PCEs:
2021-11-27 20:38:48,126 <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mire de connexion</title>
<base href="/mire/">
<script type="text/javascript">
var onloadCallback = function() {
setTimeout(onloadCallback, 500)
};
</script>
<meta name="viewport" content="width=device-height, initial-scale=1, maximum-scale=0.42">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!--<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async></script>-->
</head>
<body>
<app-root></app-root>
<script src="runtime.e7df24b5d39b2102df5c.js" defer></script><script src="polyfills.35a5ca1855eb057f016a.js" defer></script><script src="styles.bb6b60ca59ce3dec0b8a.js" defer></script><script src="main.ec88b36544257b014091.js" defer></script></body>
</html>
2021-11-27 20:38:48,179 CONSO:
2021-11-27 20:38:48,179 <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mire de connexion</title>
<base href="/mire/">
<script type="text/javascript">
var onloadCallback = function() {
setTimeout(onloadCallback, 500)
};
</script>
<meta name="viewport" content="width=device-height, initial-scale=1, maximum-scale=0.42">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!--<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async></script>-->
</head>
<body>
<app-root></app-root>
<script src="runtime.e7df24b5d39b2102df5c.js" defer></script><script src="polyfills.35a5ca1855eb057f016a.js" defer></script><script src="styles.bb6b60ca59ce3dec0b8a.js" defer></script><script src="main.ec88b36544257b014091.js" defer></script></body>
</html>
Tu as eu le même souci ?
L'authentification n'a pas fonctionné. Pour savoir où il faut regarder les req.text et le session.cookies à chaque étape pour voir ou cela ne marche pas. Tu peux directement me contacter @gmail.com pour échanger si les retours contiennent des données sensibles.
ok merci, je vais debug plus précisément
ok merci, je vais debug plus précisément
Check que tes credential que tu as remplacé dans le bout de code fonctionnent sur mon espace de GrDF en faisant des copier coller. En faisant F12 dans un browser, onglet Network avec l'option préserve en haut, tu vas retrouver les appels des web services et comparer.
Erreur à la con de mon coté, ça fonctionne :)
ok merci, je vais debug plus précisément
Check que tes credential que tu as remplacé dans le bout de code fonctionnent sur mon espace de GrDF en faisant des copier coller. En faisant F12 dans un browser, onglet Network avec l'option préserve en haut, tu vas retrouver les appels des web services et comparer.
Erreur à la con de mon coté, ça fonctionne :)
Great.
C'est super ce que tu as fait. Je m'occupe maintenant de la déco en traitant les valeurs json. Je te tiens au jus.
C'est super ce que tu as fait. Je m'occupe maintenant de la déco en traitant les valeurs json. Je te tiens au jus.
La partie plaisir :) c'est a dire l'intégration. Bravo, je regarde ton code pour faire quelques PR avec mes tests. Il faudrait arriver au même niveau que le projet enedis2mqtt et sa carte Lovelace (Ce serait top)
Oui enedis est un beau projet, madmartignan y a passé beaucoup de temps. Ok avec toi pour la carte lovelace, ça serait top.
Oui enedis est un beau projet, madmartignan y a passé beaucoup de temps. Ok avec toi pour la carte lovelace, ça serait top.
Ok je suis. On peut faire une simple évolution de la carte pour gérer le gaz a la place de l'électricité sans HC, ça reste des kW. A voir comment on s'organise ensemble car il y a un peu de travail.
Hello Eric.
Je m'y remets aujourd'hui. La priorité c'est de rétablir le service à minima. Penses-tu qu'il est possible de récupérer via l'APi d'autres infos, par exemples les données calculées au mois ou à la semaine ? Sinon, ça nous obligerait de les calculer nous-mêmes avec un risque d'avoir des écarts avec le site de Grdf... Bonne journée.
J'ai regardé, c'est bien le frontend qui fait les calculs dans le tableau de bord. Sache que les relèves (publications au fournisseur) sont disponibles ici : https://monespace.grdf.fr/api/e-conso/pce/consommation/publiees?dateDebut=2018-11-26&dateFin=2021-11-29&pceList[]=XXXXXXXXXXXXXX Ce jour, je constate que je n'ai pas de relevé depuis le 24 à 0h00. Les données affichées dans "Ma consommation détaillée" ne provoque pas de reload des infos, simplement la récupération de la météo pour afficher des températures journalières moyennes.
Si nous intégrons la base de données par la suite, il faudra de toute façon les calculer non même car les statistiques d'évolution de consommation se font sur mois/semaine glissantes (par rapport mois/semaine précédents/mois de l'année précedente ou mois/semaine de l'année précédente) Je pense qu'en combinant les index et les kWh (pour obtenir les taux de conversion), nous pouvons combler les trous dans les données quand cela arrive.
Le code du frontend est minifié donc on ne peut pas réutiliser les algos, mais je ne suis pas inquiet - sur ta base de travail je m'ocupperais de les calculer. Je vais regarder sur un mois ou il manque des données (indexes à null) quelle valeur affiche le site.
Ok merci pour ces infos. De mon côté, je revois le code gazpar.py en implémentant des classes objets qui seront utiles pour implémenter facilement différentes fonctions (de calcul notamment).
Oui, super si tu met au propre l'architecture. Je valide que le site ne compte pas les jours ou les données ne sont pas disponible. Par exemple, ce mois ci, si je compte avec mes index, j'ai dépensé 102m3 (jusqu'au 24). hors le site ne fait que cumuler les kWh des relevés et m'affiche "que" 985kWh. Hors avec le taux actuel de conversion de 11.15, cela donne pluôt 1137.3kWh. Donc le frontend fait n'importe quoi, sachant que les données kWh quotidiennes sont des arrondis au kWh près donc peu précises. De mon point de vue, ce sont les index en m3 qui sont justes. Le webservice des quantité publiées au fournisseur permet de calculer plus justement le taux de conversion sur une periode et de coller avec la facturation! Donc une petite table date_debut/date_fin/taux à mettre à jour regulièrement avec les dernières periodes publiées permet de connaitre le dernier taux de conversion pour estimer les vrais kWh qui seront facturés.
ok, je prends en compte ce point, merci. Par ailleurs, je vais devoir gérer le cas où quelqu'un possède plusieurs PCE associés à son compte GRDF. Est-ce que tu as un alias associé à ton PCE ? Et si oui, est-ce toi qui l'a modifié ou c'est une valeur par défaut (si oui laquelle) ? L'API renvoie l'alias, ça me parait pas mal d'utiliser l'alias plutot que le numéro du PCE dans le device name de Home assistant.
Je suis pas sur de comprendre, mais dans la liste des Pce, il y a alias, idObject et pce qui contiennent la donnée. Je prendrais pce pour le nom et la jointure avec les relevés pour etre sur d'avoir une donnée qui ne bougera pas.
Sur la page d'accueil, tu peux nommer ton PCE :
Oui, alias est bien mis à jour. Tu peux l'utiliser mais attention, il faudrait pas que les topics changent pour autant si on l'édite... C'est le pce l'id unique. Peut etre le mettre dans les données retournée par le topic donc le sensor.
Je suis d'accord que c'est risqué au cas où il change, mais avoir un device id avec un numéro de PCE, je trouve ça tellement moche....
Je suis d'accord que c'est risqué au cas où il change, mais avoir un device id avec un numéro de PCE, je trouve ça tellement moche....
Oui, après on a besoin d'un id fixe pour le recorder... S'il change on perd la continuité des données dans home assistant. Mieux vaut utiliser la propriété friendly_name au niveau du sensor declaré dans l'auto discovery.
Ok , je mettrais le friendly name ! Bon je viens de déployer la version 0.5-dev dans Docker. Pour l'instant je n'ai fait que rebrancher les câbles (en plus de boucler sur les PCEs). Ca fonctionne si on fait pas trop de connerie dans les paramètres :)
Evidemment, pour l'instant, j'ai désactiver les valeurs mensuelles. De toute façon, il y aura un gros rework à prévoir la dessus. J'enrichirai demain les sensors avec les nouvelles infos remontées par ton api.
Ok, je te laisse avancer pour que le socle soit le plus intégrable et propre possible. Je reviendrais sur le code pour des statistiques avancées et la mise en base. Peux tu gérer aussi la récupération de: https://monespace.grdf.fr/api/e-conso/pce/consommation/publiees?dateDebut=2018-11-26&dateFin=2021-11-29&pceList[]=XXXXXXXXXXXXXX Afin de nourrir la future table des conversion m3->kWh. Pour info, j'ai eu la chance de discuter avec un spécialiste aujourd'hui dans l'entretient de chaudière et les taux de conversion vont changer radicallement à partir de 2025, puis 2029 à cause de l'origine du gaz. Cela veut dire que l'indice de conversion va devenir une variable importante prochainement. Sur 2021, il a varié de 10.8 à 11.4 environ. La récupération des relèves est notre seul moyen d'avoir les taux de conversion à priori vu les données que j'ai pu voir dans les XHR de GRDF. En gros, pour les ceux qui n'ont pas une chaudière compatible "biogaz", c'est à dire sur pauvre pouvoir calorifique, cela va demander un réglage de la chaudière chaque année. J'ai un modèle Vaillant (ca marche pour Saunier-Duval sur la dernière génération 2021) qui s'adapte avec sonde automatiquement. On pourra donc dans la carte indiquer que la chaudière doit être reglée selon le modèle et le facteur de conversion. Pour info, un bruleur mal réglé, c'est souvent une cause d'encrassement ou de présence de CO sur mélange pauvre.
Ca me va très bien si tu t'occupes de la base de données et des statistiques avancées. Tu as l'air bien plus calé que moi en terme de conso gaz. Je suis en train de peaufiner le core model dans le script gazpar.py afin de pouvoir manipuler les objets quelque soit la source des données (GRDF ou de la base de données). Je vais aussi redesign la partie HA et rajouter de nouvelles infos. Par contre, les relevés restent bloqués au 23 côté GRDF. Ca serait bien qu'ils terminent leur mise en prod.
Ca serait bien qu'ils terminent leur mise en prod.
OUI!, Après on peut faire exprès de tronquer dans le code par configuration pour faire des tests U
Bravo, Ça marche bien au premier coup, après souvent des échec au whoami ou a la connexion... Je pense qu'on peut ajouter le dernier index connu et ajouter state class pour indiquer que c'est un cumul pour pouvoir le sélectionner dans énergie :)
Yep je suis en train de refondre le script hass. J'ajouterai les index comme tu le proposes. J'ajouterai également les 7 derniers relevés + des infos liés au compte. Plus d'autres infos si t'as des idées.
Par ailleurs, je me demandais si on pouvait enrichir l'appli en calculant les DJU à partir des infos de localisation du PCE et quelques inputs utilisateurs.
@echauvet Salut Eric, t'es toujours chaud pour mettre en place des calculs "avancés" sur la conso de gaz ? Je te propose de mettre à disposition des modules python dédiés à ces calculs et à la gestion de la BD. L'objectif est que ça reste le plus modulaire possible. On peut en rediscuter.
Oui parfaitement, tout est clair pour la partie algorithme, et avec un socle propre avec les modules nécessaires ça serait top.
Cool. Je finis de préparer le socle. Ca sera un premier jet, je pourrais le faire évoluer en fonction de tes besoins. Je te tiens au jus.
Cool. Je finis de préparer le socle. Ca sera un premier jet, je pourrais le faire évoluer en fonction de tes besoins. Je te tiens au jus.
Noice. Ça aide bien car le python et ses use cases ce n'est pas tous les jours... Si on parle archi, kernel, dpdk, buildroot, smid et même database c'est autre chose. Par chance je vais en faire en ce moment pour corriger des tests auto!
Si tu m'indiques comment calculer certains indicateurs "avancés", je peux m'occuper de leur programmation en python.
Comme je compte mettre en base de donnée, les requêtes vont faire le gros du travail.
Peux t'on se contacter de manière privée? Tel/Signal?
ok je t'ai envoyé un mail
bizarre, j'ai repris le mail qui était dans ta fiche de profil
It seems that from this day, the calls to GRDF mon espace do not work anymore. I may help to solve this. It seems that we are talking about complete rewrite of gazpar.py.