🔢 WIKI X-WIEGAND, Alarme, Contrôle d'accès et Widgets

Bonjour Ă  tous,
avec la sortie de l’extension X-Wiegand, je vous propose un nouvel article.
Mise en œuvre du module et exemples de programmations.

X-WIEGAND et X-DISPLAY V2 : La sûreté avec IPX800 V5 — GCE Electronics


J’ai également écrit un second article permettant d’étudier l’utilisation du clavier virtuel sur X-Display V2 au travers de la mise en place d’un petit système d’alarme.

X-Display V2 : conception d’un système d’alarme simple — GCE Electronics

Bonne lecture

9 « J'aime »

Bonjour Ă  tous,

Astuce 1

après la conception d’un système d’alarme sur V5, je souhaitais mettre un dashboard sur une tablette murale.
Celle-ci étant toujours connectée avec un user sans durée limitée de session, il était nécessaire de sécuriser le dashboard.
Sur IPX V5, j’ai donc créé une tempo, le dashboard sera activé pendant le décompte seulement.
Cette tempo est démarrée par la sortie d’un objet Access Control lui-même piloté via un widget clavier virtuel (voir tuto ici).
exemple avec une tempo de 3s
dashboard securise demo

Tous les widgets restent pleinement fonctionnels.
Exemple avec tempo 30s
dashboard sécurisé

un petit widget HTML récupère l’IO output de la tempo et bascule la visibilité des widgets par leur id. (pour connaître l’id d’un widget, voir plus bas)

Exemple de code pour les widget avec id ‹ 3 â€ş et ‹ 6 â€ş:

<script>
var idUnlock=66298; //id de la sortie de la tempo
var dashboardEnabled;

function g(elm){return document.getElementById(elm);}

function toggleWidgets(){ //masquage/démasquage des widget avec id=3 et 6
  if (dashboardEnabled) {
       g('3').style.display = "block";
       g('6').style.display = "block";
    } else {
       g('3').style.display = "none";
       g('6').style.display = "none";
    }
}
window.GCE_Refresh.push(function(data) { 
  switch (data['_id']) {
    case idUnlock:  //id tempo output
        dashboardEnabled=data.on;
        toggleWidgets();
        break;
  }
});

function init() {
  dashboardEnabled=false;
  GCE_API.getIO(idUnlock).then((ret) => { // ask for the actual value
    dashboardEnabled=ret.on;
    toggleWidgets();
  });

setTimeout(init,150);
</script>

Pour retrouver l’id d’un widget, faites un clic dessus avec le bouton droit de la souris puis sĂ©lectionnez l’option « inspecter Â». Dans le code qui s’affiche alors, remontez progressivement en survolant le code puis sĂ©lectionnez la balise qui met en surbrillance le widget en totalitĂ©. Vous repèrerez l’élĂ©ment avec la classe grid-stack-item widget. La valeur Ă  relever est l’attribut id. (3 dans notre exemple ci-dessous)

voici la méthode en vidéo (avec le navigateur Edge):
inspecter widgets

bonne journée

3 « J'aime »

ASTUCE 2

Il est également possible de sécuriser un Liveview.
La méthode la plus simple consiste à masquer tout ou partie du Liveview par des widgets Image On/Off.
Exemple avec le Liveview du système d’alarme. Certains widgets sont masqués par une image on/off dépendant d’une temporisation activée par la saisie d’un code administrateur. Dans le cas ci-dessous c’est un objet Control d’accès dont la sortie est liée à la commande de la tempo.
Un panneau « Entrez le code administrateur Â» masque les informations confidentielles comme le dernier numĂ©ro de badge reçu par le contrĂ´leur Wiegand.


1 « J'aime »

En partage, voici un nouveau widget HTML pour visualiser l’état d’une centrale d’alarme.

Sur IPX V5, un compteur prend 3 valeurs possibles :
0 : désarmée
1: armement partiel
2: armement total

widget statut centrale

Voici le code :

<script>
    var valueCentrale = 0;
    var positions = ["80px", "-20px", "180px"]; // Centre, Gauche, Droite
    var colors = ["#1fdb49", "yellow", "red"];
    
        function updateSlider() {
            var thumb = document.getElementById("thumb");
            thumb.style.left = positions[valueCentrale];
            thumb.style.borderColor = colors[valueCentrale];
        } 
        
    window.GCE_Refresh.push(function(data) {
    switch (data['_id'])
    {
        case 327806:
            valueCentrale=data.value;
            updateSlider();
            break;
    }
  })
  
  function init4() {
    GCE_API.get('/api/core/ana/327806').then((ret) => { // ask for the actual value
      valueCentrale=ret.value;
      updateSlider();
    })
  }
 setTimeout(init4,50);

</script>
<style>
  .slider-container {
    width: 200px;
    height: 1px;
    background-color: #fff;
    position: relative;
    margin: 40px auto 0;
  }
  
  .slider-thumb {
    width: 40px;
    height: 20px;
    position: absolute;
    top: -13px;
    left: 80px;
    background-color: #ccc;
    border-radius: 10px;
    border: 3px solid #1fdb49;
    transition: all 0.3s ease-in-out;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .slider-thumb::before {
    content: "|";
    color: #fff;
    font-size: 14px;
  }
  
  .marker {
    width: 4px;
    height: 10px;
    background-color: #fff;
    position: absolute;
    top: -5px;
  }
  
  .slider-icon {
    position: absolute;
    top: -70px;
    font-size: 2em;
  }
  
  .slider-label {
    position: absolute;
    top: -40px;
    font-size: 0.8em;
  }
</style>

<div class="slider-container">
  <!-- IcĂ´nes -->
  <i class="gce-glyph icon-home_room slider-icon" style="left: -10px; color: yellow;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 90px; color: #1fdb49;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 190px; color: #f00;"></i>
  
  <!-- Labels -->
  <span class="slider-label" style="left: -15px; color: yellow;">PARTIEL</span>
  <span class="slider-label" style="left: 85px; color: #1fdb49;">DESARME</span>
  <span class="slider-label" style="left: 185px; color: #f00;">ARME</span>
  
  <!-- Marqueurs -->
  <div class="marker" style="left: 0;"></div>
  <div class="marker" style="left: 100px;"></div>
  <div class="marker" style="left: 200px;"></div>
  
  <!-- Curseur -->
  <div id="thumb" class="slider-thumb"></div>
</div>

vous devez renseigner l’ID de la sortie Valeur du compteur

voici un exemple d’utilisation :
utilisation widget centrale

Le même widget pourrait superviser l’état d’une partition. En cas d’inhibition de capteurs, la partition serait armée partiellement, en cas de non inhibition, l’armement serait total.
bonne journée

1 « J'aime »

le même Widget avec possibilité de contrôle par déplacement du curseur, à la souris (mousemove) ou sur écran tactile (touchmove)
Le compteur est mis à jour à chaque déplacement, il suffit de scénariser l’armement et désarmement en fonction de sa valeur.
Lors d’un clic sur la ligne du slider, le script évalue la position la plus proche pour y déplacer le curseur. Si vous cliquez pile au milieu, le curseur n’est pas déplacé.
Pour éviter cela, les icônes labels et repères sont également cliquables, ce qui garantit une utilisation plus fluide.

widget controle centrale

Voici le code :

<style>
  .slider-container {
    width: 200px;
    height: 1px;
    background-color: #fff;
    position: relative;
    margin: 40px auto 0;
    cursor:pointer;
  }
  
  .slider-thumb {
    width: 40px;
    height: 20px;
    position: absolute;
    top: -13px;
    left: 80px;
    background-color: #ccc;
    border-radius: 10px;
    border: 3px solid #1fdb49;
    transition: all 0.3s ease-in-out;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor:grab;
  }
  
  .slider-thumb::before {
    content: "|";
    color: #fff;
    font-size: 14px;
  }
  
  .marker {
    width: 4px;
    height: 10px;
    background-color: #fff;
    position: absolute;
    top: -5px;
    cursor:pointer;
  }
  
  .slider-icon {
    position: absolute;
    top: -70px;
    font-size: 2em;
  }
  
  .slider-label {
    position: absolute;
    top: -40px;
    font-size: 0.8em;
  }
</style>


<script>
    var valueCentrale = 0;
    var positions = [80, -20, 180]; // Centre, Gauche, Droite
    var colors = ["#1fdb49", "yellow", "red"];

    function updateSlider() {
        var thumb = document.getElementById("thumb");
        thumb.style.left = positions[valueCentrale] + "px";
        thumb.style.borderColor = colors[valueCentrale];
        GCE_API.put('/api/core/ana/327806',{value : valueCentrale}).then((ret) => {
        });
    }

    window.GCE_Refresh.push(function(data) {
        if (data['_id'] === 327806) {
            valueCentrale = data.value;
            updateSlider();
        }
    });
    function moveThumb(event) {
        let xPos = event.clientX || event.touches[0].clientX;
        let sliderRect = document.querySelector(".slider-container").getBoundingClientRect();
        let relativeX = xPos - sliderRect.left;

        let closestIndex = positions.reduce((prev, curr, index) =>
            Math.abs(curr - relativeX) < Math.abs(positions[prev] - relativeX) ? index : prev, 0);

        valueCentrale = closestIndex;
        updateSlider();
    }
    function init4() {
        GCE_API.get('/api/core/ana/327806').then((ret) => {
            valueCentrale = ret.value;
            updateSlider();
        });
        document.querySelector(".slider-container").addEventListener("mousedown", (event) => moveThumb(event));
        document.querySelector(".slider-container").addEventListener("touchmove", (event) => {
            event.preventDefault();
            moveThumb(event);
        });
    }
    setTimeout(init4, 50);





</script>
<div class="slider-container">
  <!-- IcĂ´nes -->
  <i class="gce-glyph icon-home_room slider-icon" style="left: -10px; color: yellow;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 90px; color: #1fdb49;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 190px; color: #f00;"></i>
  
  <!-- Labels -->
  <span class="slider-label" style="left: -15px; color: yellow;">PARTIEL</span>
  <span class="slider-label" style="left: 85px; color: #1fdb49;">DESARME</span>
  <span class="slider-label" style="left: 185px; color: #f00;">ARME</span>
  
  <!-- Marqueurs -->
  <div class="marker" style="left: 0;"></div>
  <div class="marker" style="left: 100px;"></div>
  <div class="marker" style="left: 200px;"></div>
  
  <!-- Curseur -->
  <div id="thumb" class="slider-thumb"></div>
</div>

```
1 « J'aime »

Merci @fgtoul pour le partage
En prenant l’exemple des casiers dans le WIKI on peut gérer un code sous contrainte ?
Code qui désarme mais fait autre chose aussi alarme silencieuse ou autre
Bonne journée

oui, il faut créer un objet Control Access dédié

Super merci (le reste c’est pour les 20 caractères :-))

Voici une autre manière de protéger un affichage sur un liveview avec un champ de saisie :

input text

Le champ de saisie est dans un widget HTML qui vérifie à intervalle régulier la sortie d’une temporisation. Cette temporisation est démarrée par un objet Access Control qui permet la gestion d’un code administrateur. Si le code saisi est correct, la sortie de la tempo (id 65602) s’active pour le temps déterminé (9s dans l’exemple), ce qui autorise l’affichage des informations confidentielles.
Dans mon exemple, c’est un autre widget HTML qui affiche le numéro du dernier badge lu.

  • Voici l’objet Access Control permettant la gestion du code administrateur.
    Sa sortie est liée à l’entrée start de la tempo.


    Son paramètre Contenu Str est rattaché à une variable Str32 dont l’id est 524310. C’est dans cette variable que sera injectée la valeur saisie. L’objet Control Access activera alors sa sortie si le code est valide.


Dans mon exemple, le widget HTML récupère le numéro du dernier badge lu. Cette information est contenue dans le paramètre StrCurrentCode d’un autre objet Access Control.,

Voici le code:

<style>
        #admInput {
            font-size: 1.2em;
            padding: 10px;
            border: 2px solid #333;
            border-radius: 5px;
            width: 250px;
            color:white;
            background-color:#333;
        }
        #admButton {
            font-size: 1.2em;
            padding: 10px 20px;
            background-color: #007BFF;
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            margin-top: 10px;
        }
        #admButton:hover {
            background-color: #0056b3;
        }
</style>

<script type="text/javascript">
   var server="",//vide pour local, sinon format http://ip
   api="wlAbCG6FZm2UH5w", //renseigner clé API
   uriStr="/api/core/str/",
   uriIO="/api/core/io/",
   idA="524310", // Administrator code
   idT="65602"; //Tempo Admin output
   idW="524289";//dernier code reçu
   var IOadmin;
   IOadmin=false;
   var mStr="";

        function validateCode() {
            var inputValue = document.getElementById("admInput").value;
            document.getElementById("admInput").value="";
            fetch(uriStr + idA + '?ApiKey=' + api, {
                method: "PUT", //envoie valeur saisie au Access Control
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({ "value": inputValue.toString() })
                })
                .then(response => response.json())
                //document.getElementById("admInput").value="";
        }

/* Get data from API */
function getIPX1(cb) {// get sortie tempo ADM
 fetch(uriIO+idT+"?ApiKey="+api, {method: "GET"}).then((ret) => { // Get IPX object
 ret.json().then((ipx) => {
 cb(ipx); // Return IPX state from API
 });
 });
}

function getIPX2(cb) {// get dernier code reçu
 fetch(uriStr+idW+"?ApiKey="+api, {method: "GET"}).then((ret) => { // Get IPX object
 ret.json().then((ipx) => {
 cb(ipx); // Return IPX state from API
 });
 });
}

function init2(){
/* recup tempo administrateur */
        getIPX1((ipx) => {IOadmin = ipx.on;});
 /* recup string */
        getIPX2((ipx) => {mStr = ipx.value;});
        cADM=document.getElementById("cADM");        
        if (IOadmin){
          cADM.innerHTML=mStr;
          }else{
          cADM.innerHTML="Affichage verrouillé!";
        }
}
function autoRefresh() {
setInterval(() => {
init2();
}, 1000); // 1 sec
}

setTimeout(init2, 500);
autoRefresh();

</script>

                <input width=100 type="text" id="admInput" placeholder="Entrez votre code Admin" autocomplete="off">
                <button id="admButton" onclick="validateCode()">OK</button>
                

Voici le code du widget qui se charge d’afficher l’info

<div id="cADM" style="background-color:#222;font-size:1.5em">...</div>
1 « J'aime »

Voici comme discuté plus haut le widget pour le statut de 2 partitions.
Les compteurs 327806 et 327808 devront être gérés par ailleurs.

utilisation widget centrale2


<style>
  .slider-container {
    width: 200px;
    height: 1px;
    background-color: #fff;
    position: relative;
    margin: 40px auto 0;
  }
  
  .slider-thumb {
    width: 40px;
    height: 20px;
    position: absolute;
    top: -13px;
    left: 80px;
    background-color: #ccc;
    border-radius: 10px;
    border: 3px solid #1fdb49;
    transition: all 0.3s ease-in-out;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .slider-thumb::before {
    content: "|||";
    color: #fff;
    font-size: 14px;
  }
  
  .marker {
    width: 4px;
    height: 10px;
    background-color: #fff;
    position: absolute;
    top: -5px;
  }
  
  .slider-icon {
    position: absolute;
    top: -60px;
    font-size: 2em;
  }
  
  .slider-label {
    position: absolute;
    top: -30px;
    font-size: 0.8em;
  }
</style>

<script>
    var valueP1 = 0;var valueP2 = 0;
    var positions = ["80px", "-20px", "180px"]; // Centre, Gauche, Droite
    var colors = ["#1fdb49", "yellow", "red"];
    
        function updateSlider1() {
            var thumb = document.getElementById("thumb1");
            thumb.style.left = positions[valueP1];
            thumb.style.borderColor = colors[valueP1];
        } 
         function updateSlider2() {
            var thumb = document.getElementById("thumb2");
            thumb.style.left = positions[valueP2];
            thumb.style.borderColor = colors[valueP2];
        }        
    window.GCE_Refresh.push(function(data) {
    switch (data['_id'])
    {
        case 327806:
            valueP1=data.value;
            updateSlider1();
            break;
    
            case 327808:
            valueP2=data.value;
            updateSlider2();
            break;
    }
  })
  
  function init4() {
    GCE_API.get('/api/core/ana/327806').then((ret) => { // ask for the actual value
      valueP1=ret.value;
      updateSlider1();
    })
        GCE_API.get('/api/core/ana/327808').then((ret) => { // ask for the actual value
      valueP2=ret.value;
      updateSlider2();
    })
  }
 setTimeout(init4,50);

</script>

<div class="slider-container">
  <!-- IcĂ´nes -->
  <i class="gce-glyph icon-home_room slider-icon" style="left: -10px; color: yellow;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 90px; color: #1fdb49;"></i>
  <i class="gce-glyph icon-home_room slider-icon" style="left: 190px; color: #ff0013;"></i>
  
  <!-- Labels -->
  <span class="slider-label" style="left: -15px; color: yellow;">PARTIEL</span>
  <span class="slider-label" style="left: 85px; color: #1fdb49;">DESARME</span>
  <span class="slider-label" style="left: 185px; color: #ff0013;">ARME</span>
  
  <!-- Marqueurs -->
  <div class="marker" style="left: 0;"></div>
  <div class="marker" style="left: 100px;"></div>
  <div class="marker" style="left: 200px;"></div>
  
  <!-- Curseur -->
  <div id="thumb1" class="slider-thumb"></div>
</div>

<div class="slider-container">
  <!-- Marqueurs -->
  <div class="marker" style="left: 0;"></div>
  <div class="marker" style="left: 100px;"></div>
  <div class="marker" style="left: 200px;"></div>
  
  <!-- Curseur -->
  <div id="thumb2" class="slider-thumb"></div>
</div>

1 « J'aime »