Widget Html VR Vélux ne s'actualise pas à l'ouverture du dashboard

Bonjour à tous,

J’ai 5 VR Velux filaires câblés sur 2 X-8R, et c’est géré sur IPX800 V5.
J’ai cherché à réaliser des widgets html adaptés sur dashboard (Liveview, c’est pour plus tard). J’ai démarré avec beaucoup d’infos issues du forum, mais mes connaissances étant très faibles pour coordonner et adapter tout ça, j’ai utilisé ChatGpt.
Ces widgets (pour l’instant il y en a 2) sont opérationnels, à un détail près: Au moment où j’ouvre le dashboard, l’animation graphique est systématiquement à l’état 100% fermé (son état d’origine) quel que soit la position du VR (compteur) à cet instant.
Le simple fait d’avancer ou de reculer d’un pas le compteur qui l’alimente l’actualise correctement. Mais j’aimerais évidement que ça se fasse tout seul à l’ouverture du dashboard. (Pour ça, ChatGpt n’a pas su m’aider.) Est-ce possible à votre avis?

Je voulais insérer le code du widget dans ma demande mais je n’y arrive pas. Indiquez-moi comment procéder s.v.p. si besoin.

Bonjour,
faites vous l’appel de la fonction init par un setTimeout ?

ChatGPT :thinking: :roll_eyes: ne connait pas les particularités de l’ipx800 v5, ni son API Widget HTML.
Partager votre code nous permettrait effectivement de vous aider.
Dans le menu au dessus de l’éditeur de message, utilisez </>

Bonjour fgtoul,
Merci pour cette réponse rapide.
Je ne sais pratiquement rien en codage. Je ne fais pratiquement que du copier/coller, j’ajuste les id et j’arrive à jouer sur la position des éléments graphiques et quelques autres bricoles, mais c’est tout à mon grand désespoir. Pour le reste, c’est essentiellement le forum, merci à tous les contributeurs au passage, et pour ce cas ChatGpt. Bref, je « bricole », mais j’aime ça.
Du coup, vous comprendrez que je sois en difficulté pour répondre à votre première question.

En revanche avec votre petit coup de pouce, voici le code:

<html>
<head>
  <meta charset="utf-8"/>
  <style>
    html, body { margin: 0; padding: 0; }

    .widget-wrapper {
      width: 100%;
      height: 100%;
      position: relative;
      background: transparent;
      --graph-w: 90px;
      --graph-h: 78px;
      --gap: 10px;
    }

    .stage { position: absolute; inset: 0; }

    .volet-frame {
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      width: var(--graph-w);
      height: var(--graph-h);
      background: white;
      clip-path: polygon(50% 0%, 100% 0%, 75% 100%, 25% 100%);
      overflow: hidden;
      padding: 2px;
      box-sizing: border-box;
    }

    .volet-body {
      width: 100%;
      height: 100%;
      background: #222;
      clip-path: polygon(50% 0%, 100% 0%, 75% 100%, 25% 100%);
      position: relative;
      overflow: hidden;
      z-index: 1;
    }

    .volet-body::before {
      content: "";
      position: absolute;
      inset: 0;
      background-image: linear-gradient(
        to bottom,
        transparent 90%,
        white 90%,
        white 100%
      );
      background-size: 100% calc(100% / 9);
      background-repeat: repeat-y;
      pointer-events: none;
      z-index: 2;
      opacity: 0.95;
    }

    .volet-mask {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 0;
      background: white;
      z-index: 3;
      transition: height 0.25s ease;
      pointer-events: none;
    }

    .volet-buttons {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      left: calc(var(--graph-w) + var(--gap));
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 2px;
    }

    .volet-button {
      width: 40px;
      height: 40px;
      border: none;
      background: transparent;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
    }

    .volet-button svg { width: 24px; height: 24px; fill: white; }
    .volet-button:hover svg { fill: #bbb; }

    .volet-label {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 2px;
      text-align: center;
      font-size: 16.5px;
      color: white;
      pointer-events: none;
    }
  </style>

  <script>
    function updateVolet1Level(value) {
      const pct = Math.max(0, Math.min(100, Number(value)));
      const body = document.getElementById('volet1-body');
      if (!body) return;

      const h = body.offsetHeight;
      if (h === 0) {
        setTimeout(() => updateVolet1Level(value), 100);
        return;
      }

      const maskHeight = (100 - pct) / 100 * h;
      const mask = document.getElementById('volet1-mask');
      if (mask) mask.style.height = maskHeight + 'px';
    }

    window.GCE_Refresh.push(function(data) {
      if (data && data['_id'] === 327692) {
        updateVolet1Level(data.value);
      }
    });

    function initVolet1(){
      if (typeof GCE_API !== 'undefined' && GCE_API.getIO) {
        GCE_API.getIO(327692).then(ret => {
          updateVolet1Level(ret.value);
        });
      }
    }
    window.addEventListener('load', initVolet1);
  </script>
</head>

<body>
  <div class="widget-wrapper">
    <div class="stage">
      <!-- Graphisme du volet -->
      <div class="volet-frame">
        <div id="volet1-body" class="volet-body">
          <div id="volet1-mask" class="volet-mask"></div>
        </div>
      </div>

      <!-- Boutons -->
      <div class="volet-buttons">
        <button class="volet-button" onclick="GCE_API.putIO(65539, true)">
          <svg viewBox="0 0 100 100"><polygon points="50,10 90,90 10,90"/></svg>
        </button>
        <button class="volet-button" onclick="GCE_API.putIO(65539,false);GCE_API.putIO(65538,false);">
          <svg viewBox="0 0 100 100"><rect x="20" y="20" width="60" height="60"/></svg>
        </button>
        <button class="volet-button" onclick="GCE_API.putIO(65538, true)">
          <svg viewBox="0 0 100 100"><polygon points="10,10 90,10 50,90"/></svg>
        </button>
      </div>

      <div class="volet-label">RL3 & RL4 Ipx</div>
    </div>
  </div>
</body>
</html>

J’ai besoin de comprendre le fonctionnement.
65538 et 65539 correspondent aux IO cmd de relais 3 et relais 4. Vous avez lié un objet clignotant au statut de ces relais qui incrémente ou décrémente un compteur, c’est ça ?
327692 c’est la valeur du compteur ?

GPT mélange le code API entre IO et ANA. Les commandes API et surtout les réponses Json ne sont pas les mêmes. On ne peut pas avoir getIO avec une réponse json qui contient ‹ data.value ›
Si 327692 est la valeur du compteur (donc Ana32), il faut utiliser getANA mais j’ai pris l’habitude d’utiliser GCE_API.get('api/core/ana/id') à la place à cause des dysfonctionnements.
Voir la doc API HTML Widget pour plus d’info.

Oui c’est exactement ce fonctionnement pour les 3 IO que vous avez repérés.

voici un code fonctionnel:

  <style>
    .widget-wrapper {
      width: 100%;
      height: 100%;
      position: relative;
      background: transparent;
      --graph-w: 90px;
      --graph-h: 78px;
      --gap: 10px;
    }

    .stage { position: absolute; inset: 0; }

    .volet-frame {
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      width: var(--graph-w);
      height: var(--graph-h);
      background: white;
      clip-path: polygon(50% 0%, 100% 0%, 75% 100%, 25% 100%);
      overflow: hidden;
      padding: 2px;
      box-sizing: border-box;
    }

    .volet-body {
      width: 100%;
      height: 100%;
      background: #222;
      clip-path: polygon(50% 0%, 100% 0%, 75% 100%, 25% 100%);
      position: relative;
      overflow: hidden;
      z-index: 1;
    }

    .volet-body::before {
      content: "";
      position: absolute;
      inset: 0;
      background-image: linear-gradient(
        to bottom,
        transparent 90%,
        white 90%,
        white 100%
      );
      background-size: 100% calc(100% / 9);
      background-repeat: repeat-y;
      pointer-events: none;
      z-index: 2;
      opacity: 0.95;
    }

    .volet-mask {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 0;
      background: white;
      z-index: 3;
      transition: height 0.25s ease;
      pointer-events: none;
    }

    .volet-buttons {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      left: calc(var(--graph-w) + var(--gap));
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 2px;
    }

    .volet-button {
      width: 40px;
      height: 40px;
      border: none;
      background: transparent;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
    }

    .volet-button svg { width: 24px; height: 24px; fill: white; }
    .volet-button:hover svg { fill: #bbb; }

    .volet-label {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 2px;
      text-align: center;
      font-size: 16.5px;
      color: white;
      pointer-events: none;
    }
  </style>

  <script>
    window.GCE_Refresh.push(function(data) {
       switch (data['_id']){
             case 327692:
                updateVolet1Level(data.value);
                break;
        }
    });
    
    function updateVolet1Level(value) {
      const pct = Math.max(0, Math.min(100, Number(value)));
      const body = document.getElementById('volet1-body');
            const h = body.offsetHeight;
      const maskHeight = (100 - pct) / 100 * h;
      const mask = document.getElementById('volet1-mask');
      if (mask) mask.style.height = maskHeight + 'px';
    }



    function initVolet1(){
         GCE_API.get('api/core/ana/327692').then((ret) => { // ask for the actual value
            updateVolet1Level(ret.value);

        })
    }
    
    setTimeout(initVolet1,100);
  </script>


  <div class="widget-wrapper">
    <div class="stage">
      <!-- Graphisme du volet -->
      <div class="volet-frame">
        <div id="volet1-body" class="volet-body">
          <div id="volet1-mask" class="volet-mask"></div>
        </div>
      </div>

      <!-- Boutons -->
      <div class="volet-buttons">
        <button class="volet-button" onclick="GCE_API.putIO(65539, true)">
          <svg viewBox="0 0 100 100"><polygon points="50,10 90,90 10,90"/></svg>
        </button>
        <button class="volet-button" onclick="GCE_API.putIO(65539,false);GCE_API.putIO(65538,false);">
          <svg viewBox="0 0 100 100"><rect x="20" y="20" width="60" height="60"/></svg>
        </button>
        <button class="volet-button" onclick="GCE_API.putIO(65538, true)">
          <svg viewBox="0 0 100 100"><polygon points="10,10 90,10 50,90"/></svg>
        </button>
      </div>

      <div class="volet-label">RL3 & RL4 Ipx</div>
    </div>
  </div>

Chat-FGT : 1
Chat-GPT : 0

allez je retourne bêcher le jardin … :wink:

2 « J'aime »

Code collé dans mon widget et problème résolu.
Je valide le commentaire de Grocrabe.
Et puis, je vais regarder ce qui a été changé.

Merci Fgtoul et bonne soirée

2 « J'aime »

Bonjour @jmalpoincy
d’autres utilisateurs sont dans votre cas avec des VR branchés sur relais.
Vu que nous sommes dans le partage, acceptez-vous de révéler votre mise en œuvre ?
les scénarios, les liens, clignotants (valeurs TA, TB) , compteur, schéma de connexion (même à main levée) ? comment vous avez déterminé les valeurs d’incrément du compteur, etc.
Si vous préférez, vous pouvez aussi me transmettre ces éléments en message privé.

Je suis convaincu que votre retour d’expérience intéressera bon nombre de membres. De mon côté, je me propose de compiler toutes ces informations dans le wiki pour en faire profiter la communauté.

Bonne journée

Bonjour,

C’est génial,

J’ai copié votre code pour un volet, cela fonctionne partiellement et c’est déjà très bien.

mes volets sont sur des relais, merci pour cette solution à venir grâce au travail de @jmalpoincy et toujours @fgtoul

Bonne journée

Bernard

1 « J'aime »

Bonjour Fgtoul,

Oui, absolument, je pourrai communiquer tous ces éléments. Il me reste encore des choses à finaliser auparavant, mais dès que ce sera fait, je vous les transmettrai.

Ne serait-ce que le graphisme de ce widget qui est loin d’être parfait.
Je vois que celui que vous avez édité un peu plus haut montre des boutons trop décalés, alors que sur mon interface ils sont mieux centrés. Le widget n’est donc pas suffisament « universel ».
Egalement le manque de réalisme de la partie animée qui fonctionne à l’envers (Surface blanche mobile qui remonte sur une surface noire striée fixe).

2 « J'aime »

Ben si le volet est noir, tout est bon :slight_smile: , il suffit de colorer en bleu ciel la partie blanche :rofl: