Passage V5 a V7 NOK , perte info

Salut Loic,

Au cas où tu repasses par là, j’ai essayé pour voir de mettre à jour le plugin vers la branche beta d’un Jeedom qui n’avait pas besoin de l’évolution (puisque toujours sur V5 d’Enphase) et il y a un soucis de lecture du coup les valeurs ne sont plus récupérées.

Les logs en debug :

[2022-09-14 15:21:02]DEBUG : Call url http://192.168.0.14/production.json?details=1
[2022-09-14 15:21:03]DEBUG : Results {"production":[{"type":"inverters","activeCount":12,"readingTime":1663161781,"wNow":1685,"whLifetime":2936927},{"type":"eim","activeCount":1,"measurementType":"production","readingTime":1663161786,"wNow":1187.607,"whLifetime":2908468.5,"varhLeadLifetime":0.027,"varhLagLifetime":1044979.929,"vahLifetime":3551722.913,"rmsCurrent":5.156,"rmsVoltage":234.152,"reactPwr":195.833,"apprntPwr":1206.552,"pwrFactor":0.99,"whToday":5495.5,"whLastSevenDays":77164.5,"vahToday":7686.913,"varhLeadToday":0.027,"varhLagToday":3063.929,"lines":[{"wNow":1187.607,"whLifetime":2908468.5,"varhLeadLifetime":0.027,"varhLagLifetime":1044979.929,"vahLifetime":3551722.913,"rmsCurrent":5.156,"rmsVoltage":234.152,"reactPwr":195.833,"apprntPwr":1206.552,"pwrFactor":0.99,"whToday":5495.5,"whLastSevenDays":77164.5,"vahToday":7686.913,"varhLeadToday":0.027,"varhLagToday":3063.929}]}],"consumption":[{"type":"eim","activeCount":1,"measurementType":"total-consumption","readingTime":1663161786,"wNow":1570.983,"whLifetime":6812385.138,"varhLeadLifetime":2204942.14,"varhLagLifetime":1161795.438,"vahLifetime":5610918.36,"rmsCurrent":7.777,"rmsVoltage":234.148,"reactPwr":-231.016,"apprntPwr":1820.984,"pwrFactor":0.86,"whToday":14159.138,"whLastSevenDays":167823.138,"vahToday":12893.36,"varhLeadToday":5590.14,"varhLagToday":3191.438,"lines":[{"wNow":1570.983,"whLifetime":6812385.138,"varhLeadLifetime":2204942.14,"varhLagLifetime":1161795.438,"vahLifetime":5610918.36,"rmsCurrent":7.777,"rmsVoltage":234.148,"reactPwr":-231.016,"apprntPwr":1820.984,"pwrFactor":0.86,"whToday":14159.138,"whLastSevenDays":167823.138,"vahToday":12893.36,"varhLeadToday":5590.14,"varhLagToday":3191.438}]},{"type":"eim","activeCount":1,"measurementType":"net-consumption","readingTime":1663161786,"wNow":383.376,"whLifetime":3930712.796,"varhLeadLifetime":2204942.112,"varhLagLifetime":116815.509,"vahLifetime":5610918.36,"rmsCurrent":2.621,"rmsVoltage":234.144,"reactPwr":-35.183,"apprntPwr":617.315,"pwrFactor":0.61,"whToday":0,"whLastSevenDays":0,"vahToday":0,"varhLeadToday":0,"varhLagToday":0,"lines":[{"wNow":383.376,"whLifetime":3930712.796,"varhLeadLifetime":2204942.112,"varhLagLifetime":116815.509,"vahLifetime":5610918.36,"rmsCurrent":2.621,"rmsVoltage":234.144,"reactPwr":-35.183,"apprntPwr":617.315,"pwrFactor":0.61,"whToday":0,"whLastSevenDays":0,"vahToday":0,"varhLeadToday":0,"varhLagToday":0}]}],"storage":[{"type":"acb","activeCount":0,"readingTime":0,"wNow":0,"whNow":0,"state":"idle"}]}
[2022-09-14 15:21:03]ERROR : Erreur sur la fonction cron du plugin : Call to a member function getValueDate() on bool

Slt ,
Une discution très intéressante avec différents script fonctionnant apparement en v7 pour ceux voulant avoir les données en attendants

Pour ceux que ça interesse voilà le script qui fonctionne chez moi:

  • le script de récupération des infos et du token:
#!/usr/bin/env python3

import asyncio
import logging
import re
import time
import jwt
import json

from html.parser import HTMLParser
from json.decoder import JSONDecodeError
try:
    from BeautifulSoup import BeautifulSoup
except ImportError:
    from bs4 import BeautifulSoup
#from envoy_utils.envoy_utils import EnvoyUtils

import httpx

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)

    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)

    def handle_data(self, data):
        print("Encountered some data  :", data)

SITE_ID = "123456"
SERIAL_NUMBER = "123456"

ENDPOINT_URL_PRODUCTION_JSON = "http://{}/production.json"
ENDPOINT_URL_PRODUCTION_V1 = "http://{}/api/v1/production"
ENDPOINT_URL_PRODUCTION_INVERTERS = "http://{}/api/v1/production/inverters"
ENDPOINT_URL_PRODUCTION = "http://{}/production"
LOGIN_URL = "https://entrez.enphaseenergy.com/login"
TOKEN_URL = "https://entrez.enphaseenergy.com/entrez_tokens"
LOCAL_URL = "https://{}/"

payload_login = {'username': 'blabla@gmail.com', 'password': 'azerty'}

payload_token = {'Site': SITE_ID, "serialNum": SERIAL_NUMBER}

headers = {'Content-Type': 'application/json'}


client = httpx.Client(verify=False)
token = ""
try:
    r = client.post(LOGIN_URL, data=payload_login)
    print(r.status_code)
    #print(r.text)
    r = client.post(TOKEN_URL, data=payload_token)
    print(r.status_code)
    #print(r.text)
    parsed_html = BeautifulSoup(r.text, "lxml")
    token = parsed_html.body.find('textarea').text
    print(token)
    decode = jwt.decode(token, options={"verify_signature": False}, algorithms="ES256")
    print(decode["exp"])

    header = {"Authorization": "Bearer " + token}
    r = client.get(LOCAL_URL + "auth/check_jwt", headers=header)
    print(r.text)

    r = client.get(LOCAL_URL + "api/v1/production", headers=header)
    print(r.text)
    json.dump(r.json(), open("/var/www/html/plugins/script/data/enphasedonnee.txt", "w+"))
finally:
    client.close()

  • entrer son ip à la place des {}

  • login à la place de blabla@gmail.com

  • password à la place de azerty,

  • numéro de site

  • numero de gateway à la place de Serial_Number

  • installer les dépendance python depuis jeedom:

sudo pip install pyjwt html.parser html5lib bs4 asyncio httpx lxml

Puis on récupère les infos dans le fichier du plugin script:

/var/www/html/plugins/script/data/enphasedonnee.txt

et voici la config coté plugin script

Merci @jeefib pour les essais :slight_smile:

ce n’est pas très propre mais ça fonctionne .
à partir du moment ou le token est généré automatiquement, on peu récupérer toutes les informations. Dans l’exemple il n’y a que la production instantanée

2 « J'aime »

pour ma part, ça fonctionne comme ceci

le token (tokentest.PY) testé sur visualstudio donne ceci

2022.14.0\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '61381' '--' 'c:\Users\flamalex\Desktop\tokentest.py' 
200
200
eyJraWQiOiI3ZDEwMDA1ZC03ODk5LTRkMGQtYmNiNC0yNDRmOThlZGciOiJFUzI1NiJ9.eyJhdWQiOiIxMiaWF0IjoxNjY0NTMyODM4LCJqdGkiOiIwNTVkZGI1OS1lNTkxLTQ4YTYtODcxMC02NGIzNzFkN2EwMmIiLCJ1c2VybmFtZSI6ImZsYW1hbGV4MUBnbWFpbC5jb20ifQ.7Fyq-Bctu2_5Hd_CxcAamBp31N3ImwEqf2fmCBQRDNnPiIxbgpNBdvjp2XqDHHGVZeNBX-vs1SDRydQ
1664776038
<!DOCTYPE html><h2>Valid token.</h2>


{"wattHoursToday": 6275, "wattHoursSevenDays": 20939, "wattHoursLifetime": 27614, "wattsNow": 649}

1 « J'aime »

Bonjour jeefib
Est ce que tu utilises le même script que cddu33 ?
Je ne suis pas très a l’aise avec le code , donc je test et essaye de me débrouiller comme je peux d’où ma question.

Je me répond , j’ai utilisé le script de @cddu33 et dans l’adresse (puissance ou production) j’ai mis http://127.0.0.1 et pas localhost et du coup ça fonctionne et Voila un Heureux , merci les gars :grinning: :grinning:
Par contre vous actualisé le cron tout les combien ? J’ai toujours la même valeur , j’ai l’impression que ça ne s’actualise pas

bonjour @totph33
le cron n’actualise que les infos
donc changes le script> action defaut (voir ma capture ci dessus)
et remplace action par info > numerique
tu pourras fixer le cron sur 1 min ou 5 min
ca donne ça:

le script vient de whisk3y
sur github
je l’ai adapté, en me cassant les dents un bon moment, car python et moi ça fait 2, mais apres de nombreuses heures et des tests sur visualstudio je l’ai communiqué à CDDU33 qui devrait nous sortir un plugin jeedom pour envoy fw7

Super merci beaucoup , je vais faire ça encore merci , ce serait vraiment super d’avoir un plugin pour les fw7

1 « J'aime »

C’est en cours en effet, cddu33 s’est mis sur ce sujet

Super merci beaucoup @cddu33
Bon boulot , je viens de l’installer ça fonctionne pour moi
Encore un grand merci pour le don du temps passé

tu as les mesures prod et conso?

1 « J'aime »

Merci le plugin fonctionne a merveille.
J’ai la consommation et la production.

@cddu33
OUI moi aussi j’ai tout prod et conso

Bonsoir,

Pour ceux qui voudrais adapter le plugin officiel qui est beaucoup plus complet que le mien

Ce n’est pas super propre et je n’ai pas terminé l’intégration (mis les paramètre en fixe dans le fichier classe) mais c’est je pense une base de travail.

  • Modifier le fichier: html/plugins/envoy/core/class/envoy.class.php
<?php

/* This file is part of Jeedom.
*
* Jeedom 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.
*
* Jeedom 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 Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/

/* * ***************************Includes********************************* */
require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php';

class envoy extends eqLogic {

	/*     * ***********************Methode static*************************** */

	public static function cron() {
		envoy::updateValues();
	}

	public static function cron30() {
		envoy::updateDevices();
	}

	public static function request($_path) {
      	$enphasesecur_pass = "passenphaseweb";
		$enphasesecur_user = "userenphaseweb";
		$enphasesecur_serie = "numerodeseriedelapasserelle";
		$enphasesecur_site = "numerodesitedelapasserelle";
		$enphasesecur_ip = "adresseiplocal";
		if ($enphasesecur_user != '') {
          	$enphasesecur_path = realpath(dirname(__FILE__));
        	$enphasesecur_fichier = $enphasesecur_path .'/../../data/'. $enphasesecur_serie . '.json';
			$enphasesecur_cmd = 'python3 ' . $enphasesecur_path .'/../../resources/enphase.py';
			$enphasesecur_cmd .=' ' .  $enphasesecur_ip . ' ' . $enphasesecur_user . ' ' . $enphasesecur_pass . ' ' . $enphasesecur_site . ' ' . $enphasesecur_serie . ' ' . $enphasesecur_fichier . ' ' . $_path;
		log::add('envoy', 'debug', 'commande ' . $enphasesecur_cmd);
		exec($enphasesecur_cmd . ' >> ' . log::getPathToLog('envoy') . ' 2>&1 &');
		sleep(5);
		$return = json_decode(file_get_contents($enphasesecur_fichier), true);  
		} elseif (config::byKey('envoy_username', 'envoy', 'envoy') != '' && config::byKey('envoy_password', 'envoy') != '') {
			$url = 'http://' . config::byKey('envoy_ip', 'envoy') . $_path;
			$request_http = new com_http($url, config::byKey('envoy_username', 'envoy', 'envoy'), config::byKey('envoy_password', 'envoy'));
			$request_http->setCURLOPT_HTTPAUTH(CURLAUTH_DIGEST);
          log::add('envoy', 'debug', 'Call url ' . $url);
		$return = json_decode(trim($request_http->exec(20)), true);
		log::add('envoy', 'debug', 'Results ' . json_encode($return));
		if (isset($return['status']) && $return['status'] == 401) {
			throw new Exception(__('Erreur d\'authentification vérifier le nom d\'utilisateur et le mot de passe => ', __FILE__) . json_encode($return));
		}
		} else {
			$url = 'http://' . config::byKey('envoy_ip', 'envoy') . $_path;
			$request_http = new com_http($url);
          log::add('envoy', 'debug', 'Call url ' . $url);
		$return = json_decode(trim($request_http->exec(20)), true);
		log::add('envoy', 'debug', 'Results ' . json_encode($return));
		if (isset($return['status']) && $return['status'] == 401) {
			throw new Exception(__('Erreur d\'authentification vérifier le nom d\'utilisateur et le mot de passe => ', __FILE__) . json_encode($return));
		}
		}
		
		return $return;
	}

	public static function updateValues() {
      	
		$enphases = self::request('/production.json?details=1');
		$eqLogic = eqLogic::byLogicalId('global', 'envoy');
		if (!is_object($eqLogic)) {
			return;
		}

		if (isset($enphases['consumption'])) {
			$net_consumption_pwNow = $eqLogic->getCmd('info', 'net_consumption_pwNow');
			$net_consumption_pwNow->execCmd();
			$duration = (strtotime('now') - strtotime($net_consumption_pwNow->getValueDate())) / 3600;
			$production = $enphases['consumption'][1]['wNow'] * $duration;
			$export = 0;
			$import = 0;
			$export_to_grid = $eqLogic->getCmd('info', 'export_to_grid');
			$import_from_grid = $eqLogic->getCmd('info', 'import_from_grid');
			if ($production < 0) {
				if (date('d', strtotime($export_to_grid->getValueDate())) == date('d')) {
					$export = $export_to_grid->execCmd();
				}
			} else {
				if (date('d', strtotime($import_from_grid->getValueDate())) == date('d')) {
					$import = $import_from_grid->execCmd();
				}
			}
			if ($production < 0) {
				$export += -$production;
				$eqLogic->checkAndUpdateCmd('export_to_grid', $export);
			} else {
				$import += $production;
				$eqLogic->checkAndUpdateCmd('import_from_grid', $import);
			}
			$eqLogic->checkAndUpdateCmd('total_consumption_pwNow', $enphases['consumption'][0]['wNow']);
			$eqLogic->checkAndUpdateCmd('total_consumption_pwhLifetime', $enphases['consumption'][0]['whLifetime']);
			$eqLogic->checkAndUpdateCmd('total_consumption_pwhToday', $enphases['consumption'][0]['whToday']);
			$eqLogic->checkAndUpdateCmd('total_consumption_pwhLastSevenDays', $enphases['consumption'][0]['whLastSevenDays']);
			$eqLogic->checkAndUpdateCmd('net_consumption_pwNow', $enphases['consumption'][1]['wNow']);
			$eqLogic->checkAndUpdateCmd('net_consumption_pwhLifetime', $enphases['consumption'][1]['whLifetime']);
			$eqLogic->checkAndUpdateCmd('net_consumption_pwhToday', $enphases['consumption'][1]['whToday']);
			$eqLogic->checkAndUpdateCmd('net_consumption_pwhLastSevenDays', $enphases['consumption'][1]['whToday']);
		}
		if (isset($enphases['storage'])) {
			$eqLogic->checkAndUpdateCmd('nb_battery', $enphases['storage'][0]['activeCount']);
			$eqLogic->checkAndUpdateCmd('battery_wNow', $enphases['storage'][0]['wNow']);
			if (isset($enphases['storage'][0]['percentFull'])) {
				$eqLogic->checkAndUpdateCmd('battery_percentFull', $enphases['storage'][0]['percentFull']);
			}
			$eqLogic->checkAndUpdateCmd('battery_state', $enphases['storage'][0]['state']);
		}

		if (isset($enphases['production'][1])) {
			$eqLogic->checkAndUpdateCmd('pwNow', $enphases['production'][1]['wNow']);
			$eqLogic->checkAndUpdateCmd('pwhLifetime', $enphases['production'][1]['whLifetime']);
			$eqLogic->checkAndUpdateCmd('pwhToday', $enphases['production'][1]['whToday']);
			$eqLogic->checkAndUpdateCmd('pwhLastSevenDays', $enphases['production'][1]['whLastSevenDays']);
			$eqLogic->checkAndUpdateCmd('nb_inverters', $enphases['production'][1]['activeCount']);
		} else {
			$eqLogic->checkAndUpdateCmd('pwNow', $enphases['production'][0]['wNow']);
			$eqLogic->checkAndUpdateCmd('pwhLifetime', $enphases['production'][0]['whLifetime']);
			$eqLogic->checkAndUpdateCmd('nb_inverters', $enphases['production'][0]['activeCount']);
			$enphases = self::request('/api/v1/production');
			$eqLogic->checkAndUpdateCmd('pwhToday', $enphases['wattHoursToday']);
			$eqLogic->checkAndUpdateCmd('pwhLastSevenDays', $enphases['wattHoursSevenDays']);
		}

		$enphases = self::request('/api/v1/production/inverters');
		foreach ($enphases as $enphase) {
			$eqLogic = eqLogic::byLogicalId($enphase['serialNumber'], 'envoy');
			if (!is_object($eqLogic)) {
				continue;
			}
			$eqLogic->checkAndUpdateCmd('lastReportWatts', $enphase['lastReportWatts']);
			$eqLogic->checkAndUpdateCmd('maxReportWatts', $enphase['maxReportWatts']);
		}
	}

	public static function updateDevices() {
		$enphases = self::request('/inventory.json');
		foreach ($enphases[0]['devices'] as $enphase) {
			$eqLogic = eqLogic::byLogicalId($enphase['serial_num'], 'envoy');
			if (!is_object($eqLogic)) {
				continue;
			}
			$eqLogic->checkAndUpdateCmd('producing', $enphase['producing']);
			$eqLogic->checkAndUpdateCmd('communicating', $enphase['communicating']);
			$eqLogic->checkAndUpdateCmd('provisioned', $enphase['provisioned']);
		}
		if (isset($enphases[1])) {
			foreach ($enphases[1]['devices'] as $enphase) {
				$eqLogic = eqLogic::byLogicalId($enphase['serial_num'], 'envoy');
				if (!is_object($eqLogic)) {
					continue;
				}
				$eqLogic->checkAndUpdateCmd('producing', $enphase['producing']);
				$eqLogic->checkAndUpdateCmd('communicating', $enphase['communicating']);
				$eqLogic->checkAndUpdateCmd('provisioned', $enphase['provisioned']);
				$eqLogic->checkAndUpdateCmd('percentFull', $enphase['percentFull']);
				$eqLogic->checkAndUpdateCmd('maxCellTemp', $enphase['maxCellTemp']);
			}
		}
	}

	public static function searchenphaseDevices() {
		$enphases = self::request('/inventory.json');
		foreach ($enphases[0]['devices'] as $enphase) {
			$eqLogics = eqLogic::byTypeAndSearhConfiguration('envoy', $enphase['serial_num']);
			if (count($eqLogics) == 0) {
				$eqLogic = new eqLogic();
				$eqLogic->setEqType_name('envoy');
				$eqLogic->setIsEnable(1);
				$eqLogic->setName('PCU_' . $enphase['serial_num']);
				$eqLogic->setLogicalId($enphase['serial_num']);
				$eqLogic->setConfiguration('name', 'PCU_' . $enphase['serial_num']);
				$eqLogic->setConfiguration('type', 'PCU');
				$eqLogic->setIsVisible(1);
				$eqLogic->save();
			}
		}
		foreach ($enphases[1]['devices'] as $enphase) {
			$eqLogics = eqLogic::byTypeAndSearhConfiguration('envoy', $enphase['serial_num']);
			if (count($eqLogics) == 0) {
				$eqLogic = new eqLogic();
				$eqLogic->setEqType_name('envoy');
				$eqLogic->setIsEnable(1);
				$eqLogic->setName('ACB_' . $enphase['serial_num']);
				$eqLogic->setLogicalId($enphase['serial_num']);
				$eqLogic->setConfiguration('name', 'ACB_' . $enphase['serial_num']);
				$eqLogic->setConfiguration('type', 'ACB');
				$eqLogic->setIsVisible(1);
				$eqLogic->save();
			}
		}
		$eqLogics_global = eqLogic::byLogicalId('GLOBAL', 'envoy', true);
		if (count($eqLogics_global) == 0) {
			$eqLogic = new eqLogic();
			$eqLogic->setEqType_name('envoy');
			$eqLogic->setIsEnable(1);
			$eqLogic->setName('Global');
			$eqLogic->setLogicalId('GLOBAL');
			$eqLogic->setConfiguration('name', 'GLOBAL');
			$eqLogic->setConfiguration('type', 'GLOBAL');
			$eqLogic->setIsVisible(1);
			$eqLogic->save();
		}
		foreach (eqLogic::byType('envoy') as $enphase) {
			if (is_object($enphase)) {
				$enphase->postSave();
			}
		}
		envoy::updateValues();
		envoy::updateDevices();
	}

	public function postSave() {
		$enphaseCmd = $this->getCmd(null, 'refresh');
		if (!is_object($enphaseCmd)) {
			$enphaseCmd = new envoyCmd();
			$enphaseCmd->setName(__('Rafraichir', __FILE__));
		}
		$enphaseCmd->setEqLogic_id($this->getId());
		$enphaseCmd->setLogicalId('refresh');
		$enphaseCmd->setType('action');
		$enphaseCmd->setSubType('other');
		$enphaseCmd->setIsVisible(true);
		$enphaseCmd->save();
		if ($this->getConfiguration('type') == 'PCU') {
			$enphaseCmd = $this->getCmd(null, 'producing');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('producing');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'communicating');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Communication', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('communicating');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'provisioned');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Provisionné', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('provisioned');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'lastReportWatts');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('lastReportWatts');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->setUnite('W');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'maxReportWatts');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance Max', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('maxReportWatts');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->setUnite('W');
			$enphaseCmd->save();
		} else if ($this->getConfiguration('type') == 'ACB') {
			$enphaseCmd = $this->getCmd(null, 'producing');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('producing');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'communicating');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Communication', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('communicating');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'provisioned');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Provisionné', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('provisioned');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('binary');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'percentFull');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('% charge', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('percentFull');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setUnite('%');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'maxCellTemp');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Temp max', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('maxCellTemp');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setUnite('°C');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'lastReportWatts');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('lastReportWatts');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->setUnite('W');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'maxReportWatts');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance Max', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('maxReportWatts');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->setUnite('W');
			$enphaseCmd->save();
		} else if ($this->getConfiguration('type') == 'GLOBAL') {
			$enphaseCmd = $this->getCmd(null, 'export_to_grid');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Export', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('export_to_grid');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'import_from_grid');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Import', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('import_from_grid');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'nb_inverters');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Nbre de micro-onduleurs', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('nb_inverters');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'pwNow');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production instantanée', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('pwNow');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('W');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'pwhLifetime');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production depuis le début', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('pwhLifetime');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'pwhToday');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production pour la journée', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('pwhToday');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'pwhLastSevenDays');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production des 7 derniers jours', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('pwhLastSevenDays');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'total_consumption_pwNow');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance totale', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('total_consumption_pwNow');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('W');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'total_consumption_pwhLifetime');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso totale depuis le début', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('total_consumption_pwhLifetime');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'total_consumption_pwhToday');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso totale pour la journée', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('total_consumption_pwhToday');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'total_consumption_pwhLastSevenDays');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso totale des 7 derniers jours', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('total_consumption_pwhLastSevenDays');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'net_consumption_pwNow');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Puissance nette', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('net_consumption_pwNow');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('W');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'net_consumption_pwhLifetime');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso nette depuis le début', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('net_consumption_pwhLifetime');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'net_consumption_pwhToday');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso nette pour la journée', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('net_consumption_pwhToday');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'net_consumption_pwhLastSevenDays');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Conso nette des 7 derniers jours', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('net_consumption_pwhLastSevenDays');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('Wh');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'nb_battery');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Nbre de batteries', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('nb_battery');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'battery_wNow');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Production des batteries', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('battery_wNow');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('W');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'battery_percentFull');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Niveau des batteries', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('battery_percentFull');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('numeric');
			$enphaseCmd->setUnite('%');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->setIsHistorized(true);
			$enphaseCmd->save();

			$enphaseCmd = $this->getCmd(null, 'battery_state');
			if (!is_object($enphaseCmd)) {
				$enphaseCmd = new envoyCmd();
				$enphaseCmd->setName(__('Etat des batteries', __FILE__));
			}
			$enphaseCmd->setEqLogic_id($this->getId());
			$enphaseCmd->setLogicalId('battery_state');
			$enphaseCmd->setType('info');
			$enphaseCmd->setSubType('string');
			$enphaseCmd->setIsVisible(true);
			$enphaseCmd->save();
		}
	}
}

class envoyCmd extends cmd {
	/*     * *************************Attributs****************************** */


	/*     * ***********************Methode static*************************** */


	/*     * *********************Methode d'instance************************* */

	public function preSave() {
	}

	public function execute($_options = null) {
		if ($this->getLogicalId() == 'refresh') {
			envoy::updateValues();
			envoy::updateDevices();
		}
	}
}

  • Créer un dossier resources à la racine de envoy
    Fichier python enphase.py à mettre dans /ressources/ :
#!/usr/bin/env python3

import asyncio, logging, re, time, jwt, json, sys, os
from html.parser import HTMLParser
from json.decoder import JSONDecodeError
try:
    from BeautifulSoup import BeautifulSoup
except ImportError:
    from bs4 import BeautifulSoup
import httpx

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)
    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)
    def handle_data(self, data):
        print("Encountered some data  :", data)

LOCAL_URL ="https://" + sys.argv[1]
PAGE = sys.argv[7]
USER = sys.argv[2]
PASSWORD = sys.argv[3]
SITE_ID = sys.argv[4]
SERIAL_NUMBER = sys.argv[5]
SORTIE= sys.argv[6]
LOGIN_URL = "https://entrez.enphaseenergy.com/login"
TOKEN_URL = "https://entrez.enphaseenergy.com/entrez_tokens"

payload_login = {'username': USER, 'password': PASSWORD}
payload_token = {'Site': SITE_ID, "serialNum": SERIAL_NUMBER}
headers = {'Content-Type': 'application/json'}

client = httpx.Client(verify=False)
token = ""
try:
    r = client.post(LOGIN_URL, data=payload_login)
    r = client.post(TOKEN_URL, data=payload_token)
    parsed_html = BeautifulSoup(r.text, "lxml")
    token = parsed_html.body.find('textarea').text
    decode = jwt.decode(token, options={"verify_signature": False}, algorithms="ES256")
    header = {"Authorization": "Bearer " + token}
    r = client.get(LOCAL_URL + "/auth/check_jwt", headers=header)
    r = client.get(LOCAL_URL + PAGE, headers=header)
    json.dump(r.json(), open(SORTIE, "w+"))
finally:
    client.close()
  • Créer un dossier data à la racine de envoy

Bonne soirée :slight_smile:

Bonjour,
Merci pour ce récap. J’ai quelques difficultés pour rendre le plugin fonctionnel.
Apres l’installation du plugin officiel j’ai suivi tes instructions. Mais faut-il modifier des lignes de codes ? Dans le dossier data faut-il y mettre quelque chose ?
J’ai modifié le fichier class pour rentrer mes infos (user,n° serie etc). Que faut-il mettre pour passenphaseweb, le mot de passe enphase qui est les 6 derniers numéro du numéro de série par défaut ?
Merci pour l’aide apportée.

Pour me répondre, sur mes questions :

  • faut-il ajouter un fichier dans data : non. Il se crée automatiquement
  • modifier le fichier class : oui. A savoir les lignes 35 à 39 inclus
  • faut-il faire autre chose ? oui, installer les dépendance python depuis jeedom avec la commande sudo pip install pyjwt html.parser html5lib bs4 asyncio httpx lxml comme indiqué plus haut.

Avec tout ça, je pense avoir un résultat fonctionnel. Reste à vérifier les datas. Un truc me perturbe à l’heure actuelle : j’ai 8 micro-onduleurs et la valeur remontée dans jeedom varie entre 1 et 0. Peut être parce qu’il fait bientôt nuit et que les panneaux ne produisent plus.

slt, oui les micros onduleurs ne communiquent que s’ils sont alimentés par les panneaux

Merci pour la réponse.
Je pense qu’il y a un souci de mon côté vis à vis du comptage des micro-onduleurs.
J’ai 8 panneaux avec micro onduleurs. Les huit panneaux produisent et le compteur varie sans cesse entre 0 et 1.


Sur la capture on voit les huit panneaux en fonctionnement nominal. Mais le compteur micro-onduleur à 1.

Cela étant dit, cela ne me pose aucun souci. Je suis peut être un cas très isolé.