[Plugin Tiers] Plugin SuiviCO2 --> new plugin, cherche beta testeur!

Bonjour @agp.com

J’ai joué petit bras avec mes 12000 lignes. J’aurais pu faire mieux. :wink: Avec 1 ligne par minute, le maxi est 44640 31joursx24hx60min
Ça doit être l’époque où j’ai essayé de comprendre les différents lissages.
Sans lissage, les lignes sont transférées brutes dans historyArch

Ci-dessous le zip de l’historique de l’index du Linky pour décembre 2019:
historyArch.txt (71,3 Ko)

Hello @jpty,

en effet, peut mieux faire :wink:
Merci pour l’historique, une valeur toutes les minutes, c’est de la folie ! Mais le plugin suiviconso fait pareil et archive même tout en double dans une table séparée… (1,568,273 lignes pour moi depuis déc 2015 rien que pour cette table…)
Moi je reste raisonnable avec 1 data par heure…
Oui en effet l’historyArch reste brut (seul les doublons sont supprimés) quand on choisit l’archivage « none », mais il faut aller jouer dans le code pour ça, il me semble que c’est pas dispo via l’interface, si ?

Je suis allé voir le code du core de la ligne correspondant à l’erreur, malheureusement c’est incompréhensible (disons que ça dépasse mes compétences, le PHP n’étant pas ma langue maternelle, et le core ne contient aucun commentaire, ça serait trop facile !).
Très probablement le problème vient de l’excédent de datas renvoyé par ma requête « getHistory », sauf que comme je peux pas savoir la quantité en DB avant de l’avoir demandé, ça va pas être facile à gérer. Je pourrais brider les requêtes à 1 mois max pour tout le monde, mais c’est pénalisant pour tous ceux qui ne s’amusent pas à enregistrer leur index toutes les minutes…
Ou je peux ajouter l’info dans le pop-up (et dans la doc évidemment !! :wink: ) de diminuer la période de la requête en cas d’erreur 500 ou de timeout… C’est pas génial mais ça devrait couvrir le besoin…

@Spine,

merci pour ton retour sur le gaz, heureusement que j’ai pas lancé le plugin en début d’hiver alors ! L’objectif était justement de prendre conscience de l’impact de nos comportements, c’est donc atteint ! :wink:

Vu les retours plutôt positifs, je pense demander la stable dans la journée !

Cette beta a deja bien progressé avec vos remarques ! :blush:

1 « J'aime »

C’est dans la configuration de la commande:
image

Je suis passé en lissage Maximum le 9 déc.

Il faudrait changer la requête SQL pour ne récupérer que les données où les minutes sont 00

SELECT *
FROM `historyArch`
WHERE `cmd_id` = '4928' AND `datetime` LIKE '2019-12%' AND `datetime` LIKE '%:00:%'

Avec ce genre de requête, il me reste quand même presque 8500 lignes pour 2019.
Si ce n’est pas une requête possible dans Jeedom, il faudrait faire une extension de la class history dans votre plugin. Je l’ai fait pour un dev perso en partant de la fonction history::all, mais peut-être que ce n’est pas autorisé dans un plugin.

Pour les erreurs memory_limit et max_execution_time, c’est des directives dans php.ini

Vous m’avez l’air beaucoup plus doué que moi sur ces sujets !
C’est effectivement probablement ce qu’il faudrait faire, j’avoue ne pas avoir très envie de me lancer dans ce genre de manip pour une fonction annexe…

J’ai fait une fonction similaire à getHistory placée à la fin de votre fichier class.php

class suiviCo2History extends history {
  function suiviCo2GetHistory($_cmd_id,$_startTime = null,$_endTime = null)
  { $values = array( 'cmd_id' => $_cmd_id,);
  if ($_startTime !== null) $values['startTime'] = $_startTime;
    if ($_endTime !== null) $values['endTime'] = $_endTime;
    $sql = 'SELECT ' . DB::buildField('history');
    $sql .= ' FROM ( SELECT ' . DB::buildField('history') . ' FROM history WHERE cmd_id=:cmd_id';
    if ($_startTime !== null) $sql .= ' AND datetime>=:startTime';
    if ( $_endTime != null ) $sql .= ' AND datetime<=:endTime';
    $sql .= " AND datetime LIKE '%:00:%'";
    $sql .= ' UNION ALL SELECT ' . DB::buildField('history') . ' FROM historyArch WHERE cmd_id=:cmd_id';
    if ($_startTime !== null) $sql .= ' AND datetime>=:startTime';
    if ( $_endTime != null ) $sql .= ' AND datetime<=:endTime';
    $sql .= " AND datetime LIKE '%:00:%'";
    $sql .= ' ) as dt ORDER BY datetime ASC';
    // log::add(__CLASS__,'error',"SQL: $sql");
    return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, 'history');
  }
}

Modifié partiellement votre getAndRecordHistoriqueConso:

public function getAndRecordHistoriqueConso($_startDate, $_endDate){ // fct appelée par l'AJAX

        if($this->getConfiguration('index_HC')!=''){
          $_typeConso = array('HP', 'HC');
        } else {
          $_typeConso = array('HP');
        }

        foreach ($_typeConso as $_type) {
          $nbdataimportees = 0;
          $calculstarttime = date('H:i:s');
          // on recupere la cmd contenant l'index
          $index_cmd_id = $this->getConfiguration('index_' . $_type); //on va chercher l'id de la CMD contenant index_HP ou HC via la conf utilisateur, format #10#
          $cmdIndex = cmd::byId(str_replace('#', '', $index_cmd_id)); // on vire les # et on prend cette commande (d'un autre objet !)
          if (!is_object($cmdIndex)) {
            log::add('suiviCO2', 'warning', 'Pas de commande dans le champs ' . $_type . ' ou ' . $index_cmd_id . ' n est pas une commande valide - Fin de l import');
            return array();
          }

          $cmd = $this->getCmd(null, 'consumption' . $_type); // on prend la commande dans laquelle on va ecrire notre resultat de calcul conso
          if (is_object($cmd)) {
            $historyIndex = suiviCo2History::suiviCo2GetHistory($cmdIndex->getId(),$_startDate,$_endDate);
            $coef_thermique = $this->getConfiguration('coef_thermique',1);
            $nb = 0;
            foreach ($historyIndex as $history) {
              $value = $history->getValue();
              if ($nb != 0) {
                $valueDateTime = $history->getDatetime();
                $conso = round($value * $coef_thermique - $prevHisto * $coef_thermique, 0);
                $cmd->addHistoryValue($conso, $valueDateTime);
                $nbdataimportees++;
              }
              $prevHisto = $value;
              $nb++;
            }
          }
          log::add(__CLASS__, 'error', 'Import data ' . $_type . ' de ' . $_startDate . ' à ' . $_endDate . ', start à ' . $calculstarttime . ' fin à : ' . date('H:i:s') . ', nb data importées : ' . $nbdataimportees);
        }
      }

Résultat: Import 2019+2020:
image
image
L’histo qui a été importée:

Reste à vérifier la cohérence et les valeurs de début et fin.

PS: Désolé pas de commentaires dans le source.

Génial !!! :blush:

Merci infiniment !

Par contre dans getAndRecordHistoriqueConso il faut absolument que suiviCo2History ait bien renvoyé les datas dans le bon ordre vu qu’on soustrait value de prevHisto sans vérifier les timestamps.

Dans la nouvelle class history il faudrait lui demander un « sort » des datas pour être sur d’avoir les plus vieilles au début, non ? (suis nulle en sql…)

Sinon c’est clair que c’est plus efficace et plus propre que mon code initial avec double foreach sur le même tableau et unset pour virer la data une fois traitée… (j’y avais déjà passé un certain temps pour optimiser ça pourtant ! :thinking:)

Puisque vous êtes si fort, vous voudriez pas relire le reste du code par hasard ? :innocent: (sur github, ça sera plus simple…)
C’est mon premier plugin « from stratch » et je suis sure qu’il est blindé de trucs discutables…

Vous avez raison. J’ai ajouté dans la recup de l’ancien historique :

 ORDER BY datetime ASC

Les données sont créées dans la nouvelle cmd dans le bon ordre.

Il est où votre github ?

Oui comme ça ça sera parfait ! Merci encore !!

Je fais quelques tests et je l’envoie dans la nouvelle beta (j’ai demandé ce matin le passage en stable sur la version précédente… tant pis je les laisse valider l’ancienne et je ferais une mise a jour de stable après…)

Mon github est là : https://github.com/AgP42/suiviCO2/

[2020-03-03 20:37:01][INFO] : Import data HP de 2015-02-11 à 2020-03-04, start à 20:36:17 fin à : 20:37:01, nb data importées : 33229
[2020-03-03 20:37:44][INFO] : Import data HC de 2015-02-11 à 2020-03-04, start à 20:37:01 fin à : 20:37:44, nb data importées : 32208

86s pour plus de 4 ans de datas HP et HC, c’est hallucinant !! :upside_down_face: :smile:
Dans ma première version de cette fonction j’était a 50s pour… 1 mois ! Puis j’ai optimisé a 3s et j’étais deja contente de moi… :unamused:

J’ai changé les types de log pour pas surcharger la messagerie et op je la passe en stable !

Si l’équipe Jeedom a quelque chose à redire ca sera l’occasion… (mais je crois qu’ils regardent surtout si la doc est présente :laughing:)

Edit : par acquis de conscience, j’ai appliqué mon ancienne fonction et votre nouvelle fonction sur les memes datas puis j’ai exporté les données de la DB pour les comparer : strictement identique ! :+1:

Bonsoir @agp.com

En fait, la fonction suiviCo2GetHistory pourrait être réintégrée dans la classe suiviCO2 sans être une extend d’history et appelée par self::suiviCo2GetHistory
Comme cela il n’y aurait rien qui « dépasse » des 2 classes recommandées.

Je vous laisse, il parait que je monopolise cette conversation. :rofl:
J’ai ça à droite à la place de l’aperçu:

:rofl: :rofl: :rofl:

Ben tant pis si l’algo n’est pas content, moi j’apprécie beaucoup votre aide !!

J’ai regardé le code du plugin (officiel) energy qui fait aussi des appels direct en base, leur fonction est dans ‹ class energyCmd extends cmd { › ce qui leur permet de l’appeller tres simplement comme ca ‹ $cmd->getHistoryEnergy($_startTime, $_endTime) ›.
Et donc plus besoin de passer l’id de la cmd en argument, il suffit de le recuperer avec un

$values = array(
   'cmd_id' => $this->getId(),
);

Je vais faire la modif de la même façon.

EDIT : ca marche pas mon affaire comme le plugin energie… :grimacing: erreur 500… mais pourquoi ??? Est-ce que c’est parce que je l’appelle sur une cmd d’un autre plugin ($cmdIndex) ? Je vois pas pourquoi ca devrait le déranger…
Alors j’ai changé comme dit :

Et la miracle, ca marche nickel…

Bonjour @agp.com

Quand il y a erreur 500, il faut aller voir le log http.error. Normalement, il y a le pourquoi:

PHP Fatal error:  Uncaught Error: Call to undefined method legrandecoCmd::suiviCo2GetHistoryCmd()

Il utilise la classe de la cmdIndex

C’est ce que je me disais… ceci explique donc cela !

Le plugin vient de passer en stable ! (Derniere version de ce matin avec la fonction de requête sql dans la class eqLogic) !

1 « J'aime »

Bonjour @agp.com

J’ai désactivé la tuile suiviCO2 et j’ai un message chaque heure:

[2020-03-11 11:00:19][ERROR] : Erreur sur la fonction cronHourly du plugin : Call to a member function getConfiguration() on null

C’est dû à:

if($suiviCO2->getConfiguration('conso_type') == 'elec')

avec suiviCO2 non initialisé puisque pas d’eqLogic actif.

Même message d’erreur quand je veux afficher le panel. Je voulais juste voir les gCO2 émis par kWh en France.

Je vais juste masquer la tuile.

Merci pour l’info, j’ajouterai des if sur getIsVisible() et getIsEnable() un peu partout pour gérer ces cas là pour la prochaine version. C’est un test auquel je n’avais pas pensé !

@jpty, je viens de pousser une nouvelle beta qui devrait corriger le problème.

En fait il y avait 2 bugs :

  • sur le panel qui cherchait un eqLogic a afficher et n’en trouvait pas, j’ai ajouté une exception pour dire a l’utilisateur qu’il n’y avait aucun equipement actif
  • dans le cronHourly, en fait je ne sais meme pas comment ca tombait en marche en l’état, probablement juste parce que chez moi mon dernier équipement était élec. Il testait la configuration sur un $suiviCO2 qui correspondait à la variable du foreach précédent. Bref, j’ai corrigé ça, maintenant si un des équipement est de type « elec », on appellera l’API. Si aucun « elec » parmi les « actifs », on ne fait même pas l’appel à l’API.

Tu peux tester cette nouvelle beta et me dire si ca corrige bien le soucis chez toi aussi ?

Merci !

Merci pour la correction.
Pour le panel ça semble bon j’ai bien le message « Aucun équipement actif » (J’aurais ajouté suiviCO2 ds le msg.)
Pas de message d’erreur au cron de 16h.

sleep(60); dans cronHourly ne me parait pas très ‹ clean ›.
Tous les autres cronHourly sont retardés.
24s au cron de 16h et 192s à 17h avec suiviCO2 réactivé.
J’enlève le sleep pour le cron de 18h pour voir le temps.
C’est pas grave si les données n’arrivent qu’à l’heure suivante ?

Edit : Au cron de 18h sans slip ( durée 27s ) les données récupérées :
image

Cron de 19h: 23s La valeur ci-dessus pour 18h a augmenté.

Super, merci pour ton test.
Je mettrais a jour le message pour la version stable : « Aucun équipement suiviCO2 actif »

En fait l’API ne répond en général pas du tout si tu la demandes à heure pile pendant son update, donc c’est pas juste un retard d’1h mais un timeout et aucune donnée ! C’est pour ça que j’ai retardé de 60s. Visiblement tu as suffisamment de cronHourly dans tes plugins pour que suiviCO2 ne s’exécute pas à heure fixe, donc tu ne vois pas l’erreur API, mais ça ne sera pas le cas de tout le monde.
Je suis d’accord ce n’est pas très propre, je voulais gérer ça avec espèce de « setTimeout » qui appellerai la fonction avec un peu de retard pour ne pas gêner les autres, mais visiblement ça existe pas en PHP… (https://stackoverflow.com/questions/3435418/is-there-a-function-similar-to-settimeout-javascript-for-php/17252448) alors j’ai fait ça avec un pauvre sleep. Mais si tu as une proposition d’amélioration, je prend ! :wink:

Le second problème si tu vires le sleep c’est pour actualiser la variable qui s’affiche sur le dashboard avec la valeur « courante », en fait mon code prend l’heure pleine courante -15min. Donc si tu as 1h de décalage dans tes données de l’API, tu n’auras pas cette donnée…

Ta valeur de 18h (quand tu vas la lire entre 18h et 19h) dans ta base de donnée est en fait celle de 17h45 (52gCO2). Si tu regardes le log debug ou carrément l’API brut, la valeur de 18h c’est 53gCO2. Vu qu’à 18h ma dernière valeur connue est 17h45, je prend cette là pour la donner en « event » à ma commande pour actualiser le dashboard. Et pour des raisons que j’ignore, je n’arrive pas à lui assigner son horaire correct avec cette fonction. Pour lui donner un autre datetime que l’heure courante, je dois faire un addHistoryValue qui alors ne s’affiche alors pas sur le dashboard… :dizzy_face: :exploding_head:

Et c’est ce qui explique que ta valeur de 18h (qui était celle de 17h45) a bougé a 19h. A 19h l’API t’as donné la vrai valeur (=53 gCO2) et alors Jeedom, qui avait déjà une valeur a cet horaire a fait une moyenne entre les 2… (Tu dois avoir 52,5 après le cron de 19h, right ?).

J’avais pensé faire 2 cmd jeedom pour éviter cette approximation mais c’était lourd à gérer. C’est pas génial génial mais bon, de toute façon ces datas « temps réel » sont déjà des approximations. Il faut régulièrement lancer la fonction qui récupère les données définitives pour corriger ça et avoir les bonnes valeurs (dans la table historyArch cette fois, donc pas d’histoire de moyenne ! La fonction d’archive elle écrase l’éventuelle donnée précédente !)
Bref, je sais pas si j’ai été très claire… je me suis beaucoup pris la tête pour essayer de comprendre le fonctionnement de Jeedom sur ces fonctions d’historisation et d’archives et j’ai fait de mon mieux pour le code !
Mais bien joué, tu as trouvé un truc pas trés clean ! :wink: C’est grave docteur ?