Bienvenue, Visiteur
Vous devez vous enregistrer avant de pouvoir poster.

Nom d’utilisateur
  

Mot de passe
  





Rechercher dans les forums

(Recherche avancée)

Derniers sujets
v17 aide
Dernier message : Genish
Il y a 9 minutes
vitesse interrogation uxi...
Dernier message : F1ATB
Il y a 12 minutes
Pb installation rapide ro...
Dernier message : F1ATB
Il y a 33 minutes
Je souhaite me lancer...
Dernier message : Seb57
Il y a 42 minutes
Modification page action
Dernier message : F1ATB
Il y a 1 heure
Station de charge VE-RMS ...
Dernier message : EG44
Il y a 1 heure
Installation manuelle sur...
Dernier message : laprobert
Il y a 1 heure
Pince amperemetrique pour...
Dernier message : mchlbgs
Il y a 2 heures
Evolutions afficheur dist...
Dernier message : Titi21
Il y a 2 heures
Idée installation solaire...
Dernier message : lionel62210
Il y a 3 heures

Statistiques du Forum
» Membres : 2,475,   » Dernier membre : jbmur,   » Sujets du forum : 2,057,   » Messages du forum : 18,744,  
Statistiques complètes

  Nouveauté
Posté par : tupolev89 - 22-01-2026, 04:01 PM - Forum : Routeur Photovoltaïque - Réponses (1)

Bonjour, pour les développeurs avez vous entendu parler de cette nouveauté?

https://www.igen.fr/domotique/2026/01/le...261-154409

Cordialement 
Tupolev

Imprimer cet élément

Question Vérification configuration
Posté par : Jean31 - 22-01-2026, 01:32 PM - Forum : Evolutions faites, à faire, dont vous rêvez... - Réponses (20)

Bonjour,

Un ami, indisponible actuellement, m'a installé un routeur pour optimiser la consommation de mon chauffe eau.
Pas d'anomalies de chauffe sur cet été mais l'hiver arrivant, il m'est arrivé de manquer d'eau chaude à la douche du matin.

J'ai donc décidé de forcer manuellement la chauffe pendant les heures creuses (00:00 à 08:00) pendant 2 heures. C'est concluant mais pas simple à piloter en raison de l'heure tardive de déclenchement.

Le seuil a été réglé initialement à -50 W, dois-je le laisser tel quel ? La réactivité est à 80.
J'ai une installation photovoltaïque 3 KW et un chauffe eau de 1800 W

Je suis allé  sur la chaine youtube, j'ai fait les modifs suivantes
- Réactivité passée à 20. J'ai pas bien compris les effets de ce paramètre
- J'ai inséré une condition on de 04:00 à 06:00 pour éviter les désagréments rencontrés.

Quelqu'un peut-il valider ces modifications ? Je ne suis pas très à l'aise avec toutes ces notions électriques.

Merci par avance



Pièces jointes Miniature(s)
       
Imprimer cet élément

  Modification page action
Posté par : 59jag - 21-01-2026, 11:42 PM - Forum : Evolutions faites, à faire, dont vous rêvez... - Réponses (14)

J ai fait quelques modifications de la page action.
Car sur smartphone tres difficile de ne pas modifier les plage horaire qui sont trop sensible.

le bin

https://drive.google.com/file/d/1aADt1Ao...p=drivesdk

dans le binaire il y a aussi la possibilite de lancer  des actions avec des interrupteur ou poussoir branche sur gpio

la modif de js action

Code :
const char * ActionsJS1 = R"====(
var LesActions = [];
var mouseClick = false;
var blockEvent = false;
var draggedHandle = null;    
var LesTemperatures = [];
var NomTemperatures = [];
var ListeActions = [];
var SelectActions = "";
var LTARFbin = 0;
var pTriac = 0;
var ReacCACSI = 1;
var PlotIdx = -1;
var TabIdx = 0;
var MesuresPwAct = [];
var Ecart = [];
var Ouvert = [];
var Retard = [];
var Prop = [];
var Integ = [];
var Deriv = [];
var Pause = false;
var IS = "|";
var BordsInverse = [".Bactions"];
function Init() {
    LoadActions();
    LoadCouleurs();
    ShowAction();
}
function creerAction(aActif, aTitre, aHost, aPort, aOrdreOn, aOrdreOff, aRepet, aTempo, aKp, aKi, aKd, aPID, aPeriodes) {
    if (aTitre == "") aTitre = "Titre";
    var S = {
        Actif: aActif,
        Titre: aTitre,
        Host: aHost,
        Port: aPort,
        OrdreOn: aOrdreOn,
        OrdreOff: aOrdreOff,
        Repet: aRepet,
        Tempo: aTempo,
        Kp: aKp,
        Ki: aKi,
        Kd: aKd,
        PID: aPID,
        Periodes: aPeriodes
    }
    return S;
}
function TracePlanning(iAct) {
    var Radio0 = "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-0' onclick='checkDisabled();'>Inactif</div>";
    var Radio1 = "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-1'  onclick='checkDisabled();'>Découpe sinus</div>";
    if (iAct > 0) { Radio1 = "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-1'  onclick='checkDisabled();'>On/Off</div>"; }
    Radio1 += "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-5'  onclick='checkDisabled();'>Demi-sinus</div>";
    Radio1 += "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-2'  onclick='checkDisabled();'>Multi-sinus</div>";
    Radio1 += "<div ><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-3'  onclick='checkDisabled();'>Train de sinus</div>";
    Radio1 += "<div id='Pwm" + iAct + "'><input type='radio' name='modeactif" + iAct + "' id='radio" + iAct + "-4'  onclick='checkDisabled();'>PWM</div>";
    var SelectPin = "<div>Gpio <select id='selectPin" + iAct + "' onchange='checkDisabled();'  title='Choix broche (GPIO) de commande'>";
    for (var i = 0; i < Pins.length; i++) {
        var v = "gpio:" + Pins[i];
        if (Pins[i] == 0) v = "";
        if (Pins[i] == -1) v = "Externe";
        SelectPin += "<option value=" + Pins[i] + ">" + v + "</option>";
    }
    SelectPin += "</select></div>";
    var SelectOut = "<div id='SelectOut" + iAct + "'>Sortie 'On' <select id='selectOut" + iAct + "'  title='Dépend du relais. En général +3.3V'><option value=0>0V</option><option value=1 selected>3.3V</option></select></div>";

    var S = "<div class='titre'><span id ='titre" + iAct + "'  onclick='editTitre(" + iAct + ")' title='Donnez un nom'>Titre</span></div>";
    S += "<div class='visu' onclick='Plot(" + iAct + ")' id='visu" + iAct + "' title='Zoom sur la régulation en temps réel. Les réglages peuvent être modifiés. Ne pas oublier de sauvegarder'>?</div>";
    S += "<div  id='mode' ><div class='TitZone' title='Choix du mode de découpe du secteur'>Mode</div>" + Radio0 + Radio1 + "</div>";
    S += "<div id='blocPlanning" + iAct + "' >";
    S += "<div class='les_select' id='sortie" + iAct + "'>";
    S += "<div class='TitZone' title='Définir la broche (GPIO) ou commande' >Sortie</div>" + SelectPin + SelectOut;
    S += "<div><span id='Tempo" + iAct + "'>Temporisation(s) <input type='number' class='tm' id='tempo" + iAct + "'  title='Temporisation entre chaque changement d&apos;état pour éviter des oscillations quand un appareil dans la maison consomme en dents de scie (Ex: un four).'></span></div>";
    S += "</div><div class='les_select' id='ligne_bas" + iAct + "'><div class='TitZone'>Externe</div>";
    S += "<div><span id='Host" + iAct + "'>Host<br><input type='text' id='host" + iAct + "'  onchange='checkDisabled();' title='Adresse IP machine sur réseau LAN, nom de domaine ou rien.'></span></div>";
    S += "<div><span id='Port" + iAct + "'>Port<br><input type='number' class='tm' id='port" + iAct + "'  title='Port d&apos;acc&egrave;s via le protocole http , uniquement pour machine distante. En g&eacute;n&eacute;ral <b>80</b>.'></span></div>";
    S += "<div><span id='ordreon" + iAct + "'>Ordre On<br><input type='text' id='ordreOn" + iAct + "'  title='Ordre à passer à la machine distante.'></span></div>";
    S += "<div><span id='ordreoff" + iAct + "'>Ordre Off<br><input type='text' id='ordreOff" + iAct + "' ></span></div>";
    S += "<div><span id='Repet" + iAct + "'>Répétition(s)<br><input type='number' id='repet" + iAct + "' class='tm'  title='P&eacute;riode en s de r&eacute;p&eacute;tition/rafra&icirc;chissement de la commande. Uniquement pour les commandes vers l&apos;extérieur. 0= pas de répétition.'></span></div>";
    S += "</div>";

    S += "<div  class='bouton_curseur' ><div class='boutons'><input id='adds' type='button' value='-' class='tbut'  onclick='AddSub(-1," + iAct + ")'  title='Retrait d&apos;une p&eacute;riode horaire.'>";
    S += "<input id='adds' type='button' value='+' class='tbut' onclick='AddSub(1," + iAct + ")' title='Ajout d&apos;une p&eacute;riode horaire.'></div>";
    S += "<div class='slideTriac' id='fen_slide" + iAct + "'>";
    S += "<div class='slideTriacIn' id='Propor" + iAct + "'>";
    S += "<div class='Tcell1'>Coef. Proportionnel</div>";
    S += "<div class='Tcell2'><input type='range' min='0' max='100' value='50' title='Correction proportionnelle à l&apos;écart en W' id='sliderKp" + iAct + "' style='width:100%;max-width:none;' oninput=\"GH('sensiKp" + iAct + "',Math.floor(this.value));UpdateK(" + iAct + ");\"  ></div>";
    S += "<div class='Tcell3'><strong id='sensiKp" + iAct + "'></strong></div>";
    S += "</div>";
    S += "<div class='slideTriacIn'>";
    S += "<div class='Tcell1'>Coef. Intégral ou R&eacute;activit&eacute; </div>";
    S += "<div class='Tcell2'><input type='range' min='0' max='100' value='50' title='Correction suivant l&apos;intégrale de l&apos;écart en W' id='sliderKi" + iAct + "'  style='width:100%;max-width:none;' oninput=\"GH('sensiKi" + iAct + "',Math.floor(this.value));UpdateK(" + iAct + ");\"  ></div>";
    S += "<div class='Tcell3'><strong id='sensiKi" + iAct + "'></strong></div>";
    S += "</div>";
    S += "<div class='slideTriacIn' title='Correction suivant la derivée de l&apos;écart en W' id='Derive" + iAct + "'>";
    S += "<div class='Tcell1'>Coef. Dérivé</div>";
    S += "<div class='Tcell2'><input type='range' min='0' max='100' value='50' id='sliderKd" + iAct + "' style='width:100%;max-width:none;' oninput=\"GH('sensiKd" + iAct + "',Math.floor(this.value));UpdateK(" + iAct + ");\"  ></div>";
    S += "<div class='Tcell3'><strong id='sensiKd" + iAct + "'></strong></div>";
    S += "</div>";
    S += "</div>";
    S += "<div id='PIDbox" + iAct + "'><label> PID On</label><input type='checkbox' id='PID" + iAct + "' onclick='checkDisabled();'></div>";
    S += "</div>";
    S += "<did id='graphAction" + iAct + "' class='graphAction'><div id='graphSVG" + iAct + "' class='graphSVG'></div><div class='GraphSVG' onclick='Pause=!Pause;'>&#x23EF;</div></div>";
    S += "<div style='margin:4px;'>";
    S += "<div id='infoAction" + iAct + "' class='infoAction'></div>";
    S += "<div id='curseurs" + iAct + "' class='curseur' onmousemove='dragHandle(event," + iAct + ");' onmouseup='stopDrag();' ontouchmove='dragHandle(event," + iAct + ");' ontouchend='stopDrag();'></div>";
    S += "</div>";
    S += "</div>";

    GH("planning" + iAct, S);
    GID("radio" + iAct + "-" + LesActions[iAct].Actif).checked = true;
    GH("titre" + iAct, LesActions[iAct].Titre);
    GV("host" + iAct, LesActions[iAct].Host);
    GV("port" + iAct, LesActions[iAct].Port);
    GV("ordreOn" + iAct, LesActions[iAct].OrdreOn);
    GV("ordreOff" + iAct, LesActions[iAct].OrdreOff);
    GV("repet" + iAct, LesActions[iAct].Repet);
    GV("tempo" + iAct, LesActions[iAct].Tempo);
    GV("sliderKp" + iAct, LesActions[iAct].Kp);
    GH("sensiKp" + iAct, LesActions[iAct].Kp);
    GV("sliderKi" + iAct, LesActions[iAct].Ki);
    GH("sensiKi" + iAct, LesActions[iAct].Ki);
    GV("sliderKd" + iAct, LesActions[iAct].Kd);
    GH("sensiKd" + iAct, LesActions[iAct].Kd);
    GID("PID" + iAct).checked = LesActions[iAct].PID == 1 ? true : false;
    if (LesActions[iAct].OrdreOn.indexOf(IS) > 0) {
        var vals = LesActions[iAct].OrdreOn.split(IS);
        GID("selectPin" + iAct).value = vals[0];
        GID("selectOut" + iAct).value = vals[1];
    } else {
        GID("selectPin" + iAct).value = -1;
        GID("selectOut" + iAct).value = 1;
        if (LesActions[iAct].OrdreOn == "") GID("selectPin" + iAct).value = 0;
    }
    TracePeriodes(iAct);

}


function TracePeriodes(iAct) {
    var S = "";
    var Sinfo = "";
    var SinfoClick = "";
    var left = 0;
    var H0 = 0;
    var colors = ["#666", "#66f", "#f66", "#6f6", "#cc4"]; //NO,OFF,ON,PW,Triac
    blockEvent = false;
    for (var i = 0; i < LesActions[iAct].Periodes.length; i++) {
        var w = (LesActions[iAct].Periodes[i].Hfin - H0) / 24;
        left = H0 / 24;
        H0 = LesActions[iAct].Periodes[i].Hfin;
        var Type = LesActions[iAct].Periodes[i].Type;
        var color = colors[Type];
        var temperature = "";
        if (LesActions[iAct].Periodes[i].CanalTemp >= 0) {
            if (LesTemperatures[LesActions[iAct].Periodes[i].CanalTemp] > -100) { // La sonde de température fonctionne         
                var Tsup = LesActions[iAct].Periodes[i].Tsup;
                if (Tsup >= 0 && Tsup <= 1000) temperature += "<div>T &ge;" + Tsup / 10 + "°</div>";
                var Tinf = LesActions[iAct].Periodes[i].Tinf;
                if (Tinf >= 0 && Tinf <= 1000) temperature += "<div>T &le;" + Tinf / 10 + "°</div>";
            }
        }
        var H_Ouvert = "";
        if (LesActions[iAct].Periodes[i].SelAct != 255) {
            if (LesActions[iAct].Periodes[i].Hmin > 0) H_Ouvert += "<div>H<span class='fsize8'>ouverture</span> &ge;" + Hdeci2Hmn(LesActions[iAct].Periodes[i].Hmin) + "</div>";
            if (LesActions[iAct].Periodes[i].Hmax > 0) H_Ouvert += "<div>H<span class='fsize8'>ouverture</span> &le;" + Hdeci2Hmn(LesActions[iAct].Periodes[i].Hmax) + "</div>";
            if (LesActions[iAct].Periodes[i].Ooff > 0) H_Ouvert += "<div>On à Off si &le;" + LesActions[iAct].Periodes[i].Ooff + "%</div>";
            if (LesActions[iAct].Periodes[i].O_on > 0) H_Ouvert += "<div>Off à On si &ge;" + LesActions[iAct].Periodes[i].O_on + "%</div>";
        }
        var TxtTarif = "";
        if (LTARFbin > 0) {
            TxtTarif = "Tarif : ";
            var Tarif_ = LesActions[iAct].Periodes[i].Tarif;
            if (LTARFbin <= 3) {
                TxtTarif += (Tarif_ & 1) ? "<span style='color:red;'>H. Pleine</span>" : "";
                TxtTarif += (Tarif_ & 2) ? "<span style='color:green;'> H. Creuse</span>" : "";
            } else {
                TxtTarif += (Tarif_ & 4) ? "Tempo<span style='color:blue;'>Bleu</span>" : "";
                TxtTarif += (Tarif_ & 8) ? "<span style='color:white;'> Blanc</span>" : "";
                TxtTarif += (Tarif_ & 16) ? "<span style='color:red;'> Rouge</span>" : "";
            }
            TxtTarif = "<div>" + TxtTarif + "</div>";
        }
        let TexteMinMax = "";
        var condition = (temperature != "" || H_Ouvert != "" || TxtTarif != "") ? "<div>Condition(s) :</div>" + temperature + H_Ouvert + TxtTarif : "";
        if (LesActions[iAct].Actif <= 1 && iAct > 0) {
            LesActions[iAct].Periodes[i].Vmax = Math.max(LesActions[iAct].Periodes[i].Vmin, LesActions[iAct].Periodes[i].Vmax);
            TexteMinMax = "<div>Off si Pw&gt;" + LesActions[iAct].Periodes[i].Vmax + "W</div><div>On si Pw&lt;" + LesActions[iAct].Periodes[i].Vmin + "W</div>" + condition;
        } else {
            LesActions[iAct].Periodes[i].Vmax = Math.max(0, LesActions[iAct].Periodes[i].Vmax);
            LesActions[iAct].Periodes[i].Vmax = Math.min(100, LesActions[iAct].Periodes[i].Vmax);
            TexteMinMax = "<div>Seuil Pw : " + LesActions[iAct].Periodes[i].Vmin + "W</div>" + "<div>Ouvre Max : " + LesActions[iAct].Periodes[i].Vmax + "%</div>" + condition;
        }
        var TexteTriac = "<div>Seuil Pw : " + LesActions[iAct].Periodes[i].Vmin + "W</div>" + "<div>Ouvre Max : " + LesActions[iAct].Periodes[i].Vmax + "%</div>" + condition;
        var paras = ["Pas de contr&ocirc;le", "OFF", "<div>ON</div>" + condition, TexteMinMax, TexteTriac];
        var para = paras[Type];
       
        // Créer la période
        S += "<div id='zone" + iAct + "_" + i + "' class='periode' data-idx='" + i + "' style='width:" + w + "%;left:" + left + "%;background-color:" + color + ";'>";
       
        // Ajouter une poignée de déplacement uniquement si ce n'est pas la dernière période
        if (i < LesActions[iAct].Periodes.length - 1) {
            var handleStyle = "position:absolute;right:-15px;top:50%;transform:translateY(-50%);width:30px;height:60px;";
            handleStyle += "background-color:rgba(255,255,255,0.8);border:2px solid #333;border-radius:8px;";
            handleStyle += "cursor:ew-resize;display:flex;align-items:center;justify-content:center;";
            handleStyle += "font-size:14px;font-weight:bold;color:#333;z-index:10;";
            handleStyle += "box-shadow:0 2px 5px rgba(0,0,0,0.3);touch-action:none;user-select:none;";
           
            S += "<div class='handle' style='" + handleStyle + "' data-action='" + iAct + "' data-periode='" + i + "' ";
            S += "onmousedown='startDrag(this,event," + iAct + "," + i + ");' ";
            S += "ontouchstart='startDrag(this,event," + iAct + "," + i + ");'>|||</div>";
        }
       
        S += "</div>";
       
        Hmn = Hdeci2Hmn(H0);
        fs = Math.max(8, Math.min(16, w / 2)) + "px";
        Sinfo += "<div class='infoZone' style='width:" + w + "%;border-color:" + color + ";font-size:" + fs + "'  onclick='infoZclicK(" + i + "," + iAct + ")'  >"
        Sinfo += "<div class='Hfin'>" + Hmn + "</div>" + para + "</div>";
        SinfoClick += "<div id='info" + iAct + "Z" + i + "' class='infoZ' ></div>";
    }
    GH("curseurs" + iAct, S);
    GH("infoAction" + iAct, SinfoClick + Sinfo);
}

)====";

const char * ActionsJS2 = R"====(
   
function startDrag(handleElement, ev, iAct, iPeriode) {
   if (ev.preventDefault) ev.preventDefault();
    if (ev.stopPropagation) ev.stopPropagation();
     draggedHandle = {
        action: iAct,
        periode: iPeriode,
        element: handleElement,
        originalStyle: handleElement.style.cssText
    };
    var dragStyle = "position:absolute;right:-15px;top:50%;transform:translateY(-50%) scale(1.2);width:30px;height:60px;";
    dragStyle += "background-color:#ffeb3b;border:2px solid #f57c00;border-radius:8px;";
    dragStyle += "cursor:ew-resize;display:flex;align-items:center;justify-content:center;";
    dragStyle += "font-size:14px;font-weight:bold;color:#333;z-index:10;";
    dragStyle += "box-shadow:0 4px 8px rgba(0,0,0,0.5);touch-action:none;user-select:none;";
    handleElement.style.cssText = dragStyle;
}

function dragHandle(ev, iAct) {
    if (!draggedHandle || draggedHandle.action !== iAct) return;
   
    if (ev.preventDefault) ev.preventDefault();
   
    var curseur = GID('curseurs' + iAct);
    var leftPos;
   
      if (ev.touches && ev.touches.length > 0) {
        leftPos = ev.touches[0].clientX - curseur.getBoundingClientRect().left;
    } else {
        leftPos = ev.clientX - curseur.getBoundingClientRect().left;
    }
   var width = curseur.getBoundingClientRect().width;
    var HeureMouse = leftPos * 2420 / width;
    var iPeriode = draggedHandle.periode;
   
    var NewHfin = Math.max(0, Math.min(HeureMouse, 2400));
   
  if (iPeriode < LesActions[iAct].Periodes.length - 1) {
        NewHfin = Math.min(NewHfin, LesActions[iAct].Periodes[iPeriode + 1].Hfin);
    }
    if (iPeriode > 0) {
        NewHfin = Math.max(NewHfin, LesActions[iAct].Periodes[iPeriode - 1].Hfin);
    }
   
   LesActions[iAct].Periodes[iPeriode].Hfin = Math.floor(NewHfin);
   var H0 = (iPeriode > 0) ? LesActions[iAct].Periodes[iPeriode - 1].Hfin : 0;
    var left = H0 / 24;
    var w = (NewHfin - H0) / 24;
   
   var zone = GID('zone' + iAct + '_' + iPeriode);
    if (zone) {
        zone.style.width = w + '%';
    }
   
     if (iPeriode < LesActions[iAct].Periodes.length - 1) {
        var nextZone = GID('zone' + iAct + '_' + (iPeriode + 1));
        var nextLeft = NewHfin / 24;
        var nextW = (LesActions[iAct].Periodes[iPeriode + 1].Hfin - NewHfin) / 24;
        if (nextZone) {
            nextZone.style.left = nextLeft + '%';
            nextZone.style.width = nextW + '%';
        }
    }
}

function stopDrag() {
    if (draggedHandle && draggedHandle.element) {
      draggedHandle.element.style.cssText = draggedHandle.originalStyle;
       
      var iAct = draggedHandle.action;
        TracePeriodes(iAct);
    }
    draggedHandle = null;
}

function AddSub(v, iAct) {
    if (v == 1) {
        if (LesActions[iAct].Periodes.length < 8) {
            LesActions[iAct].Periodes.push({
                Hfin: 2400,
                Type: 1,
                Vmin: 0,
                Vmax: 100,
                Tinf: 1600,
                Tsup: 1600,
                Hmin: 0,
                Hmax: 0,
                CanalTemp: -1,
                SelAct: 255,
                Ooff: 0,
                O_on: 0,
                Tarif: 31
            }); //Tarif codé en bits
            var Hbas = 0;
            if (LesActions[iAct].Periodes.length > 2) {
                Hbas = parseInt(LesActions[iAct].Periodes[LesActions[iAct].Periodes.length - 3].Hfin);
            }
            if (LesActions[iAct].Periodes.length > 1) {
                LesActions[iAct].Periodes[LesActions[iAct].Periodes.length - 2].Hfin = Math.floor((Hbas + 2400) / 2);
            }
        }
    } else {
        if (LesActions[iAct].Periodes.length > 1) {
            LesActions[iAct].Periodes.pop();
            if (LesActions[iAct].Periodes.length > 0)
                LesActions[iAct].Periodes[LesActions[iAct].Periodes.length - 1].Hfin = 2400;
        }
    }
    TracePeriodes(iAct);

}
function infoZclicK(i, iAct) {
    var capteurT = false;
    if (!blockEvent) {
        blockEvent = true;
        var Type = LesActions[iAct].Periodes[i].Type;
        var idZ = "info" + iAct + "Z" + i;
        var S = "<div class='selectZ'> S&eacute;lection Action<div class='closeZ' onclick='infoZclose(\"" + idZ + "\")'>X</div></div>";
        var check = (Type == 1) ? "checked" : "";
        S += "<div class='zOff'  ><div class='radioC' ><input type='radio'  name='R" + idZ + "' onclick='selectZ(1," + i + "," + iAct + ");' " + check + " title='Off forcé'>OFF</div></div>";
        S += "<div class='fcontainer'><div class='fcontleft'>";
        check = (Type == 2) ? "checked" : "";
        S += "<div  class='zOn'   ><div class='radioC' ><input type='radio'  name='R" + idZ + "' onclick='selectZ(2," + i + "," + iAct + ");' " + check + " 'title='On forcé (si conditions optionnelles valides)'>ON <small>100%</small></div></div>";
        check = (Type > 2) ? "checked" : "";
        var Vmin = LesActions[iAct].Periodes[i].Vmin;
        var Vmax = LesActions[iAct].Periodes[i].Vmax;
        var Tinf = LesActions[iAct].Periodes[i].Tinf;
        var Tsup = LesActions[iAct].Periodes[i].Tsup;
        var TinfC = Tinf / 10;
        var TsupC = Tsup / 10;
        var Hmin = (LesActions[iAct].Periodes[i].Hmin > 0) ? Hdeci2Hmn(LesActions[iAct].Periodes[i].Hmin) : "";
        var Hmax = (LesActions[iAct].Periodes[i].Hmax > 0) ? Hdeci2Hmn(LesActions[iAct].Periodes[i].Hmax) : "";
        var Ooff = (LesActions[iAct].Periodes[i].Ooff > 0) ? LesActions[iAct].Periodes[i].Ooff : "";
        var O_on = (LesActions[iAct].Periodes[i].O_on > 0) ? LesActions[iAct].Periodes[i].O_on : "";
        if (Tinf > 1500 || Tinf < -500) TinfC = ""; //Temperature entre -50 et 150° représenté en dixième
        if (Tsup > 1500 || Tsup < -500) TsupC = ""; //Temperature entre -50 et 150
        if (iAct > 0) {
            var Routage = ["", "Routage ON/Off", "Routage Multi-sinus", "Routage Train de Sinus", "PWM", "Routage Demi-Sinus"];
            S += "<div class='zPw' ><div class='radioC' ><input type='radio'  name='R" + idZ + "' onclick='selectZ(3," + i + "," + iAct + ");' " + check + ">" + Routage[LesActions[iAct].Actif] + "</div>";
            if (LesActions[iAct].Actif <= 1) {
                S += "<div><small>On : &nbsp;</small>Pw &lt;<input id='Pw_min_" + idZ + "'  type='number' value='" + Vmin + "' onchange='NewVal(this)' title='Seuil de puissance pour activer ou désactiver le routage. Attention, en cas de mode On/Off la diff&eacute;rence, seuil sup&eacute;rieur moins  seuil inf&eacute;rieur doit &ecirc;tre sup&eacute;rieure &agrave; la consommation du dipositif pour &eacute;viter l&apos;oscillation du relais de commande.'>W</div>";
                S += "<div><small>Off : </small>Pw &gt;<input id='Pw_max_" + idZ + "'  type='number' value='" + Vmax + "' onchange='NewVal(this)'>W</div>";
                S += "<div><small>Puissance active en entrée de maison</small></div></div>";
            } else {
                S += "<div><small>Seuil Pw : &nbsp;</small><input id='Pw_min_" + idZ + "'  type='number' value='" + Vmin + "' onchange='NewVal(this)' title='Seuil de puissance pour activer ou désactiver le routage.' >W</div>";
                S += "<div><small>Puissance active en entrée de maison</small></div>";
                S += "<div><small>Ouvre Max : </small><input id='Pw_max_" + idZ + "'   type='number' value='" + Vmax + "' onchange='NewVal(this)' title='Ouverture maximum du  SSR. Valeur typique : 100%'>%</div></div>";
            }

        } else {
            var Routage = ["", "Routage Découpe Sinus", "Routage Multi-sinus", "Routage Train de Sinus", "", "Routage Demi-Sinus"];
            S += "<div  class='zTriac' ><div class='radioC' ><input type='radio'  name='R" + idZ + "' onclick='selectZ(4," + i + "," + iAct + ");' " + check + ">" + Routage[LesActions[iAct].Actif] + "</div>";
            S += "<div>Seuil Pw &nbsp;<input id='Pw_min_" + idZ + "'  type='number' value='" + Vmin + "' onchange='NewVal(this)' title='Seuil en W de r&eacute;gulation par le Triac de la puissance mesur&eacute;e Pw en entrée de la maison. Valeur typique : 0.'>W</div>";
            S += "<div><small>Puissance active en entrée de maison</small></div>";
            S += "<div>Ouvre Max <input id='Pw_max_" + idZ + "' type='number' value='" + Vmax + "' onchange='NewVal(this)' title='Ouverture maximum du triac. Valeur typique : 100%'>%</div></div>";
        }
        S += "</div>";
        var SelectT = "<div>Canal de Température <select id='CanalTemp" + idZ + "'  onchange='NewVal(this)'><option value=-1 selected>Non exploité</option>";
        for (var c = 0; c < 4; c++) {
            if (LesTemperatures[c] > -100) {
                var Temper = parseFloat(LesTemperatures[c]).toFixed(1);
                SelectT += "<option value=" + c + " >" + NomTemperatures[c] + " (" + Temper + "°)" + "</option>";
                capteurT = true;
            }
        }
        SelectT += "</select></div>";
        var style = (ModePara == 0) ? "none" : "block";
        style = "style='display:" + style + "';";
        S += "<div>";
        S += "<div class='TitZone' " + style + ">&nbsp;&nbsp;&nbsp;Conditions optionnelles pour activer</div>";
        if (capteurT) {
            S += "<div  class='bord1px' " + style + ">";
            S += SelectT;
            S += "<div class='minmax'><div>T &ge;<input id='T_sup_" + idZ + "'  type='number' value='" + TsupC + "' onchange='NewVal(this)' title='Définir la ou les températures qui permettent l&apos;activation de la fonction On ou Routage.'>°</div>";
            S += "<div>T &le;<input id='T_inf_" + idZ + "'  type='number' value='" + TinfC + "' onchange='NewVal(this)' >°</div></div>";
            S += "<div><small>T en degré (-50.0 à 150.0) ou laisser vide</small></div>";
            S += "</div>";
        }
        S += "<div  class='bord1px' " + style + " >";
        S += "<div>Etat d'une Action <select id='SelAct" + idZ + "' onchange='NewVal(this)' >" + SelectActions + "</select></div>";
        S += "<div class='minmax'><div>Durée : </div><div>H &ge;<input id='H_min_" + idZ + "'  type='text' value='" + Hmin + "' onchange='NewVal(this)' >h:mn</div>";
        S += "<div>H &le;<input id='H_max_" + idZ + "'  type='text' value='" + Hmax + "' onchange='NewVal(this)' >h:mn</div></div>";
        S += "<div class='minmax'><div>Seuil : </div><div>On à Off si &le;<input id='O_min_" + idZ + "'  type='number' value='" + Ooff + "' onchange='NewVal(this)' >%</div>";
        S += "<div>Off à On si &ge;<input id='O_max_" + idZ + "'  type='number' value='" + O_on + "' onchange='NewVal(this)' >%</div></div>";
        S += "<div><small>h:mn ou % ou laisser vide</small></div>";
        S += "</div>";


        if (LTARFbin > 0) {
            S += "<div  class='bord1px' >";
            S += "<div title='Condition d&apos;activation suivant la tarification. Sinon ordre Off envoyé ou Triac/SSR se ferme.'>Actif si tarif :</div>";
            if (LTARFbin <= 3) {
                S += "<div id='PleineCreuse'><span style='color:red;'>Heure Pleine</span><input type='checkbox' checked id='TarifPl_" + idZ + "' onchange='NewVal(this)'> <span style='color:green;'>Heure Creuse</span><input type='checkbox' checked id='TarifCr_" + idZ + "' onchange='NewVal(this)'></div>";
            } else {
                S += "<div id='Tempo'>Tempo <span style='color:blue;'>Bleu</span><input type='checkbox' checked id='TarifBe_" + idZ + "' onchange='NewVal(this)'><span style='color:white;'> Blanc</span><input type='checkbox' checked id='TarifBa_" + idZ + "' onchange='NewVal(this)'><span style='color:red;'> Rouge</span><input type='checkbox' checked id='TarifRo_" + idZ + "' onchange='NewVal(this)'></div>";
            }
            S += "</div>";
        }
        S += "</div>";

        S += "</div>";
        GH(idZ, S);
        if (capteurT) GID("CanalTemp" + idZ).value = LesActions[iAct].Periodes[i].CanalTemp;
        GID("SelAct" + idZ).value = LesActions[iAct].Periodes[i].SelAct;
        var Tarif_ = LesActions[iAct].Periodes[i].Tarif;
        if (LTARFbin > 0) {
            if (LTARFbin <= 3) {
                GID("TarifPl_" + idZ).checked = (Tarif_ & 1) ? 1 : 0; // H Pleine
                GID("TarifCr_" + idZ).checked = (Tarif_ & 2) ? 1 : 0;
            } else {
                GID("TarifBe_" + idZ).checked = (Tarif_ & 4) ? 1 : 0;
                GID("TarifBa_" + idZ).checked = (Tarif_ & 8) ? 1 : 0;
                GID("TarifRo_" + idZ).checked = (Tarif_ & 16) ? 1 : 0; //Rouge
            }
        }
        GID(idZ).style.display = "block";
    }
}

)====";

const char * ActionsJS3 = R"====(
function infoZclose(idx) {
    var champs = idx.split("info");
    var idx = champs[1].split("Z");
    S = "TracePeriodes(" + idx[0] + ");";
    setTimeout(S, 100);
}
function selectZ(T, i, iAct) {
    if (LesActions[iAct].Periodes[i].Type != T) {
        LesActions[iAct].Periodes[i].Type = T;
        var idZ = "info" + iAct + "Z" + i;
        if (T <= 1) {
            infoZclose(idZ);
            TracePeriodes(iAct);
        }
    }
}

function NewVal(t) {
    var champs = t.id.split("info");
    var idx = champs[1].split("Z");   //Num Action, Num période
    if (champs[0].indexOf("Pw_min") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].Vmin = Math.floor(GID(t.id).value);
    }
    if (champs[0].indexOf("Pw_max") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].Vmax = Math.floor(GID(t.id).value);
        if (idx[0] == 0) {
            LesActions[idx[0]].Periodes[idx[1]].Vmax = Math.max(LesActions[idx[0]].Periodes[idx[1]].Vmax, 5);
            LesActions[idx[0]].Periodes[idx[1]].Vmax = Math.min(LesActions[idx[0]].Periodes[idx[1]].Vmax, 100);
        }
    }
    if (champs[0].indexOf("inf") > 0) {
        var V = GID(t.id).value;
        if (V == "") V = 158;
        LesActions[idx[0]].Periodes[idx[1]].Tinf = Math.floor(V * 10);
    }
    if (champs[0].indexOf("sup") > 0) {
        var V = GID(t.id).value;
        if (V == "") V = 158;
        LesActions[idx[0]].Periodes[idx[1]].Tsup = Math.floor(V * 10);
    }
    if (champs[0].indexOf("H_min") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].Hmin = Hmn2Hdeci(GID(t.id).value);
    }
    if (champs[0].indexOf("H_max") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].Hmax = Hmn2Hdeci(GID(t.id).value);
    }
    if (champs[0].indexOf("O_min") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].Ooff = Math.max(0, Math.min(100, Math.floor(GID(t.id).value)));
    }
    if (champs[0].indexOf("O_max") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].O_on = Math.max(0, Math.min(100, Math.floor(GID(t.id).value)));
    }
    if (champs[0].indexOf("Tarif") >= 0) {
        var idZ = "info" + champs[1];
        var Tarif_ = 0;
        if (LTARFbin <= 3) {
            Tarif_ += GID("TarifPl_" + idZ).checked ? 1 : 0; //H pleine
            Tarif_ += GID("TarifCr_" + idZ).checked ? 2 : 0;
        } else {
            Tarif_ += GID("TarifBe_" + idZ).checked ? 4 : 0; //Bleu
            Tarif_ += GID("TarifBa_" + idZ).checked ? 8 : 0;
            Tarif_ += GID("TarifRo_" + idZ).checked ? 16 : 0; //Rouge
        }
        LesActions[idx[0]].Periodes[idx[1]].Tarif = Tarif_;
    }
    if (champs[0].indexOf("CanalTemp") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].CanalTemp = GID(t.id).value;
    }
    if (champs[0].indexOf("SelAct") >= 0) {
        LesActions[idx[0]].Periodes[idx[1]].SelAct = GID(t.id).value;
    }
}


function editTitre(iAct) {
    if (GID("titre" + iAct).innerHTML.indexOf("<input") == -1) {
        GH("titre" + iAct, "<input type='text' value='" + GID("titre" + iAct).innerHTML + "' id='Etitre" + iAct + "'  onblur='TitreValid(" + iAct + ")' >");
        GID("Etitre" + iAct).focus();
    }
}
function TitreValid(iAct) {
    LesActions[iAct].Titre = GID("Etitre" + iAct).value.trim();
    GH("titre" + iAct, LesActions[iAct].Titre);
}
function checkDisabled() {
    GID("sortie0").style.display = "none";
    GID("Freq_PWM").style.display = "none";
    GID("commun").style.display = (ModePara > 0 && ReacCACSI < 100) ? "block" : "none";
    for (var iAct = 0; iAct < LesActions.length; iAct++) {
        for (var i = 0; i <= 5; i++) {
            if (GID("radio" + iAct + "-" + i).checked) { LesActions[iAct].Actif = i; } //0=Inactif,1=Decoupe ou On/Off, 2=Multi, 3= Train, 4= PWM, 5=Demi-Sinus
        }
        if (GID("selectPin" + iAct).value == -1 && LesActions[iAct].Actif > 1 && iAct > 0) { LesActions[iAct].Actif = 1; GID("radio" + iAct + "-" + LesActions[iAct].Actif).checked = true; }
        TracePeriodes(iAct);
        GID("planning0").style.display = (pTriac > 0) ? "block" : "none";  // Si Pas de Triac
        GID("TitrTriac").style.display = (pTriac > 0) ? "block" : "none";
        GID("blocPlanning" + iAct).style.display = (LesActions[iAct].Actif > 0) ? "block" : "none";
        GID("visu" + iAct).style.display = (LesActions[iAct].Actif > 0) ? "block" : "none";
        if (LesActions[iAct].Actif == 1 && iAct>0){
             GID('graphAction' + iAct).style.display ="none";
             GID("visu" + iAct).style.display ="none";
        }
        var visible = (LesActions[iAct].Actif == 1) ? "block" : "none";
        GID("Tempo" + iAct).style.display = visible;
        var disable = true;
        var disp = "block";
        if (GID("selectPin" + iAct).value >= 0) { visible = "none"; disable = false; disp = "none"; }
        GID("SelectOut" + iAct).style.display = (GID("selectPin" + iAct).value <= 0) ? "none" : "inline-block";
        GID("Host" + iAct).style.display = visible;
        GID("Port" + iAct).style.display = visible;
        GID("Repet" + iAct).style.display = visible;
        GID("radio" + iAct + "-2").disabled = disable;
        GID("radio" + iAct + "-3").disabled = disable;
        GID("radio" + iAct + "-4").disabled = disable;
        GID("radio" + iAct + "-5").disabled = disable;
        GID("ordreoff" + iAct).style.display = disp;
        GID("ordreon" + iAct).style.display = disp;
        if (GID("selectPin" + iAct).value == -1 && GID("ordreOn" + iAct).value.indexOf(IS) > 0) GID("ordreOn" + iAct).value = "";
        GID("ligne_bas" + iAct).style.display = (LesActions[iAct].Actif == 1 && GID("selectPin" + iAct).value <= 0 && iAct > 0) ? "flex" : "none";
        GID("fen_slide" + iAct).style.display = (LesActions[iAct].Actif == 1 && iAct > 0) ? "none" : "table";
        if (GID("radio" + iAct + "-4").checked) {
            GID("Freq_PWM").style.display = "block";
            GID("commun").style.display = "block";
        }
        if (ModePara == 0) {
            GID("PID" + iAct).checked = false;
        }
        GID("PIDbox" + iAct).style.display = (ModePara == 0 || (GID("selectPin" + iAct).value <= 0 && iAct > 0) || (LesActions[iAct].Actif == 1 && iAct > 0)) ? "none" : "block";
        GID("Propor" + iAct).style.display = (GID("PID" + iAct).checked) ? "table-row" : "none";
        GID("Derive" + iAct).style.display = (GID("PID" + iAct).checked) ? "table-row" : "none";

    }
    GID("Pwm0").style.display = "none"; //Pas de PWM sur la sortie Triac
}

function LoadActions() {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            var LeRetour = this.responseText;
            var Les_ACTIONS = LeRetour.split(GS);
            var LesParas = Les_ACTIONS[0].split(RS);
            LesTemperatures = LesParas[0].split("|");
            NomTemperatures = LesParas[1].split(US);
            LTARFbin = parseInt(LesParas[2]);
            pTriac = parseInt(LesParas[3]);
            ReacCACSI = LesParas[4]; //1,24 8 ou 100 pour EstimCACSI
            if (ReacCACSI < 100) {
                GID("CACSI" + ReacCACSI).checked = true; //Reactivité Ki CACSI et non Estimation
                GID("CACSI").style = "display:block;";
            }
            GID("Fpwm" + LesParas[5]).checked = true;
            LesActions.splice(0, LesActions.length);
            for (var iAct = 1; iAct < Les_ACTIONS.length - 1; iAct++) {
                var champs = Les_ACTIONS[iAct].split(RS);
                var NbPeriodes = champs[12];
                var Periodes = [];
                var j = 13;
                for (var i = 0; i < NbPeriodes; i++) {
                    Periodes[i] = { Type: champs[j], Hfin: champs[j + 1], Vmin: champs[j + 2], Vmax: champs[j + 3], Tinf: champs[j + 4], Tsup: champs[j + 5], Hmin: champs[j + 6], Hmax: champs[j + 7], CanalTemp: champs[j + 8], SelAct: champs[j + 9], Ooff: champs[j + 10], O_on: champs[j + 11], Tarif: champs[j + 12] };
                    j = j + 13;
                }
                LesActions[iAct - 1] = creerAction(champs[0], champs[1], champs[2], champs[3], champs[4], champs[5], champs[6], champs[7], champs[8], champs[9], champs[10], champs[11], Periodes);
            }
            if (LesActions.length == 0) {  //Action Triac
                LesActions.push(creerAction(0, "Titre Triac", "", 50, "", "", "", 0, 10, 10, 10, 0, [{
                    Hfin: 2400,
                    Type: 4,
                    Vmin: 0,
                    Vmax: 100,
                    Tinf: 1600,
                    Tsup: 1600,
                    Hmin: 0,
                    Hmax: 0,
                    CanalTemp: -1,
                    SelAct: 255,
                    Ooff: 0,
                    O_on: 0,
                    Tarif: 31
                }
                ]));
            }
            LesActions.push(creerAction(0, "Titre Relais " + LesActions.length, "", 80, "", "", 240, 0, 10, 10, 10, 0, [{
                Hfin: 2400,
                Type: 3,
                Vmin: 0,
                Vmax: 100,
                Tinf: 1600,
                Tsup: 1600,
                Hmin: 0,
                Hmax: 0,
                CanalTemp: -1,
                SelAct: 255,
                Ooff: 0,
                O_on: 0,
                Tarif: 31
            }
            ]));
            var S = "";
            for (var i = 1; i < LesActions.length; i++) {
                S += "<div id='planning" + i + "' class='planning' ></div>";
            }
            let imax = LesActions.length - 1;

            S += "<input id='butR' type='button'  class='tbut' value='+' onclick='this.style.display=\"none\";GID(\"planning" + imax + "\").style.display=\"block\";' title='Rajouter un relais d&apos;action.'>";
            GH("plannings", S);
            GID("planning" + imax).style.display = "none";
            for (var iAct = 0; iAct < LesActions.length; iAct++) {
                TracePlanning(iAct);
            }
            checkDisabled();
            LoadParaRouteur();
        }
    };
    xhttp.open('GET', '/ActionsAjax', true);
    xhttp.send();
}
function UpdateK(iAct) {
    if (PlotIdx >= 0) { //envoi direct des coef si on visualise en temps réel la régulation. Ils ne sont pas enregistrés.
        let Kp = Math.floor(GID("sliderKp" + iAct).value);
        let Ki = Math.floor(GID("sliderKi" + iAct).value);
        let Kd = Math.floor(GID("sliderKd" + iAct).value);

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                var retour = this.responseText;
            }
        };
        xhttp.open('GET', '/UpdateK?iAct=' + iAct + '&Kp=' + Kp + '&Ki=' + Ki + '&Kd=' + Kd, true);
        xhttp.send();
    }

}
)====";

const char * ActionsJS4 = R"====(
function SendValues() {
    GID("attente").style = "visibility: visible;";
    for (var iAct = 0; iAct < LesActions.length; iAct++) {
        for (var i = 0; i <= 4; i++) {
            if (GID("radio" + iAct + "-" + i).checked) { LesActions[iAct].Actif = i; }
        }
        LesActions[iAct].Titre = GID("titre" + iAct).innerHTML.trim();
        LesActions[iAct].Host = GID("host" + iAct).value.trim();
        LesActions[iAct].Port = GID("port" + iAct).value;
        LesActions[iAct].OrdreOn = GID("ordreOn" + iAct).value.trim();
        LesActions[iAct].OrdreOff = GID("ordreOff" + iAct).value.trim();
        LesActions[iAct].Repet = GID("repet" + iAct).value;
        LesActions[iAct].Tempo = GID("tempo" + iAct).value;
        LesActions[iAct].Kp = GID("sliderKp" + iAct).value;
        LesActions[iAct].Ki = GID("sliderKi" + iAct).value;
        LesActions[iAct].Kd = GID("sliderKd" + iAct).value;
        LesActions[iAct].PID = GID("PID" + iAct).checked ? 1 : 0;
        if (GID("selectPin" + iAct).value >= 0) LesActions[iAct].OrdreOn = GID("selectPin" + iAct).value + IS + GID("selectOut" + iAct).value;
        if (iAct > 0 && (GID("selectPin" + iAct).value == 0 || LesActions[iAct].Titre == "")) LesActions[iAct].Actif = -1; //Action à effacer
    }
    var S = "";
    for (var iAct = 0; iAct < LesActions.length; iAct++) {
        if (LesActions[iAct].Actif >= 0) {
            S += LesActions[iAct].Actif + RS + LesActions[iAct].Titre + RS;
            S += LesActions[iAct].Host + RS + LesActions[iAct].Port + RS;
            S += LesActions[iAct].OrdreOn + RS + LesActions[iAct].OrdreOff + RS + LesActions[iAct].Repet + RS + LesActions[iAct].Tempo + RS;
            S += LesActions[iAct].Kp + RS + LesActions[iAct].Ki + RS + LesActions[iAct].Kd + RS + LesActions[iAct].PID + RS + LesActions[iAct].Periodes.length + RS;
            for (var i = 0; i < LesActions[iAct].Periodes.length; i++) {
                if (ModePara == 0) { //Standard
                    LesActions[iAct].Periodes[i].CanalTemp = -1;
                    LesActions[iAct].Periodes[i].SelAct = 255;
                }
                S += LesActions[iAct].Periodes[i].Type + RS + Math.floor(LesActions[iAct].Periodes[i].Hfin) + RS;
                S += Math.floor(LesActions[iAct].Periodes[i].Vmin) + RS + Math.floor(LesActions[iAct].Periodes[i].Vmax) + RS;
                S += Math.floor(LesActions[iAct].Periodes[i].Tinf) + RS + Math.floor(LesActions[iAct].Periodes[i].Tsup) + RS;
                S += Math.floor(LesActions[iAct].Periodes[i].Hmin) + RS + Math.floor(LesActions[iAct].Periodes[i].Hmax) + RS;
                S += Math.floor(LesActions[iAct].Periodes[i].CanalTemp) + RS + Math.floor(LesActions[iAct].Periodes[i].SelAct) + RS;
                S += Math.floor(LesActions[iAct].Periodes[i].Ooff) + RS + Math.floor(LesActions[iAct].Periodes[i].O_on) + RS;
                S += LesActions[iAct].Periodes[i].Tarif + RS;
            }
            S += GS;
        }
    }
    if (ReacCACSI < 100) ReacCACSI = document.querySelector('input[name="ReacCACSI"]:checked').value; //Pas d'estimation
    var Fpwm = document.querySelector('input[name="Fpwm"]:checked').value;
    S = encodeURIComponent(S);
    S = "?ReacCACSI=" + ReacCACSI + "&Fpwm=" + Fpwm + "&actions=" + S + "|"; //On ne peut pas terminer par GS

    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            var retour = this.responseText;
            location.reload();
        }
    };
    xhttp.open('GET', '/ActionsUpdate' + S, true);
    xhttp.send();

}
function Plot(iAct) {
    for (i = 0; i < LesActions.length; i++) {
        GID('graphAction' + i).style.display = "none";
    }
    if (PlotIdx != iAct) {
        PlotIdx = iAct;
        GID('graphAction' + iAct).style.display = "block";
        PlotR(iAct);
    } else {
        PlotIdx = -1;
    }


}
function PlotR(iAct) { // Courbes détaillées PID
    if (PlotIdx >= 0) {
        if (!Pause) {
            TabIdx = (TabIdx + 1) % 150;
            Ecart[TabIdx] = parseInt(MesuresPwAct[0]);
            Prop[TabIdx] = parseFloat(MesuresPwAct[1]);
            Integ[TabIdx] = parseFloat(MesuresPwAct[2]);
            Deriv[TabIdx] = parseFloat(MesuresPwAct[3]);
            let retard = Prop[TabIdx] + Integ[TabIdx] + Deriv[TabIdx];
            Retard[TabIdx] = Math.floor(Math.max(Math.min(100, retard), 0));
            Ouvert[TabIdx] = 100 - Retard[TabIdx];
            var cW = "#" + Koul[Coul_W][3];
            var cOuvre = "#" + Koul[Coul_Ouvre][3];
            var cRetard = "#" + Koul[Coul_VA][3];
            var cT = "#" + Koul[Coul_Graphe][1];
            var cP = "#" + Koul[Coul_Temp][3];
            var cI = "#" + Koul[Coul_Temp + 1][3];
            var cD = "#" + Koul[Coul_Temp + 3][3];
            var style = 'background:linear-gradient(#' + Koul[Coul_Graphe][5] + ',#' + Koul[Coul_Graphe][3] + ',#' + Koul[Coul_Graphe][5] + ');border-color:#' + Koul[Coul_Tab][5] + ';';
            var S = "<svg viewbox='0 0 970 240' style='" + style + "' height='240'  >"; //  
            S += "<line x1='50' y1='20' x2='50' y2='220' style='stroke:" + cW + ";stroke-width:2' />";
            S += "<line x1='800' y1='20' x2='800' y2='220' style='stroke:" + cOuvre + ";stroke-width:2' />";
            S += "<line x1='50' y1='220' x2='800' y2='220' style='stroke:" + cT + ";stroke-width:2' />";
            for (var t = 0; t < 75; t = t + 5) {
                let x = 800 - t * 10;
                S += "<text x='" + x + "' y='237' style='font-size:16px;fill:" + cT + ";'>" + t + "</text>";
                S += "<line x1='" + x + "' y1='220' x2='" + x + "' y2='224' style='stroke:" + cT + ";stroke-width:2' />";
            }
            S += "<text x='790' y='218' style='font-size:12px;fill:" + cT + ";'>s</text>";
            S += "<text x='804' y='220' style='font-size:12px;fill:" + cOuvre + ";'>0%</text>";
            S += "<text x='804' y='20' style='font-size:12px;fill:" + cOuvre + ";'>100%</text>";
            S += "<line x1='50' y1='20' x2='800' y2='20' style='stroke:" + cOuvre + ";stroke-width:2' stroke-dasharray='1 4' />";
            S += "<line x1='50' y1='120' x2='800' y2='120' style='stroke:" + cW + ";stroke-width:2' stroke-dasharray='1 4' />";
            S += "<text x='20' y='120' style='font-size:12px;fill:" + cW + ";'>0 W</text>";
            S += "<text x='5' y='20' style='font-size:12px;fill:" + cW + ";'>100 W</text>";
            S += "<text x='1' y='220' style='font-size:12px;fill:" + cW + ";'>-100 W</text>";


            S += "<text x='830' y='40' style='font-size:16px;fill:" + cW + ";'>Ecart..........." + Ecart[TabIdx] + " W</text>";
            S += "<text x='830' y='60' style='font-size:16px;fill:" + cOuvre + ";'>Ouverture....." + Ouvert[TabIdx] + " %</text>";
            S += "<text x='860' y='76' style='font-size:12px;fill:" + cT + ";'>= 100 - Retard</text>";
            S += "<text x='830' y='96' style='font-size:16px;fill:" + cRetard + ";'>Retard........." + Retard[TabIdx] + " %</text>";           
            S += "<text x='830' y='168' style='font-size:16px;fill:" + cI + ";'>Intégral....." + Integ[TabIdx] + "</text>";
           
            if (ModePara == 1 && GID("PID" + iAct).checked ){
                S += "<text x='860' y='112' style='font-size:12px;fill:" + cT + ";'>=</text>";
                S += "<text x='830' y='132' style='font-size:16px;fill:" + cP + ";'>Proportion.." + Prop[TabIdx] + "</text>";
                S += "<text x='860' y='148' style='font-size:12px;fill:" + cT + ";'>+</text>";
                S += "<text x='860' y='184' style='font-size:12px;fill:" + cT + ";'>+</text>";
                S += "<text x='830' y='204' style='font-size:16px;fill:" + cD + ";'>Dérivée........" + Deriv[TabIdx] + "</text>";
            }

            let SE = "<polyline points='";
            let SO = "<polyline points='";
            let SR = "<polyline points='";
            let SP = "<polyline points='";
            let SI = "<polyline points='";
            let SD = "<polyline points='";
            for (let i = 0; i < 150; i++) { //toutes les 0.5s
                let j = (TabIdx - i + 150) % 150;
                let x = 800 - i * 5;
                let y = 120 - Ecart[j];
                y = Math.min(y, 220); y = Math.max(y, 20);
                SE += x + "," + y + " ";
                y = 220 - 2 * Ouvert[j];
                SO += x + "," + y + " ";
                y = 220 - 2 * Retard[j];
                SR += x + "," + y + " ";
                y = 120 - Prop[j];
                y = Math.min(y, 220); y = Math.max(y, 20);
                SP += x + "," + y + " ";
                y = 220 - 2 * Integ[j];
                SI += x + "," + y + " ";
                y = 120 - Deriv[j];
                y = Math.min(y, 220); y = Math.max(y, 20);
                SD += x + "," + y + " ";
            }
            SE += "' style='fill:none;stroke:" + cW + ";stroke-width:2' />";
            SO += "' style='fill:none;stroke:" + cOuvre + ";stroke-width:2' />";
            SR += "' style='fill:none;stroke:" + cRetard + ";stroke-width:2' />";
            SP += "' style='fill:none;stroke:" + cP + ";stroke-width:2' />";
            SI += "' style='fill:none;stroke:" + cI + ";stroke-width:2' />";
            SD += "' style='fill:none;stroke:" + cD + ";stroke-width:2' />";
             if (ModePara == 1 && GID("PID" + iAct).checked){
                    S += SD  + SP;
             }
            S +=  SI  + SR + SO + SE + "</svg>";
            GID('graphSVG' + iAct).innerHTML = S;

        }
        let P = "PlotR(" + iAct + ");"
        setTimeout(P, 500);
    }
}

function ShowAction() {
    let Dt = 200; //ms
    if (PlotIdx >= 0) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                var retour = this.responseText;
                MesuresPwAct.length = 0;
                MesuresPwAct = retour.split(RS);

            }
        };
        xhttp.open('GET', '/ShowAction?NumAction=' + PlotIdx, true);
        xhttp.send();
    } else {
        for (var i = 0; i < 4; i++) {
            MesuresPwAct[i] = 0;
        }
        for (var i = 0; i < 150; i++) {
            Ecart[i] = 0;
            Ouvert[i] = 0;
            Retard[i] = 0;
            Prop[i] = 0;
            Integ[i] = 0;
            Deriv[i] = 0;
        }
        Dt = 2000;
    }
    setTimeout("ShowAction();", Dt);
}

function FinParaRouteur() {
    SelectActions = "<option value=255>Non exploité</option>";
    for (esp = 0; esp < nomRMS.length; esp++) { //Liste des actions par routeur
        for (var iAct = 0; iAct < nomActions[esp].length; iAct++) {
            var v = esp * 10 + parseInt(nomActions[esp][iAct][0]); //Nombre refletant la référence esp et action
            var T = (esp == 0) ? "" : nomRMS[esp] + " / ";
            SelectActions += "<option value=" + v + ">" + T + nomActions[esp][iAct][1] + "</option>";
            ListeActions[v] = T + nomActions[esp][iAct][1];
        }
    }
    for (var iAct = 0; iAct < LesActions.length; iAct++) {
        GID("PID" + iAct).checked = LesActions[iAct].PID == 1 ? true : false;
    }
    checkDisabled();
}



function AdaptationSource() {

}
)====";

Imprimer cet élément

  perte connexion a la passerelle Envoy suite a passage a version 16.09
Posté par : Jessidy - 21-01-2026, 04:56 PM - Forum : Routeur Photovoltaïque - Réponses (1)

Bonjour a tous,
j'utilise avec bonheur ce routeur solaire depuis la version V8.06, en utilisant ma passerelle Enphase - Envoy comme capteur de mesure de puissance. Tout s'était parfaitement bien passe jusqu'a present (installation - configuration - utilisation) grace a ce site et au Forum.

Merci a André pour ce travail remarquable d'efficacité, et a vous tous pour vos questions / réponses qui m'ont souvent été d'une aide précieuse.

une panne récente (qui s'est révélée être un faux contact), m'a amené a évoluer dimanche dernier vers la version 15.08 (j'en ai profité), car il semblait que cette version était tres stable. Apres quelques difficultés avec le wifi, tout est rentre dans l'ordre :

mes 2 routeurs en réseau (un principal proche du tableau électrique et dont le Triac est connecte a mon cumulus, et un secondaire, sur le cumulus, possédant une sonde de temperature ds18b20) communiquent parfaitement

la connexion a la passerelle enphase se faisait sans problème, et les mesures de puissance / consommation remontaient bien au routeur RMS, permettant l'envoi du surplus solaire vers le cumulus.

mes 2 routeurs ainsi que la passerelle ont des IP fixes déclarées sur dans Livebox.

Ce matin, pas de routage solaire et les donnees maison (venant de la passerelle Enphase) etaient toutes a zero. pas de puissance ni de consommation.

je suis passé a la version 16.09, sans succes.

lorsque je regarde les logs du routeur principal, j'obtiens le message suivant :

"21/01/2026 15:44:59 : connection to client clientFirmV5 failed (call to Envoy-S)
21/01/2026 15:45:59 : connection to client clientFirmV5 failed (call to Envoy-S)
21/01/2026 15:46:05 : connection to client clientFirmV5 failed (call to Envoy-S)
21/01/2026 15:46:59 : connection to client clientFirmV5 failed (call to Envoy-S)
Note échanges entre routeurs
Routeur - DS18b20 (192.168.1.47)"

La connexion entre le routeur et la passerelle ne se fait donc plus.

le firmware de ma passerelle est en D8.3.5167

pour resumer :

routeur RMS V16.09 + Envoy D8.3.5167
Log: "connection to client clientFirmV5 failed"
IP stable 192.168.1.53, WiFi -27dBm

j'ai réussi jusqu'a aujourd'hui a surmonter toutes les difficultés, mais là, je sèche ...

quelqu'un a t il une idée d'ou vient le problème ?

Imprimer cet élément

  adaptation pour certains sujets
Posté par : laprobert - 21-01-2026, 03:03 PM - Forum : Evolutions faites, à faire, dont vous rêvez... - Réponses (3)

Bonjour André,

Ce mot a pour but de proposer, si vous le jugez utile, une adaptation pour certains sujets.

1- Routeur photovoltaïque via Ethernet
1-1_ Vous nous avez aidé en écrivant :"esp_wps.h fait partie de la bibliothèque qui gère l'ESP32 que vous définissez dans les préférences/paramètre de l'IDE Arduino. Il faut la V3.3.1"
1-2_ l’ESP32_ETH01 : connecté sur un câble RJ45 en POE ne fonctionne pas.

2- Affichage à distance consommation ou surproduction électrique
Problème : Carte Lilygo Affichage à distance toujours allumée.
Les détecteurs IR que j’ai sont ceux référencés par André dans sont article « f1atb.fr/fr/affichage-a-distance-consommation-ou-surproduction-electrique/ » : Module de détection automatique capteur AM312 DC 2.7 à 12V.
Jaques13 a fait la remarque : « Le module PIR HC-SR505 a aussi une résistance en sortie mais de 2K , ce qui change complètement la donne »
J’avais alors refait des mesures et écrit : « A l'attention de André@F1ATB et Jacques13,
Pour clôturer cet échange j'ai rechargé le programme sur le Display avec Le INPUT_PULLUP. J'ai fait des mesures de tension sur le GPIO 33 avec le Module de détection automatique capteur AM312 DC 2.7 à 12V.
Lors des détections de présence du capteur PIR: 3V
Sans détection : 1.35V
Cela confirme bien l'évaluation de Jacques13. « 

Cordialement.

Imprimer cet élément

  installation impossible programme F1tab dans eps32 avec ethernet
Posté par : Caboyot - 21-01-2026, 01:46 PM - Forum : Routeur Photovoltaïque - Réponses (4)

Bonjour, 
Je tente d'installer le programme f1atb dans un Esp32 ethernet.
Le message d'erreur "installation failed" cf photo PJ s'affiche après 30s.
Une idée du problème?
Je précise que le ftdi232 est bien configurer en 3v, et qu'une mise à la masse avant le premier allumage des pins gnd/IOo a bien été respecté.
Merci à vous pour votre aide



Pièces jointes Miniature(s)
       
Imprimer cet élément

  Comment j'ai réglé mon PID
Posté par : Yves911 - 20-01-2026, 08:16 PM - Forum : Routeur Photovoltaïque - Réponses (2)

Hello,

Voici ma config :
- 1 shelly Gen3
- 1 Chauffe eau de 300L 3KW/h
- 1 Routeur avec SSR
- 3 Kwc de panneaux solaire orienté sud
- 1 Home Assistant.

SSR en mode Dem-sinus
Coef. proportionnel : 3
Coef. Intégral ou Réactivité : 45
Coef. Dérivé : 0

J'ai réussi à trouver ces valeurs grâce à Gemini.
Je lui ai passé les graphiques disponibles via le bouton permettant de voir la régulation en temps réel.
A force d'aller et retour ça a fini par stabiliser mes courbes => bluffant je pense que le faire moi-même par essai successifs m'aurait pris beaucoup plus de temps...

Au passage un petit lien fort intéressant : https://www.youtube.com/watch?v=aRaMj-SGA0Q

Exemple de réponse durant le process de réglage :
On voit une amélioration nette dans la stabilité des courbes turquoise (Retard) et verte (Proportion), qui sont maintenant beaucoup plus horizontales. 
Cependant, la courbe rouge (Ecart) continue de faire des aller-retours brutaux entre +100W et -100W.

Cela indique que votre système est encore trop "nerveux". Pour obtenir une ligne rouge plate proche de 0W, vous devez réduire l'influence de la correction immédiate.
Voici la prochaine étape pour stabiliser l'ensemble :
1. Baisser encore le Coef. Proportionnel
Le système réagit encore trop violemment à la moindre variation.

  • Action : Passez le Coef. Proportionnel de 8 à 4.
  • Objectif : Réduire l'amplitude des pics rouges pour qu'ils ne touchent plus les bords haut et bas du graphique.
2. Augmenter le Coef. Intégral (Réactivité)
C'est ce coefficient qui va "lisser" l'erreur sur la durée. On peut lui donner plus de poids maintenant que le système est moins brutal.
  • Action : Passez le Coef. Intégral de 15 à 30.
  • Objectif : Forcer la courbe rouge à converger lentement mais sûrement vers la ligne centrale (0W).
3. Garder le Coef. Dérivé à 0
Le réglage actuel à 0 est correct car votre système oscille déjà sans lui.

Je profite de ce message pour te remercier André pour ton travail et le support fourni à la communauté !

Cheers
Yves

Imprimer cet élément

  Bug passage V16.10
Posté par : jph64 - 19-01-2026, 06:17 PM - Forum : Evolutions faites, à faire, dont vous rêvez... - Réponses (13)

Bonjour à tous, et meilleurs vœux. Je viens de passer de la versionV13 à la version V16.10 avec quelques difficultés mais ça y est j'arrive à me connecter à mon esp32.
par contre je n'ai aucune données de mon Linky qui remonte. Tout d'abord je n'ai pas d'heure qui remonte que ce soit par le Linky ou autres. Après j'ai esp32 classique alors je pense que le choix dans modèle de carte est Wroom. Ensuite j'ai contrôlé mon câblage venant du Linky (+3.3, Gpio26, Gnd) sur les nouveaux paramètre (port série 2) j'ai coché Rx Gpio26 TX Gpio27.
Apres dans données brut j'ai ( Attente Linky 4000 boucles = 8s)
Des pistes? 
Un grand merci

Imprimer cet élément

  Plus de connexion Remote SDR
Posté par : F5llx - 19-01-2026, 04:04 PM - Forum : Remote SDR (Fr) - Réponses (3)

Bonjour, 
Depuis ce matin, je n'arrive plus à me connecter sur mon remote  SDR. 
Le Rpi répond bien au ping, mais l'accès sur cette adresse avec Chrome me renvoie connexion refused. Essai fait sur 2 PC différents. 
J'ai connecté un écran sur le Rpi et tout semble fonctionner. 
Puis je tester en local sur le RPi ? 
Je  ne sais pas comment. 
Y a t il un diagnostic que je pourrais faire en local ? 
Merci de votre aide. 
73
Pascal 
F5LLX

Imprimer cet élément

  Plantage interface
Posté par : Philkeeper - 19-01-2026, 12:42 PM - Forum : Routeur Photovoltaïque - Réponses (3)

Bonjour,

J'utilise le RMS v13.03 depuis plusieurs années, sans problème nickel !

depuis une semaine j'ai activé le MQTT pour récupérer les données sur Home Assistant, et depuis l'interface plate au bout de quelques heures, cependant les données sont bien envoyer.

j'ai configurer les paramètres pour envoyer les données chaque seconde, et j'ai crée un nouveau utilisateur dans Home Assistant en mode local.

Ma question :-) est-ce que c'est un problème connu et je vais devoir faire la mise a jour du RMS ?

Merci pour votre aide !

Imprimer cet élément


Utilisateurs en ligne
Il y a actuellement 588 utilisateurs connectés. » 6 Membre(s) | 580 Visiteur(s)
Bing, Google, F1ATB, g60fr, Genish, jbmur, SC2024

Moteur MyBB, © 2002-2026 Melroy van den Berg.