Système de contrôle d’accès distribué avec nœuds Arduino PoE, synchronisation NTP et réplication de la base de données des badges via RS485

Système de contrôle d’accès distribué avec nœuds Arduino PoE, synchronisation NTP et réplication sécurisée des badges via RS485 multi-maître.

Brève Introduction

Système de contrôle d’accès distribué avec nœuds Arduino PoE, synchronisation NTP et réplication de la base de données des badges via RS485 (arduino)
DESCRIPTION :
Implémentation avancée d'un système de contrôle d'accès distribué basé sur des nœuds Arduino alimentés via PoE, avec synchronisation horaire via le protocole NTP et réplication sécurisée et robuste de la base de données des badges via communication RS485 multi-maître. Le système gère l'authentification des badges RFID, la journalisation des événements avec horodatage synchronisé, et la communication bidirectionnelle pour les mises à jour et la diagnostic.

NOTES SUPPLÉMENTAIRES :
Ce système est conçu pour des environnements distribués avec plusieurs nœuds Arduino connectés en réseau Ethernet PoE et communication RS485 pour synchroniser les bases de données des badges. La synchronisation NTP garantit des horodatages fiables. Le protocole RS485 implémenté est simple mais robuste, avec en-têtes et contrôle d'état. Le code est évolutif et peut être étendu avec une authentification cryptographique et une gestion avancée des erreurs.

EXPLICATIONS :
- La synchronisation NTP met à jour l'horloge RTC DS3231 pour maintenir un temps précis même en cas de perte temporaire du réseau.
- La communication RS485 utilise un protocole personnalisé simple avec des en-têtes 0xAA et 0x55 pour délimiter les paquets de réplication de la base de données des badges.
- La base de données des badges est maintenue en RAM sous forme de tableau d'UID de 4 octets, avec des fonctions pour ajouter uniquement de nouveaux badges en évitant les doublons.
- Le module MFRC522 lit les badges RFID et compare l'UID avec la base de données pour autoriser ou refuser l'accès.
- Le module Ethernet W5500 est configuré avec SPI partagé avec MFRC522, utilisant des broches CS séparées pour éviter les conflits.
- La broche RS485_DE_RE_PIN contrôle la direction de la communication RS485, activant la transmission ou la réception.
- La réplication de la base de données se fait périodiquement en envoyant la liste complète des badges aux autres nœuds pour maintenir la synchronisation.
- La journalisation des événements avec horodatage précis aide à la surveillance et à l'audit du système de contrôle d'accès.

Code d'Exemple : arduino

// Système de contrôle d'accès distribué avec Arduino Mega, PoE, synchronisation NTP et réplication de la base de données des badges via RS485

#include <SPI.h>
#include <Ethernet.h>
#include <NTPClient.h>
#include <EthernetUdp.h>
#include <MFRC522.h>
#include <RTClib.h>
#include <ModbusMaster.h>

// --- CONFIGURATION DES BROCHES ---
// Ethernet W5500 SPI
#define ETH_CS_PIN 10
#define ETH_INT_PIN 2

// MFRC522 RFID
#define RFID_SS_PIN 53
#define RFID_RST_PIN 9

// RS485 MAX485
#define RS485_DE_RE_PIN 8

// I2C pour RTC
// SDA : broche 20, SCL : broche 21 (I2C matériel)

// --- CONFIGURATION RÉSEAU ---
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 100); // IP statique, modifier pour chaque nœud
unsigned int localPort = 8888; // port UDP pour NTP

// --- VARIABLES GLOBALES ---
EthernetUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000); // mise à jour toutes les 60s
MFRC522 mfrc522(RFID_SS_PIN, RFID_RST_PIN);
RTC_DS3231 rtc;
ModbusMaster node;

// Tampon pour base de données des badges (exemple simple, max 100 badges)
#define MAX_BADGES 100
#define BADGE_ID_LEN 4 // UID de 4 octets
byte badgeDatabase[MAX_BADGES][BADGE_ID_LEN];
uint8_t badgeCount = 0;

// ID nœud RS485 (à configurer de manière unique pour chaque nœud)
#define NODE_ID 1

// Fonction pour activer la transmission RS485
void rs485TransmitEnable(bool enable) {
  digitalWrite(RS485_DE_RE_PIN, enable ? HIGH : LOW);
}

// Fonction pour comparer deux UID de badge
bool confrontaUID(byte *uid1, byte *uid2) {
  for (int i = 0; i < BADGE_ID_LEN; i++) {
    if (uid1[i] != uid2[i]) return false;
  }
  return true;
}

// Ajoute un badge à la base de données s'il n'est pas présent
bool aggiungiBadge(byte *uid) {
  for (int i = 0; i < badgeCount; i++) {
    if (confrontaUID(badgeDatabase[i], uid)) return false; // déjà présent
  }
  if (badgeCount < MAX_BADGES) {
    memcpy(badgeDatabase[badgeCount], uid, BADGE_ID_LEN);
    badgeCount++;
    return true;
  }
  return false; // base de données pleine
}

// Vérifie si le badge est autorisé
bool badgeAutorizzato(byte *uid) {
  for (int i = 0; i < badgeCount; i++) {
    if (confrontaUID(badgeDatabase[i], uid)) return true;
  }
  return false;
}

// Fonction pour envoyer la base de données des badges via RS485 (réplication)
void inviaDatabase() {
  // Protocole simple : envoi d'un paquet avec en-tête, nombre de badges, liste des UID
  rs485TransmitEnable(true);
  delay(10); // stabiliser la ligne

  Serial1.write(0xAA); // en-tête début
  Serial1.write(NODE_ID); // ID nœud émetteur
  Serial1.write(badgeCount); // nombre de badges

  for (int i = 0; i < badgeCount; i++) {
    Serial1.write(badgeDatabase[i], BADGE_ID_LEN);
  }

  Serial1.write(0x55); // en-tête fin
  Serial1.flush();
  delay(10);
  rs485TransmitEnable(false);
}

// Fonction pour recevoir et traiter la base de données des autres nœuds
void riceviDatabase() {
  static enum {WAIT_START, READ_ID, READ_COUNT, READ_UIDS, WAIT_END} state = WAIT_START;
  static byte buffer[MAX_BADGES * BADGE_ID_LEN];
  static uint8_t count = 0;
  static uint8_t index = 0;
  static uint8_t senderID = 0;

  while (Serial1.available()) {
    byte c = Serial1.read();
    switch(state) {
      case WAIT_START:
        if (c == 0xAA) {
          state = READ_ID;
        }
        break;
      case READ_ID:
        senderID = c;
        state = READ_COUNT;
        break;
      case READ_COUNT:
        count = c;
        if (count > MAX_BADGES) {
          // erreur, réinitialiser
          state = WAIT_START;
        } else {
          index = 0;
          state = READ_UIDS;
        }
        break;
      case READ_UIDS:
        buffer[index++] = c;
        if (index >= count * BADGE_ID_LEN) {
          state = WAIT_END;
        }
        break;
      case WAIT_END:
        if (c == 0x55) {
          // Traiter la base de données reçue
          for (int i = 0; i < count; i++) {
            byte *uid = &buffer[i * BADGE_ID_LEN];
            aggiungiBadge(uid); // ajoute seulement si nouveau
          }
        }
        state = WAIT_START;
        break;
    }
  }
}

// Fonction pour enregistrer un événement d'accès
void logEvento(const char* evento, byte *uid) {
  Serial.print("[");
  Serial.print(rtc.now().timestamp());
  Serial.print("] ");
  Serial.print(evento);
  Serial.print(" UID: ");
  for (int i = 0; i < BADGE_ID_LEN; i++) {
    if (uid[i] < 0x10) Serial.print("0");
    Serial.print(uid[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200); // debug
  Serial1.begin(9600); // RS485

  pinMode(RS485_DE_RE_PIN, OUTPUT);
  rs485TransmitEnable(false); // réception RS485

  // Initialiser Ethernet PoE
  SPI.begin();
  Ethernet.begin(mac, ip);

  // Initialiser NTP
  timeClient.begin();

  // Initialiser RTC
  if (!rtc.begin()) {
    Serial.println("Erreur RTC");
    while (1);
  }
  if (rtc.lostPower()) {
    Serial.println("RTC a perdu l'alimentation, réglage de l'heure via NTP");
    timeClient.update();
    DateTime now = DateTime(timeClient.getEpochTime());
    rtc.adjust(now);
  }

  // Initialiser MFRC522
  mfrc522.PCD_Init();

  // Initialiser ModbusMaster (non utilisé dans cet exemple mais prêt)
  node.begin(NODE_ID, Serial1);

  Serial.println("Système de contrôle d'accès démarré");
}

void loop() {
  // Synchroniser l'heure NTP périodiquement
  if (timeClient.update()) {
    DateTime now = DateTime(timeClient.getEpochTime());
    rtc.adjust(now);
  }

  // Gestion de la communication RS485 (réception base de données)
  riceviDatabase();

  // Lecture du badge RFID
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
    byte uid[BADGE_ID_LEN] = {0};
    // Copier UID (4 octets)
    for (byte i = 0; i < BADGE_ID_LEN; i++) {
      uid[i] = mfrc522.uid.uidByte[i];
    }

    if (badgeAutorizzato(uid)) {
      logEvento("Accès autorisé", uid);
      // Actions d'accès (ex. ouvrir porte) ici
    } else {
      logEvento("Accès refusé", uid);
    }

    mfrc522.PICC_HaltA();
  }

  // Réplication périodique de la base de données (ex. toutes les 5 minutes)
  static unsigned long lastReplica = 0;
  if (millis() - lastReplica > 300000) {
    inviaDatabase();
    lastReplica = millis();
  }

  // Watchdog logiciel (optionnel)
  // Implémenter un reset si nécessaire
}
×
×
×
Veux-tu régénérer la réponse ?
×
Exporter le chat
Choisissez le format d'export
⏳ Generazione PDF in corso…
Allegati
×
⚠️ Vous êtes sur le point de fermer le chat et de passer au générateur d’images. Si vous n’êtes pas connecté, vous perdrez notre conversation. Confirmez-vous ?
👁 Tu consultes une discussion partagée en mode temporaire. Elle ne sera pas enregistrée.
💬
×
Prompts enregistrés
×
Note privée
×
Étiquette
×
Rechercher dans toutes les discussions
×
Vos insights
Analyse en cours…
×
Préférences IA
Nom de l'assistant 30
Longueur des réponses
Modèle IA
Réponses structurées
Inclure des exemples
Utiliser des emojis
Guide-moi, ne résous pas Des indices et des questions plutôt que la réponse toute faite
Plus de réglages →
×
Partager cette discussion
Toute personne ouvrant ce lien pourra consulter la discussion ou l'ajouter à son profil comme discussion personnelle.
⚠️ Attention : les pièces jointes de la discussion seront également partagées. Qui l'ajoutera recevra une copie des fichiers dans son dossier.
Discussion partagée
Quelqu'un a partagé une discussion avec toi. Veux-tu seulement la consulter ou l'ajouter à tes discussions ?
⚠️ Attention : les pièces jointes de la discussion seront également partagées. Qui l'ajoutera recevra une copie des fichiers dans son dossier.
×

📌 Messages enregistrés

Chargement...

×

Historique des discussions

programmes-exemples · HISTORIQUE DU CHAT

Chargement...

Préférences IA

×
  • 🟢 BasiqueRéponses rapides et essentielles pour étudier
  • 🔵 MoyenQualité supérieure pour étude et programmation
  • 🟣 AvancéRaisonnement complexe et analyses détaillées
Expliquer les étapes

Qu'est-ce qu'il faut ?

Arduino Mega 2560 (pour plus de broches et de RAM)

Module Ethernet PoE W5500 (alimentation et communication réseau)

Module RTC DS3231 (sauvegarde horaire locale en cas de perte NTP)

Module RFID MFRC522 (lecture des badges RFID 13,56 MHz)

Transceiver RS485 MAX485 (pour communication série différentielle multi-nœuds)

Alimentation PoE conforme IEEE 802.3af/at

Câbles Ethernet CAT5e/CAT6 avec connecteurs RJ45

Câbles paires torsadées pour RS485 (de préférence blindés)

Bibliothèque Arduino Ethernet (Ethernet.h)

Bibliothèque NTPClient (pour synchronisation horaire via UDP)

Bibliothèque MFRC522 (gestion du lecteur RFID)

Bibliothèque RTClib (gestion du RTC DS3231)

Bibliothèque ModbusMaster (pour protocole RS485 multi-maître)

Configuration du câblage :
  • Ethernet PoE W5500 : SPI (MOSI : broche 51, MISO : broche 50, SCK : broche 52), CS : broche 10, INT : broche 2
  • MFRC522 : SPI (partagé avec Ethernet), SS : broche 53, RST : broche 9
  • RTC DS3231 : I2C (SDA : broche 20, SCL : broche 21)
  • RS485 MAX485 : broche DE/RE 8 (contrôle de direction), DI : broche 51 (MOSI), RO : broche 50 (MISO)
  • Alimentation PoE connectée via module séparateur PoE ou directement au module Ethernet PoE
Configuration logicielle :
  • Définir une adresse IP statique ou DHCP pour le module Ethernet
  • Configurer le serveur NTP (ex. pool.ntp.org)
  • Configurer un ID de nœud unique pour le protocole RS485 multi-maître
  • Implémenter la gestion des erreurs et les tentatives de nouvelle communication pour RS485 et NTP
  • Implémenter un watchdog pour un redémarrage automatique en cas de blocage

Sujets Similaires

LED clignotant avec bouton d’arrêt
Programme Arduino pour faire clignoter une LED avec un bouton d’arrêt. La LED clignote toutes les 5 ms et s’éteint quand le bouton est pressé.
Feu piéton avec deux LED et bouton
Projet Arduino simple de feu piéton avec deux LED rouge et verte et un bouton pour contrôler le passage en toute sécurité.
Thermomètre de base avec capteur de température et LED d’alerte
Thermomètre Arduino simple avec capteur LM35 et LED d’alerte qui s’allume au-delà de 3 degrés Celsius pour une surveillance efficace.
Alarme porte ouverte avec capteur magnétique et buzzer
Projet Arduino d’alarme porte ouverte utilisant un capteur magnétique reed et un buzzer pour détecter et signaler l’ouverture d’une porte efficacement.
Contrôle d’un ventilateur avec capteur de température on/off
Contrôle d’un ventilateur avec capteur LM35 et Arduino pour allumer ou éteindre selon la température détectée, seuil réglable à 3 degrés Celsius.
LED qui s’allume dans le noir avec une photorésistance
Projet Arduino avec photorésistance pour allumer une LED dans le noir. Seuil ajustable, diviseur de tension et contrôle simple pour détecter l’obscurité.
Sonnette de maison avec bouton et buzzer
Projet Arduino simple pour une sonnette maison avec bouton et buzzer actif. Utilise INPUT_PULLUP et anti-rebond logiciel pour un fonctionnement fiable.
Compteur de personnes avec bouton et afficheur 7 segments
Compteur de personnes simple avec bouton et afficheur 7 segments cathode commune, utilisant Arduino Uno et anti-rebond logiciel pour un comptage précis.