[TUTORIEL] Créer un lecteur de badge dans un boitier RPI (ou autre) avec retour d'état d'alarme

Salut tout le monde, petit tutoriel pour créer un lecteur de badge que j’ai inséré dans un boitier de Raspberry. La Led passe de vert à rouge suivant l’état de l’alarme. Vert désarmée, rouge armée. Led bleue au centre pour confirmer la lecture du badge.



Puisque chaque badge est lu et transmis à Gladys, vous pouvez ainsi élaborer toutes les scènes que vous souhaitez en fonction de chaque personne qui badge.

Fonctionnement :
Lorsque le module est alimenté, il envoie le code 000 sur le topic(1) cité dans le code et lit la valeur du topic alarme(2) afin d’afficher la couleur de LED correspondante (alarme active ou non).
Si vous changer la valeur buzzer en D3, au démarrage il bipera 3 fois : 2 courts et 1 long
Lorsque vous passez un badge, la lumière bleue s’allume et le buzzer retenti 1 fois pour confirmer sa lecture. Le code du badge est envoyé sur le topic(1). La scène que vous aurez créée prends la suite …

Prérequis
Vous aurez besoin de :

ESP8266
RFID
LED
Buzzer
câbles
RPI vierge
pistolet

Coté Logiciel :
Arduino. Vous pouvez le télécharger ici :

Ajouter des bibliothèques suivantes :

  • ESP8266WiFi.h
  • ESP8266WiFiMulti.h
  • PubSubClient.h
  • SPI.h
  • MFRC522.h
  • NTPClient.h
  • WiFiUdp.h

bibliothèques

Connectez votre ESP8266 et vérifier qu’il soit bien reconnu.
Le driver des copies d’ESP8266 sur aliexpress peut être trouvé ici :

Suivez le tuto d’installation.
Dans Arduino, choisissez le port COM qui correspond à votre petite bête :

Choisissez votre carte (Pour des copies de cartes ESP8266, j’utilise cette ref de carte :

Programmation
Afin que le lecteur puisse communiquer le code lu à Gladys, il vous faut créer 2 fakes-device MQTT.
Dans l’intégration MQTT, créez 2 « fake device » comme ceci :

  1. Lecture du code alarme qu’il faudra paramétrer en valeur 0 à 1000000000000. Ce qui permet de laisser une large (très large) ouverture aux codes reçus. Moi j’ai utilisé le type « contrôle d’accès » .

→ Indiqué Lien1 dans le code

  1. Un commutateur alarme qui s’active en 0 ou 1 suivant l’état de l’alarme. Moi j’ai utilisé le type « Power».

→ Indiqué Lien2 dans le code

Intégration :
mqtt

Fakes devices :

Récupérez bien les adresses de Topic qu’il vous faudra indiquer dans le code pour l’ESP8266.

Code :
Il contient sans doute des erreurs grossières qui vont faire saigner quelques yeux mais j’ai réussi à le faire tourner avec mes faibles compétences en codage, ce qui est un grand exploit ! :exploding_head: Il est donc très perfectible …
J’ai ajouté un redémarrage toutes les 24h car, pour je ne sais quelle raison, le code s’épuise au bout d’un certain temps et le module ne capte plus les badges. Si l’un d’entre vous comprends le problème …

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h> 
#include <PubSubClient.h> 
#include <SPI.h>
#include <MFRC522.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

int Buzzer = D4; //for ESP8266 Microcontroller
#define SS_PIN D8
#define RST_PIN D0

#define alarme_code " Lien1"  //Topic Gladys alarme code

MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class

MFRC522::MIFARE_Key key;

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

long lastMsg = 0;   //Horodatage du dernier message publié sur MQTT
long lastRecu = 0;

// Init array that will store new NUID
byte nuidPICC[4];

//WIFI
const char* ssid = "votre nom de réseau SSID";
const char* password = "vode code wifi";
const char* code = "";

//MQTT
#define MQTT_BROKER       "adresse IP du broker"
#define MQTT_BROKER_PORT  1883
#define MQTT_USERNAME     "non d’utilisateur broker MSTT"
#define MQTT_KEY          "mot de passe du broker" 


ESP8266WiFiMulti WiFiMulti;
WiFiClient espClient;
PubSubClient client(espClient);


void setup() {
  Serial.begin(115200);
  setup_wifi();
  setup_mqtt();
  setup_RFID();
  
  pinMode (Buzzer, OUTPUT);
client.setCallback(callback);

pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
     digitalWrite(D1,LOW);
     digitalWrite(D2,LOW);
     digitalWrite(D3,LOW);
          delay(200); 
     digitalWrite (Buzzer, HIGH); //turn buzzer on
          delay(200); 
      digitalWrite (Buzzer, LOW);  //turn buzzer off
         delay(200); 
     digitalWrite (Buzzer, HIGH); //turn buzzer on
          delay(200); 
      digitalWrite (Buzzer, LOW);  //turn buzzer off
          delay(500); 
    digitalWrite (Buzzer, HIGH); //turn buzzer on
          delay(500); 
     digitalWrite (Buzzer, LOW);  //turn buzzer off

  // Abonnement au topic MQTT d'activation alarme par bouton
  client.subscribe("Lien2 ");

 client.publish(alarme_code, "000", true);   //Publie un code sur le topic alarme_code
  
   }
   
void restartESP() {
  ESP.restart(); // Redémarrage logiciel de l'ESP8266
}

void setup_wifi(){
  //connexion au wifi
  WiFiMulti.addAP(ssid, password);
  while ( WiFiMulti.run() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }
  Serial.println("");
  Serial.println("WiFi connecté");
  Serial.print("MAC : ");
  Serial.println(WiFi.macAddress());
  Serial.print("Adresse IP : ");
  Serial.println(WiFi.localIP());
    
}
void setup_mqtt(){
  client.setServer(MQTT_BROKER, MQTT_BROKER_PORT);
  client.setCallback(callback);//Déclaration de la fonction de souscription
  reconnect();
}

/**   
 *    Helper routine to dump a byte array as hex values to Serial.
*/
void printHex(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

void setup_RFID(){
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522
  Serial.println();
  Serial.print(F("Reader :"));
  rfid.PCD_DumpVersionToSerial();

  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }
  Serial.println();
  Serial.println(F("This code scan the MIFARE Classic NUID."));
  Serial.print(F("Using the following key:"));
  printHex(key.keyByte, MFRC522::MF_KEY_SIZE); 
}

void callback(char* topic, byte* payload, unsigned int length) {
  String value = "";
  for (int i = 0; i < length; i++) {
    value += (char)payload[i];
  }
  Serial.print("Valeur actuelle = ");
  Serial.println(value);
       
  Serial.println("-------Nouveau message du broker mqtt-----");
   Serial.print("Canal:");
   Serial.println(topic);
   Serial.print("donnee:");
   Serial.write(payload, length);
   Serial.println();
   if ((char)payload[0] == '1') { //A Paramétrer pour allumage ou extinction LED
     Serial.println("LED ON");
      digitalWrite(D2,LOW);
      digitalWrite(D1,HIGH);
      digitalWrite (Buzzer, HIGH); //turn buzzer on 
      delay(1000); 
     digitalWrite (Buzzer, LOW); //turn buzzer off
      Serial.println("allumage alarme");
           
   } else if ((char)payload[0] == '0'){
     Serial.println("LED OFF");
     digitalWrite(D1,LOW);
      digitalWrite(D2,HIGH);
      digitalWrite (Buzzer, HIGH); //turn buzzer on 
     delay(1000); 
     digitalWrite (Buzzer, LOW); //turn buzzer off
     Serial.println("Extinction alarme");
    
   }
 }


void reconnect(){
  while (!client.connected()) {
    Serial.println("Connection au serveur MQTT ...");
    if (client.connect("ESPClient", MQTT_USERNAME, MQTT_KEY)) {
      Serial.println("MQTT connecté");
          }
    else {
      Serial.print("echec, code erreur= ");
      Serial.println(client.state());
      Serial.println("nouvel essai dans 2s");
    delay(2000);
    }
  }
  client.subscribe("Lien2");// Abonnement au topic MQTT statut d’alarme
}

/**
   Helper routine to dump a byte array as dec values to Serial.
*/
void printDec(byte *buffer, byte bufferSize) {
  String payload = "";
  String topic = " Lien1";
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : "");
    Serial.print(buffer[i], DEC);
    payload += String(buffer[i]); // Ajout du script ChatGPT
      if (i != bufferSize - 1) { // Ajout du script ChatGPT
        payload += ""; // Ajout du script ChatGPT
      }
  }
client.publish(topic.c_str(), payload.c_str());
}


void loop() {
    if (millis() >= 86400000) { // Vérifier si 24 heures se sont écoulées (86 400 000 millisecondes)
  Serial.print ("24 heures passées");
    ESP.restart(); // Appeler la fonction pour redémarrer l'ESP8266
  }
  reconnect();
  client.loop();  
  float temp = 0;
  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! rfid.PICC_IsNewCardPresent())
    return;

  // Verify if the NUID has been readed
  if ( ! rfid.PICC_ReadCardSerial())
    return;

  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  Serial.println(rfid.PICC_GetTypeName(piccType));

  // Check is the PICC of Classic MIFARE type
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
      piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
      piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("Your tag is not of type MIFARE Classic."));
    return;
  }
    Serial.println(F("A new card has been detected."));
    // Store NUID into nuidPICC array
    for (byte i = 0; i < 4; i++) {
      nuidPICC[i] = rfid.uid.uidByte[i];
    }
    Serial.println(F("The NUID tag is:"));
    Serial.print(F("In hex: "));
    printHex(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
    Serial.print(F("In dec: "));
    printDec(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
    
      digitalWrite(D3,HIGH); // Allumage Led Bleue
      digitalWrite (Buzzer, HIGH); //turn buzzer on 
      delay(1000); 
      digitalWrite (Buzzer, LOW); //turn buzzer off 
      digitalWrite(D3,LOW); // Extinction Led Bleue
      
 long now = millis();    
 if (now - lastMsg > 1000 * 60) {
    lastMsg = now;

 }
  // Halt PICC
  rfid.PICC_HaltA();

  // Stop encryption on PCD
  rfid.PCD_StopCrypto1();
}

Pensez à modifier ces valeurs suivant votre propre installation :
• const char* ssid = « votre nom de réseau SSID »;
• const char* password = « vode code wifi »;
#define MQTT_BROKER « adresse IP du broker »
#define MQTT_BROKER_PORT 1883
#define MQTT_USERNAME « nom d’utilisateur broker MQTT »
#define MQTT_KEY « mot de passe du broker »

Le raccordement :

Le buzzer est raccordé avec la LED bleue afin d’être informé de manière visuelle et sonore.
Si vous souhaitez un clignotement LED bleue/buzzer au démarrage du module, changer la valeur D4 en D3 ici :
int Buzzer = D4



Vous affichez la boxes « contrôle d’accès » sur votre dashboard, vous alimentez votre lecteur de badge et vous passez un badge. Normalement vous entendrez le bip, verrez la lumière bleue et recevrez le code lu sur le dashboard.
Par sécurité, l’affichage du code n’est pas à laisser sur le dashboard, il ne sert qu’à récupérer les valeurs en mode paramétrage.

Scènes Gladys :
Enfin pour fonctionner avec le nouveau système d’alarme de Gladys, il vous faut créer 2 scènes inversées.
Activation de l’alarme par badge :

  • Lorsque le code lu (fake device contrôle d’accès 1) est = à (valeur de votre badge) alors,
  • Si la maison est désarmée
    • Armement de la maison
    • « Contrôler un appareil » (fake device power 2) et le passer en 1

Désactivation de l’alarme par badge :

  • Lorsque le code lu (fake device contrôle d’accès 1) est = à (valeur de votre badge) alors,
  • Si la maison est armée
    • Désarmement de la maison
    • « Contrôler un appareil » (fake device power 2) et le passer en 0

Dans le déclencheur, vous pouvez ajouter plusieurs boxes de codes à vérifier.
Vous pouvez ajouter une temporisation dans votre scène d’activation par badge entre la lecture du badge et l’armement de la maison afin de vous laisser le temps de sortir.
Personnellement j’ai ajouté des messages Google Home qui avertissent de quitter la maison à l’activation du badge, 3 minutes après puis 4 puis à l’armement.

J’espère être assez clair et qu’il pourra convenir à votre usage.

A votre tour et bon courage …

8 « J'aime »

Merci pour le tuto, c’est super chouette de découvrir des projets comme ça :slight_smile:

Concernant ton code, depuis quelques temps je dev des macros VBA (et Office Script quand je peux, je préfère) pour automatiser certaines tâches. Comme je ne connais pas le VBA, j’utilise pas mal https://bard.google.com/ (le « ChatGPT » de Google) ou https://chat.openai.com/ (ChatGPT) pour me fournir des exemples de code.

Parfois ces deux IA ont des codes totalement fonctionnels, parfois pas tellement :sweat_smile:
Dans tous les cas, ça peut aussi aider à corriger certains problèmes surtout quand on y connait pas grand chose.

1 « J'aime »

Merci beaucoup pour ce super tuto !!! :+1:
C’est le genre de chose dans laquelle j’aimerai bien me lancer.

Merci pour ton retour. Je ne suis pas expert en VBA mais je me débrouille pas mal en concoctant des macros sous Excel me permettant de gagner beaucoup de temps professionnellement. Concernant ChatGPT, figures toi que je m’en suis également servi pour « stabiliser » le code :sweat_smile:
Parfois par contre il empirait les choses en s’excusant à chaque fois … :yum:

J’ai pas mal trainé aussi mais je voulais remplacer ma centrale 433 car Gladys finissait par faire l’interface un peu bancale entre détecteurs zigbee et les télécommandes 433. Là c’est simple, modulable et appréciée pour la famille qui n’a pas le nez dans l’installation Gladys.
Il me reste à monter un système sms (super tuto de Checconio) en cas de chute du wifi (même si déjà tout sur onduleur) et une sirène zigbee.

1 « J'aime »

Oui, faut savoir faire du « prompt hacking » parfois ou carrément détecter quand il fait n’importe quoi.
J’alterne entre recherches sur internet et ChatGPT pour le code.

Bref, bien joué pour le tuto ! Tu l’utilises pour armer l’alarme chez toi ?

@lmilcent
Oui.
Je passe le badge entrée/sortie ou bien j’active via le nouveau bouton Gladys.
La subtilité étant que ces 2 actions déclenchent une scène de compte à rebours qui me laisse le temps de sortir, couplé à des messages Google Home qui m’invitent gentiment à sortir rapidement de chez moi :yum:
Ensuite un fake device s’active armé/désarmé et c’est celui-ci qui est vérifié en cas d’intrusion.
Petite vérif immédiate de baies ouvertes également à l’activation badge ou bouton.

1 « J'aime »