C'est compliqué, mais voilà :
1 - La procédure de calcul des puissances, courant et tension :
float Infos_UIP(uint8_t v0, uint8_t vIn, uint8_t iIn, float kV, float kI, uint8_t nbpt, float echV[nbPt], float echI[nbPt], float *vEff, float *iEff){
float V0, V, I, V2 = 0, I2 = 0, P = 0;
float vr, ir;
uint8_t i = 0;
uint32_t P50 = 20000; // Durée en µS d'une période de 50 Hz
uint64_t tc, tcPrec = 0;
uint64_t dT; // Intervale entre deux mesures
uint64_t Td = micros();
do {
tc = micros()-Td;
if (tc >= P50*i/nbPt) { // Période divisée par le nombre de points de mesure
V0 = analogReadMilliVolts(v0); // Lecture de la tension du point commun
V = analogReadMilliVolts(vIn); // Lecture de la tension
I = analogReadMilliVolts(iIn); // Lecture du courant
vr = (V-V0)*kV;
ir = (I-V0)*kI;
dT = tc - tcPrec;
V2 += sq(vr) * dT;
I2 += sq(ir) * dT;
P += vr * ir * dT; // Puissance active
echV[i] += vr/50.0;
echI[i] += ir/50.0;
i++;
tcPrec = tc;
}
} while (i < nbPt); // nbPt = 48 --> la période de 50 Hz est découpée en 48 tronçons
*vEff = sqrtf(V2 / P50); // Tension efficace
*iEff = sqrtf(I2 / P50); // Courant efficace
return P / P50; // Puissance active
}
Dans la suite, cette procédure - activée 50 fois par seconde - est utilisée en alternance toutes les secondes (boolean Vu):
- une fois pour ce qui concerne le réseau
- une fois pour ce qui concerne l'onduleur.
A chaque seconde noCycle == 0:
- je fais le cumul des infos de la dernière seconde
- et toutes les 30 secondes, je mets les données dans un fichier.
2 les variables intéressantes :
float pA_Reseau; // Valeur de la puissance active sur une période de 50 Hz
float sumPA_R; // Somme partielle de pA_Reseau
float pA_Onduleur; // Valeur de la puissance active sur une période de 50 Hz
float sumPA_O; // Somme partielle de pA_Reseau
float vRMS, iRMS; // Valeur efficace pour la tension et le courant
float cosPhi_Res, cosPhi_Ond;
float ptsV[nbPt];
float ptsI_R[nbPt];
float ptsI_P[nbPt];
String infUI; // Chaîne de caractères représentant la forme de la tension et du courant
char info_PPDD[32]; // Chaîne de caractères représentant les puissances et les déphasages réseau et onduleur
char info_PPU[32]; // Chaîne de caractères pour l'écriture des données
3 - son utilisation :
void loop() {
ArduinoOTA.handle();
etatNouv = digitalRead(pin_DetSinus);
if (etatNouv == HIGH && etatPrec == LOW) { // Il n'y a changement d'état que si le réseau est présent
#endif
t1 = 0; // Réinitialisation du compteur de défaut
pb = false; // Si on passe dans cette boucle, c'est que le réseau est présent
statut0 = "Normal";
digitalWrite(ledPB, LOW); // on éteint la LED de défaut
noCycle++;
if (noCycle >= nbP50Hz) { // On recommence la série de nbP50Hz mesures
noCycle = 0;
}
if (Vu) { // Alternance des mesures du courant Réseau et Onduleur toutes les secondes
pA_Reseau = Infos_UIP(pin_Commun, pin_Tension, pin_I_Reseau, 0.935, 0.1, nbPt, ptsV, ptsI_R, &vRMS, &iRMS); // Mesure toutes les 20 mS ; Sonde 50 A/V
sumPA_R += pA_Reseau; // On fait le cumul des différents mesures pour faire un moyennage
cosPhi_Res = -pA_Reseau/(vRMS*iRMS);
} else {
pA_Onduleur = Infos_UIP(pin_Commun, pin_Tension, pin_I_Onduleur, 0.935, 0.1, nbPt, ptsV, ptsI_P, &vRMS, &iRMS); // Mesure toutes les 20 mS ; Sonde 50 A/V
sumPA_O += pA_Onduleur; // On fait le cumul des différents mesures pour faire un moyennage
cosPhi_Ond = pA_Onduleur/(vRMS*iRMS);
}
if (noCycle == 0) { // Commencement de la série de nbP50Hz mesures
lanceLecture = true; // Lance le processus d'acquisition des températures des sondes
infUIoK = false;
infUI = "";
for (uint8_t i = 0; i < nbPt; i++) { // nbPt est le nombre de points de mesure à l'intérieur d'une période
infUI += String(ptsV[i]) + "," + String(-ptsI_R[i]) + "," + String(ptsI_P[i]) + "\n";
ptsV[i] = 0;
}
if (Vu) { // Comme on alterne les mesures, on alterne les effacements
for (uint8_t i = 0; i < nbPt; i++)
ptsI_P[i] = 0;
} else {
for (uint8_t i = 0; i < nbPt; i++)
ptsI_R[i] = 0;
}
Vu = !Vu;
digitalWrite(ledOK, Vu);
forceWiFi = String(WiFi.RSSI()); // Mesure de l'intensité du signal WiFi
pActifReseau = sumPA_R / nbP50Hz; // Valeur moyenne de la puissance sur les nbP50Hz mesures
pActifOnduleur = sumPA_O / nbP50Hz; // Valeur moyenne de la puissance sur les nbP50Hz mesures
if (getLocalTime(&timeinfo)) {
strftime(info_DH, 24, "%d/%m/%Y %H:%M:%S,", &timeinfo); // Mise en forme de la date : JJ/MM/AAA HH:MM:SS
if (abs(pActifReseau) > 10000) { // Sparadrap pour masquer une potentielle erreur
pActifReseau = pActifReseauPrec;
logPb(1);
}
if (abs(pActifOnduleur) > 10000) { // Sparadrap pour masquer une potentielle erreur
pActifOnduleur = pActifOnduleurPrec;
logPb(2);
}
snprintf(info_PPU, 32, "%.1f,%.1f,%.1f", pActifReseau, pActifOnduleur, vRMS);
snprintf(info_PPDD, 32, "%.1f,%.1f,%.2f,%.2f\n", -pActifReseau, pActifOnduleur, cosPhi_Res, cosPhi_Ond);
infUIoK = true;
if (timeinfo.tm_sec % 30 == 0) { // Enregistrement toutes les 30 secondes
appendFile2(LittleFS, fchHisto, info_DH, info_PPU, 114688); // Enregistrement d'une nouvelle ligne de données
if (timeinfo.tm_yday != jourPrec) { // MàJ de l'heure à chaque changement de jour et ...
configTime(0, 0, ntpServer);
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); // Définir le fuseau horaire pour Europe centrale (Paris)
tzset();
//configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); // On configure le seveur NTP
fchHisto = remplaceFchHisto(); // ... remplace l'ancien fichier "fchHisto" portant sur le même jour de la semaine
timestamp = mktime(&timeinfo); // Temps UNIX de la nouvelle journée
jourPrec = timeinfo.tm_yday;
}
if (WiFi.status() != WL_CONNECTED) { // Si problème de connexion au WiFi
File file = LittleFS.open(Suivi, FILE_APPEND);
file.print(info_DH);
file.print(',');
file.print("Déconnexion ... ");
WiFi.disconnect();
WiFi.begin(ssid, password);
tr = millis();
while (WiFi.status() != WL_CONNECTED && millis()-tr < 10000) {
delay(100);
}
if (millis() - tr > 10000 )
file.print("Echec reconnexion\n");
else
file.print("Reconnexion OK \n");
file.close();
}
affOLED(2);
}
}
if (pActifReseau < 0) // Si il y a surplus de production
nbP_CmdTriac += 1 + 50 * pActifReseau / pMaxSurplus;
else
nbP_CmdTriac -= 1 + 50 * pActifReseau / pMaxSurplus;
nbP_CmdTriac = constrain(nbP_CmdTriac, 0, nbP50Hz - 1);
if (Vu)
sumPA_R = 0; // Remise à zéro de la puissance moyenne toutes les nbP50Hz périodes
else
sumPA_O = 0; // Remise à zéro de la puissance moyenne toutes les nbP50Hz périodes
if (nbP_CmdTriac == 0)
digitalWrite(pin_CmdTriac1, LOW);
else
digitalWrite(pin_CmdTriac1, HIGH);
modeFonctionnement(); // Modifie la gestion du surplus de production
}
}
if (nbP_CmdTriac < noCycle) // Remise à zéro de la commande du triac
digitalWrite(pin_CmdTriac1, LOW); // Attention, cette commande doit arriver avant le front montant de la tension EDF
etatPrec = etatNouv;
t1++;
pb = statut();
if (digitalRead(pin_ResetTotal) == LOW && LittleFS.exists(FchWiFi)) { // Réinitialisation totale par effacement du fichier "FchWiFi"
Serial.println("Réinitialisation totale");
LittleFS.remove(FchWiFi);
}
}
Bon courage pour déchiffrer tout ça 
Cordialement.
Pierre