**Evolution V2.00 du 20/10/2025
Optimisation des injections
Récupères et injecte dynamiquement depuis la date du dernier index
Ajout d’une tolérance pour journée incomplète
Force journée= bleu si pas e couleur dans l’historique
Amelrioation des logs
Correction du 13/01/2024
Alignement des injections à 29/59 au lieu de 00/30. cela permet de ne pas avoir à 00h00 la consommation de la veille pour 23h30-00h00 pris en compte dans le calcul du jour.
Ajout d’une ligne à 0 à 0h00 pour le bon fonctionnement. elle ne sert à rien dans les calculs mais est nécessaire pour le moment pour la synchro car crée un évènement sur la journée.
je laisse les logs pour le moment
Correction du 05/12/2023
régression corrigé , j’avais omis de remettre l’appel pour les derniers index dans la base.
j’ai laissé les logs pour le moment
Correction du 04/12/2023
- corrige la couleur en prenant en compte la couleur de 06h00 à 05h59 le lendemain. au lieu de la journée
- ne nécessite plus de modifier avec adminer les index de la table conso_teleinfo en supprimant « unique » pour timestamp
Restriction connues :
- si pas de données dans ecowatt maintenant => le scenario s’arrête
solutions : importer les données via un scenario, en respectant les heures (>06h00
pour HPx et >22h00 pour HCx
Voici le script
<<<<<<<<<<<<c’est une beta>>>>>>>>>>> donc soyez prudent et surtout indulgent. C’est mon premier codage …je débute tout juste le php et le ‹ jeedom ›.
nécessite :
- plugin suiviconso
… Vous créez un nouvel élément sur lequel vous ne cocher surtout rien afin qu’aucune commandes ne soient appelées
- plugin Enedis
- plugin Ecowat
Le bloc code
// =========================
// CONFIGURATION
// =========================
$id_equipement = 258; // celui de suivi_conso
$toleranceManquants = 2; // entre 0 et 48creneaux manquants
// Commandes Jeedom
$cmdConsoPath = "#[Maison][Poitiers][Consommation Horaire]#"; //chemin historique données horaire du pluggin Enedis
$cmdTempoPath = "#[Maison][Tempo][Maintenant]#"; //chemin historique données couleur du pluggin Tempo
// Fenêtres HP/HC
$HP_START = "06:00:01";
$HC_START = "22:00:01";
// Conso horaire (kWh) ? Oui => demi-heure = /2
$DIVISE_CONSO = 2;
// Index initiaux (raccord compteur)
$hchp = 15615695; // HP Bleu
$hchc = 6262995; // HC Bleu
$hchp2 = 1062795; // HP Blanc
$hchc2 = 471645; // HC Blanc
$hchp3 = 550000; // HP Rouge
$hchc3 = 237835; // HC Rouge
// Comportements
$FORCE_BLEU_IF_NO_TEMPO = true;
$LOG_DETAIL = false;
$LOG_ABS_CONSO_AGG = true;
// Tableaux pour récapitulatif
$joursManquants = [];
$joursSansCouleur = [];
$joursManquantsDetail = [];
// =========================
// Récupération des index cumulés depuis la dernière ligne
// =========================
function chargerIndexDerniereLigne($id_equipement, $scenario) {
$sql = "SELECT hchp, hchc, hchp2, hchc2, hchp3, hchc3
FROM conso_teleinfo
WHERE id_equipement = :ide
ORDER BY timestamp DESC
LIMIT 1";
$row = DB::Prepare($sql, array(':ide' => $id_equipement), DB::FETCH_TYPE_ROW);
if (!empty($row)) {
$scenario->setLog("[DEBUG] Index init depuis base: HP={$row['hchp']} HC={$row['hchc']} HP2={$row['hchp2']} HC2={$row['hchc2']} HP3={$row['hchp3']} HC3={$row['hchc3']}");
return array_map('intval', $row);
} else {
$scenario->setLog("[DEBUG] Aucune ligne en base: utilisation des index init de configuration");
return null;
}
}
// Charger les index init depuis la dernière ligne en base (si disponible)
$idxInit = chargerIndexDerniereLigne($id_equipement, $scenario);
if ($idxInit) {
$hchp = $idxInit['hchp'];
$hchc = $idxInit['hchc'];
$hchp2 = $idxInit['hchp2'];
$hchc2 = $idxInit['hchc2'];
$hchp3 = $idxInit['hchp3'];
$hchc3 = $idxInit['hchc3'];
}
// =========================
// RÉCUP COMMANDES
// =========================
$cmdConso = cmd::byString($cmdConsoPath);
if (!is_object($cmdConso)) {
$scenario->setLog("ERREUR: Commande conso introuvable: " . $cmdConsoPath);
return;
}
$idConso = $cmdConso->getId();
$cmdTempo = cmd::byString($cmdTempoPath);
if (!is_object($cmdTempo)) {
$scenario->setLog("ERREUR: Commande Tempo introuvable: " . $cmdTempoPath);
return;
}
$idTempo = $cmdTempo->getId();
$scenario->setLog("OKcommandes: consoId=$idConso, tempoId=$idTempo");
// =========================
// SQL INSERT
// =========================
$sqlInsert = "INSERT INTO `conso_teleinfo`
(timestamp, rec_date, rec_time, hchp, hchc, hchp2, hchc2, hchp3, hchc3, ptec, papp, id_equipement)
VALUES (:ts, :rdate, :rtime, :hchp, :hchc, :hchp2, :hchc2, :hchp3, :hchc3, :ptec, :papp, :ide)
ON DUPLICATE KEY UPDATE timestamp = timestamp";
// =========================
// FONCTIONS UTILES
// =========================
function isHP($time, $HP_START, $HC_START) {
$t = strtotime($time);
$hp = strtotime($HP_START);
$hc = strtotime($HC_START);
return ($t >= $hp && $t < $hc);
}
function tempoWindow($dayDate) {
$start = clone $dayDate; $start->setTime(6, 0, 0);
$end = clone $start; $end->add(new DateInterval('P1D')); $end->sub(new DateInterval('PT1S'));
return array($start, $end);
}
function jourManquant($dateStr, $idConso, $scenario, $toleranceManquants) {
global $joursManquantsDetail;
$J = new DateTime($dateStr);
$pub0 = clone $J;
$pub0->setTime(0, 30, 0);
$manquants = 0;
$joursManquantsDetail[$dateStr] = []; // initialise le tableau pour ce jour
for ($k = 0; $k < 48; $k++) {
$pub = clone $pub0;
$pub->add(new DateInterval("PT" . ($k * 30) . "M"));
$start = clone $pub;
$start->sub(new DateInterval("PT30M"));
$start->add(new DateInterval("PT1S"));
$stat = history::getStatistique(
$idConso,
$start->format('Y-m-d H:i:s'),
$pub->format('Y-m-d H:i:s')
);
$watt = isset($stat["sum"]) ? (float)$stat["sum"] : 0.0;
if ($watt <= 0) {
$manquants++;
// On stocke l’intervalle manquant pour audit
$joursManquantsDetail[$dateStr][] = $start->format('H:i') . '-' . $pub->format('H:i');
}
}
$scenario->setLog("[DEBUG] Vérif historique $dateStr : $manquants publications manquantes (tolérance=$toleranceManquants)");
// Jour considéré comme manquant uniquement si le nombre de créneaux manquants dépasse la tolérance
return ($manquants > $toleranceManquants);
}
// =========================
// INJECTION
// =========================
function injecterJour($dateStr, $idConso, $idTempo, $scenario,
$HP_START, $HC_START, $FORCE_BLEU_IF_NO_TEMPO,
$LOG_DETAIL, $LOG_ABS_CONSO_AGG,
$sqlInsert, $id_equipement,
&$hchp, &$hchc, &$hchp2, &$hchc2, &$hchp3, &$hchc3) {
global $joursManquantsDetail, $joursSansCouleur;
$D = new DateTime($dateStr);
$D->setTime(0, 0, 0);
$jourStr = $D->format('Y-m-d');
// Fenêtre Tempo
list($tempoStart, $tempoEnd) = tempoWindow($D);
$tempoStat = history::getStatistique(
$idTempo,
$tempoStart->format('Y-m-d H:i:s'),
$tempoEnd->format('Y-m-d H:i:s')
);
$tempoVal = $tempoStat["last"] ?? null;
$scenario->setLog("[DEBUG] Injection $jourStr avec tempo=$tempoVal");
// Préparation batch SQL
$values = [];
$params = [];
$lastPtec = null;
// Point de départ : 00h30
$pub = clone $D;
$pub->setTime(0, 30, 0);
for ($k = 0; $k < 48; $k++) {
$end = clone $pub;
$end->add(new DateInterval("PT" . ($k * 30) . "M"));
$start = clone $end;
$start->sub(new DateInterval("PT30M"));
$start->add(new DateInterval("PT1S"));
$stat = history::getStatistique(
$idConso,
$start->format('Y-m-d H:i:s'),
$end->format('Y-m-d H:i:s')
);
$watt = isset($stat["sum"]) ? (float)$stat["sum"] : 0.0;
$wh = $watt / 2.0;
if ($watt <= 0) {
//$joursManquantsDetail[$jourStr][] = $start->format('H:i').'-'.$end->format('H:i');
continue;
}
// Détermination HP/HC
$timeStr = $end->format('H:i:s');
$isHP = isHP($timeStr, $HP_START, $HC_START);
// Détermination couleur Tempo
$tempoColor = $tempoVal;
if ($FORCE_BLEU_IF_NO_TEMPO && empty($tempoColor)) {
$tempoColor = 'JB'; // forcé en Jour Bleu
$joursSansCouleur[] = $jourStr;
$scenario->setLog("[INFO][TEMPO] >>> Couleur forcée en BLEU le $jourStr <<<");
}
// Mise à jour index cumulés
if (strpos($tempoColor, 'JB') !== false) {
if ($isHP) $hchp += ($wh * 1000); else $hchc += ($wh * 1000);
$ptec = $isHP ? 'HPJB' : 'HCJB';
} elseif (strpos($tempoColor, 'JW') !== false) {
if ($isHP) $hchp2 += ($wh * 1000); else $hchc2 += ($wh * 1000);
$ptec = $isHP ? 'HPJW' : 'HCJW';
} elseif (strpos($tempoColor, 'JR') !== false) {
if ($isHP) $hchp3 += ($wh * 1000); else $hchc3 += ($wh * 1000);
$ptec = $isHP ? 'HPJR' : 'HCJR';
} else {
// fallback si valeur inattendue
$ptec = $isHP ? 'HP' : 'HC';
}
$lastPtec = $ptec; // mémorise le dernier PTEC du jour
// Préparation ligne batch
$inj = clone $end;
$inj->sub(new DateInterval("PT1M"));
$values[] = "(?,?,?,?,?,?,?,?,?,?,?,?)";
$params[] = $inj->getTimestamp();
$params[] = $inj->format('Y-m-d');
$params[] = $inj->format('H:i:s');
$params [] = round ( $hchp );
$params [] = round ( $hchc );
$params [] = round ( $hchp2 );
$params [] = round ( $hchc2 );
$params [] = round ( $hchp3 );
$params [] = round ( $hchc3 );
$params[] = $ptec;
$params[] = round($watt);
$params[] = $id_equipement;
}
// Ligne d’ancrage J+1 00:00:00
$D_next = clone $D;
$D_next->add(new DateInterval('P1D'));
$D_next->setTime(0, 0, 0);
$values[] = "(?,?,?,?,?,?,?,?,?,?,?,?)";
$params[] = $D_next->getTimestamp();
$params[] = $D_next->format('Y-m-d');
$params[] = '00:00:00';
$params [] = round ( $hchp );
$params [] = round ( $hchc );
$params [] = round ( $hchp2 );
$params [] = round ( $hchc2 );
$params [] = round ( $hchp3 );
$params [] = round ( $hchc3 );
$params[] = $lastPtec ?? 'ANCHOR'; // reprend le dernier PTEC du jour
$params[] = 0;
$params[] = $id_equipement;
// Exécution batch
if (!empty($values)) {
$sql = "INSERT INTO conso_teleinfo
(timestamp, rec_date, rec_time, hchp, hchc, hchp2, hchc2, hchp3, hchc3, ptec, papp, id_equipement)
VALUES " . implode(',', $values) . "
ON DUPLICATE KEY UPDATE timestamp=timestamp";
DB::Prepare($sql, $params, DB::FETCH_TYPE_ALL);
}
$scenario->setLog("[DEBUG][CARRY] Ligne d’ancrage créée à " . $D_next->format('Y-m-d 00:00:00') . " avec PTEC=$lastPtec");
return true;
}
// =========================
// DERNIÈRE INJECTION
// =========================
$sqlLast = "SELECT rec_date, rec_time
FROM conso_teleinfo
WHERE id_equipement = :ide
ORDER BY timestamp DESC
LIMIT 1";
$res = DB::Prepare($sqlLast, array(':ide' => $id_equipement), DB::FETCH_TYPE_ROW);
if ($res) {
$lastDate = trim($res['rec_date']);
$lastTime = trim($res['rec_time']);
$scenario->setLog("[DEBUG] Dernière injection conso_teleinfo : $lastDate $lastTime");
if ($lastTime === '00:00:00') {
// Ligne d’ancrage → on reprend à partir de ce jour
$loopStart = new DateTime($lastDate);
$scenario->setLog("[DEBUG] Reprise depuis ancrage $lastDate");
} else {
// Ancien mode → reprise classique
$startDate = new DateTime("$lastDate $lastTime");
$startDate->add(new DateInterval("PT30M"));
$loopStart = clone $startDate;
$loopStart->setTime(0, 0, 0);
$scenario->setLog("[DEBUG] Reprise legacy depuis " . $startDate->format("Y-m-d H:i:s"));
}
} else {
$scenario->setLog("[DEBUG] Aucune donnée trouvée → injection complète depuis la veille");
$today = new DateTime();
$yesterday = clone $today;
$yesterday->sub(new DateInterval("P1D"));
$yesterday->setTime(0, 0, 0);
$loopStart = $yesterday;
}
// =========================
// BOUCLE PRINCIPALE
// =========================
$today = new DateTime();
$yesterday = clone $today;
$yesterday->sub(new DateInterval("P1D"));
$yesterday->setTime(23, 59, 59);
$period = new DatePeriod($loopStart, new DateInterval("P1D"), $yesterday);
// Liste des jours injectés sous tolérance
$joursToleres = [];
global $joursManquantsDetail;
foreach ($period as $day) {
$dateStr = $day->format("Y-m-d");
if (jourManquant($dateStr, $idConso, $scenario, $toleranceManquants)) {
$scenario->setLog("[DEBUG][BACKFILL] Jour manquant $dateStr → pas d'injection");
$joursManquants[] = $dateStr;
} else {
// Injection acceptée (même si jour incomplet mais <= tolérance)
$scenario->setLog("[DEBUG][BACKFILL] Injection $dateStr");
///test//
$scenario->setLog("[DEBUG][CHECK] $dateStr → manquants détectés = " . count($joursManquantsDetail[$dateStr]));
// Vérifie si le jour a été injecté sous tolérance
if (!empty($joursManquantsDetail[$dateStr])) {
$nbManquants = count($joursManquantsDetail[$dateStr]);
if ($nbManquants > 0 && $nbManquants <= $toleranceManquants) {
$scenario->setLog("[DEBUG][TOLERANCE] $dateStr injecté malgré $nbManquants créneaux manquants (tolérance=$toleranceManquants)");
$joursToleres[] = $dateStr . " ($nbManquants manquants)";
}
}
injecterJour(
$dateStr, $idConso, $idTempo, $scenario,
$HP_START, $HC_START, $FORCE_BLEU_IF_NO_TEMPO,
$LOG_DETAIL, $LOG_ABS_CONSO_AGG,
$sqlInsert, $id_equipement,
$hchp, $hchc, $hchp2, $hchc2, $hchp3, $hchc3
);
}
}
// =========================
// LOG DE SYNTHÈSE
// =========================
if (!empty($joursManquants)) {
$scenario->setLog("[RÉCAP] Jours manquants : " . implode(', ', $joursManquants));
} else {
$scenario->setLog("[RÉCAP] Aucun jour manquant");
}
if (!empty($joursSansCouleur)) {
$scenario->setLog("[RÉCAP] Couleur forcée en BLEU pour " . count($joursSansCouleur) . " jours : " . implode(', ', $joursSansCouleur));
} else {
$scenario->setLog("[RÉCAP] Aucun jour forcé en BLEU");
}
if (!empty($joursToleres)) {
$scenario->setLog("[RÉCAP] Jours injectés sous tolérance : " . implode(', ', $joursToleres));
}
$joursInjectes = [];
foreach ($period as $day) {
$d = $day->format('Y-m-d');
if (!in_array($d, $joursManquants)) {
$joursInjectes[] = $d;
}
}
if (!empty($joursInjectes)) {
$scenario->setLog("[RÉCAP] Jours injectés normalement : " . implode(', ', $joursInjectes));
} else {
$scenario->setLog("[RÉCAP] Aucun jour injecté normalement");
}
$scenario->setLog("[DEBUG][BACKFILL] Terminé");