Controllo accessi di un gruppo di armadietti

SOMMARIO

Questo progetto rappresenta il primo di alcuni sottoprogetti a complessità crescente; il risultato è comunque pienamente utilizzabile in modo indipendente dallo sviluppo dei due sottoprogetti successivi.
Si propone di realizzare un semplice dispositivo di controllo accessi di un sistema di armadietti (per esempio di uno spogliatoio di una palestra o di luoghi pubblici in genere), non assegnati in maniera personalizzata e occupati dagli utenti per un tempo limitato.

PRINCIPALI MATERIALI UTILIZZATI

MFRC-522 RC522 RFID Modulo IC Card
Componente molto economico, ma ai test, risultato molto affidabile e dotato di una notevole libreria di applicazioni. E' possibile realizzare operazioni di lettura e scrittura di transponder a 13,56MHz; richiede un'alimentazione a 3.3V.
ATMEGA328-PU MCU 8 bit, 20 MHz, 1kB
RFID Chip con 13,56 MHz Transponder MIFARE Classic (1kbytes)
RFID PVC Card 13,56 MHz Transponder MIFARE Classic (1kbytes)
12V DC 0.43A Cabinet Drawer Electric Door Lock Assembly Solenoid Lock 27x29x18mm
Mini bullone elettrico 12V DC 0.43A serratura Push pull solenoide cilindrico serratura 5mm corsa

CONTESTO D'USO

Si immagina di elettrificare un gruppo di armadietti, dotandoli, sull'incontro dello sportello di un blocco a solenoide, del tipo degli esempi mostrati sopra; sempre nell'incontro si inserisce, il dispositivo di Fig.6 del progetto Controllo Accessi, modificato come da Fig.1.
Al pin D2 si collega un micro-bottone di Programmazione (che deve risultare accessibile solo dall'interno dello sportello, al pin D3 un Led Verde, al pin D4 un Led Rosso, entrambi visibili all'esterno sull'incontro dello sportello; viene anche aggiunto un diodo di ricircolo fra VIN e l'uscita D7 Open Collector.

Fig.1

Un risultato è mostrato nelle Figg. 2, 3, 4 e 5 (è una realizzazione utile per il debug, va ingegnerizzato ulteriormente per il montaggio sullo sportello.

Fig.2 Fig.3
Fig.4 Fig.5

Il piccolo add-on di Figg.4 e 5 si collega al connettore J1 di Fig.1 e permette di connettere il modulo USB per operazioni di programmazione e debug.
Nella versione ingegnerizzata il lato frontale del modulo RFID deve essere accessibile sull'incontro dell'armadietto, anche attraverso un involucro protettivo, che però non deve essere metallico.

PRINCIPIO DI FUNZIONAMENTO

  • Tenendo premuto il tasto di programmazione (giallo nella foto) per 5 secondi comincia a lampeggiare il led rosso;
  • avvicinando una RFID Card essa viene memorizzata in modo non volatile come Passepartout Card; il successo viene segnalato dal led verde;
  • sarà il Superuser del sistema a disporre della Passepartout Card (una tessera RFID del tipo PVC Card per evitare di confonderla con le User Card di tipo Chip);
  • il dispositivo elettromeccanico deve essere tale che chiudendo manualmente lo sportello si realizzi il blocco;
  • dando un impulso al solenoide il blocco si ritira e lo sportello si socchiude in modo tale che terminato l'impulso lo sportello rimanga aperto.
  • l’armadietto è libero quando il led verde è acceso; lo sportello dell’armadietto può essere indifferentemente aperto o chiuso;
  • tutti gli utenti dispongono di una User Card (detenuta permanentemente o presa temporaneamente da un contenitore comune all'ingresso dell'area di utilizzo degli armadietti);
  • avvicinando una qualunque RFID Card viene dato il consenso all’apertura dello sportello (l'impulso è impostato per un secondo, ma può essere variato in funzione della soluzione elttromeccanica adottata);
  • il codice della RFID Card viene memorizzato in modo non volatile, si spegne il led verde e si accende il led rosso;
  • adesso l’armadietto è occupato;
  • l'utente può riporre la sua roba nell'armadietto e quando quest'ultimo viene chiuso, un nuovo consenso di apertura può essere dato solo o dalla RFID Card che l’ha reso occupato o dalla Passepartout Card;
  • dopo tale apertura l’armadietto è di nuovo libero ;
  • l’ultima operazione realizzata si mantiene anche se viene a mancare l’alimentazione.

CONNESSIONE AL SOLENOIDE

Dai dati di targa, i solenoidi dell'elenco componenti potrebbero essere collegati direttamente ai terminali VIN e OC_D7 del connettore J4, essendo di circa 600mA la corrente massima ammissibile. Alimentati direttamente a 12 Volt con l'inserzione di un amperomentro, tuttavia, il Cabinet Drawer Electric Door Lock Assembly ha fatto effettivamente misurare un assorbimento di circa 400mA, mentre il secondo Mini bullone elettrico un assorbimento di oltre 900mA (mai fidarsi dei dati di targa di questi componenti low cost). Quindi, per usare il secondo solenoide, occorrerebbe cambiare il transistore di potenza con uno più performante o, più predentemente, frapporre un microrelè a 12 Volt, che piloti il solenoide, come da Figg. 9 e 10 del progetto Controllo Accessi.
Nel caso del prototipo di test, si è optato per usare il primo solenoide, che si è rivelato anche più promettente per l'integrazione meccanica di una ingegnerizzazione successiva. Il risultato d'insieme è mostrato in Fig.6.

Fig.6

PROGRAMMAZIONE E TEST

Il codice che realizza il funzionamento descritto precedentemente è mostrato qui di seguito:

/*
   -------------------------------------------
   Controllo Armadietto con Passepartout Card
   -------------------------------------------
  Mappa della EEPROM:
  00      Flag Passepartout card: AA = Passepartout card definita
  01      Flag User card (armadietto occupato anche al reset): AA = User card definita  
  02-05   Memorizzazione Passepartout card
  06-09   Memorizzazione User card
*/
#include <EEPROM.h>     // Libreria di gestione EEPROM
#include <SPI.h>        // Protocollo SPI
#include <MFRC522.h>  // Libreria per il dispositivo Mifare RC522
constexpr uint8_t Consenso = 7;   // Pin dei LED rosso
constexpr uint8_t Led_Rosso = 4;   // Pin dei LED rosso
constexpr uint8_t Led_Verde = 3;   // Pin dei LED verde
constexpr uint8_t progBtn = 2;     // Tasto di programmazione
boolean match = false;          // initializza card match a falso
boolean statusFlag;  // vero se l'armadietto è libero; falso se occupato
boolean userCardSelect = false;  // initializza userCardSelect a falso
boolean replaceMaster = false;
uint8_t successRead;    // Variabile per Lettura corretta dal Lettore RFID
byte passCard[4];    // ID Pass Card
byte userCard[4];    // ID utente corrente
// Inizializza Lettore RFID MFRC522
MFRC522 mfrc522(10, 9);
void setup() {   
    delay(500);
//Configurazione del microcontrollore
    pinMode(Led_Rosso, OUTPUT);
    pinMode(Led_Verde, OUTPUT);
    pinMode(Consenso, OUTPUT);
    pinMode(progBtn, INPUT_PULLUP);   // Abilita pull-up   
    digitalWrite(Led_Rosso, HIGH);    
    digitalWrite(Led_Verde, HIGH);          
//Guadagno Antenna al massimo aumenta la distanza di lettura
  mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
  digitalWrite(Consenso, LOW);// Consenso negato  
// Controlla che una passCard sia stata definita
    if (EEPROM.read(0) == 170){
      IDCardRead(2, passCard); // memorizza ID nel vettore passCard      
    }
// Controlla che al reset una User Card non sia già definita
// L'indirizzo 1 della EEPROM contiene il flag '170' = AA se User card definita
    if (EEPROM.read(1) == 170){
// Armadietto occupato
      digitalWrite(Led_Rosso, LOW);    // Led Rosso acceso
      digitalWrite(Led_Verde, HIGH);  // Led Verde spento
      statusFlag = false;
      IDCardRead(6, userCard); // memorizza l'ID nel vettore userCard       
    }
    else {
      // Armadietto libero
      digitalWrite(Led_Rosso, HIGH);    // Led Rosso spento
      digitalWrite(Led_Verde, LOW);  // Led Verde acceso
      statusFlag = true;    
    }
}
void loop() { 
    SPI.begin();
    mfrc522.PCD_Init();
// se viene premuto il tasto programmazione per più di 5 secondi,
// si comanda la programmazione della ID di Pass Card
      if (digitalRead(progBtn) == LOW) { // Controlla che il tasto prog sia premuto      
// In caso di tasto premuto
        digitalWrite(Led_Rosso, LOW);  // accende il Led Rosso: inizio programmazione Pass Card
        digitalWrite(Led_Verde, HIGH);  // spegne il Led Verde
        bool buttonState = monitorProgButton(5000); // Attesa dei 5 secondi
        if (buttonState == true && digitalRead(progBtn) == LOW) {    
// se il Tasto è ancora premuto, cancella la flag della Pass Card
          EEPROM.write(0, 0); // Cancella flag di Pass Card all'indirizzo 0 EEPROM
// Pass Card
          do {
            successRead = getID();//se lettura corretta successRead = 1 altrimenti = 0
// Lampeggio del Led Rosso in attesa della lettura della Pass Card
            digitalWrite(Led_Rosso, LOW);    // accende il Led Rosso
            delay(200);
            digitalWrite(Led_Rosso, HIGH);  // spegne il Led Rosso
            delay(200);
          }
 // il programma non va avanti fino a che non viene letta la Pass Card correttamente
          while (!successRead); 
 // Memorizzazione della Pass Card ID, contenuto nel vettore readCard, 
 // nella EEPROM a partire dall'indirizzo 2          
          EEPROM.write(0, 170); // configura il flag Pass Card definita
          for ( uint8_t j = 0; j < 4; j++ ) {       
            EEPROM.write( 2 + j, mfrc522.uid.uidByte[j] );
            passCard[j] =  mfrc522.uid.uidByte[j];
          }
          digitalWrite(Led_Verde, LOW);  // accende il Led Verde          
        }    
      } 
 // Verifica se una Card è stata rilevata
    if (mfrc522.PICC_IsNewCardPresent()){
      if (mfrc522.PICC_ReadCardSerial()) {
// Lettura effettuata
      boolean contr_flg = true; // initializza contr_flg a vero  
      if(EEPROM.read(0) == 170){
// Una Passpartout Card e' stata definita         
        if(CompareVector(mfrc522.uid.uidByte, passCard, 0, 4)) {
// La card letta e' la Passpartout
          granted(500); // consenso all'apertura per 500 ms in ogni caso
          freeMode();
          EEPROM.write( 1, 0);
          statusFlag = true;           
          contr_flg = false; // elimina altri controlli successivi                      
        }
      }
      if(contr_flg){
// La card letta e' una User Card                
        if (statusFlag) {
// Armadietto libero                            
          granted(500); // consenso all'apertura per 500 ms in ogni caso
// Perciò deve diventare occupato          
// Memorizzazione del currCard ID, contenuto nel vettore readCard,
// nella EEPROM a partire dall'indirizzo 6    
          for ( uint8_t j = 0; j < 4; j++ ) {       
            EEPROM.write( 6 + j, mfrc522.uid.uidByte[j] );
            userCard[j] = mfrc522.uid.uidByte[j];
          }   
          statusFlag = false;
          EEPROM.write( 1, 170);
          occupiedMode();               
        }
        else {
// Armadietto occupato
// Controlla se la card letta è quella corrente
          if (CompareVector(mfrc522.uid.uidByte, userCard, 0, 4)) {                  
// La card letta è quella corrente
            granted(500); // da'  il consenso all'apertura per 500 ms
            statusFlag = true; // libera l'armadietto
            freeMode();
            EEPROM.write( 1, 0);                   
          }
          else {      
// La card letta NON è nella lista memorizzata
            denied();
          }
        }
      }
      }
    }
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();    
}
//////////// Controlla i bytes di due vettori //////////// 
boolean CompareVector(byte *x, byte *z, byte inz, byte dv) {
    byte j;   
    boolean flg = true;
    for (j = inz; j
      if(x[j] != z[j]) flg = false;           
    }
    return flg;
}
//////////// Accesso concesso //////////// 
void granted ( uint16_t setDelay) {
  digitalWrite(Consenso, HIGH);     // Consenso abilitato 
  delay(setDelay);          // Tieni il consenso per il tempo selezionato
  digitalWrite(Consenso, LOW);    // Consenso negato
  delay(1000);            // aspetta un secondo
}
//////////// Accesso negato //////////// 
void denied() {
  digitalWrite(Led_Verde, HIGH);   // spegni il Led Verde
  digitalWrite(Led_Rosso, HIGH);   //  spegni il Led Rosso
  delay(500); // aspetta mezzo secondo
  digitalWrite(Led_Rosso, LOW);   //  accendi il Led Rosso
  delay(500); // aspetta mezzo secondo
  digitalWrite(Led_Rosso, HIGH);   //  spegni il Led Rosso
  delay(500); // aspetta mezzo secondo
  digitalWrite(Led_Rosso, LOW);   //  accendi il Led Rosso
  delay(3000); // attende la rimozione della Card per evitare una ripetizione immediata del segnale di diniego        
}
//////////// Acquisisci l'ID di una card //////////// 
uint8_t getID() {
  // Prepara la lettura di un ID
  if ( ! mfrc522.PICC_IsNewCardPresent()) { // se non c'è una card esci
    return 0; // segnala lettura non eseguita
  }
  //fino a che la lettura non è terminata correttamente esci
  if ( ! mfrc522.PICC_ReadCardSerial()) {   
    return 0; // segnala lettura non esguita
  }
  // Si legge la card a 4 bytes
  // Non supporta la lettura della card a 7 bytes
  mfrc522.PICC_HaltA(); // termina lettura
  return 1;  // segnala lettura eseguita
}
//////////// Read an ID from EEPROM //////////// 
void IDCardRead(uint8_t iin, byte IDCard[4]){
  for ( uint8_t i = 0; i < 4; i++ ) {      // Leggi l'ID Card dalla EEPROM
    IDCard[i] = EEPROM.read(iin + i);    // salva l'ID nel vettore IDCard
  }
}
////////////  Led in Modo Occupato //////////// 
void occupiedMode () {
  digitalWrite(Led_Rosso, LOW);  // accende il Led Rosso
  digitalWrite(Led_Verde, HIGH);  // spegni il Led Verde
  digitalWrite(Consenso, LOW);    // Consenso negato
// attende la rimozione della Card per evitare lo sblocco immediato
  delay(3000); 
}
//////////// Led in Modo Libero //////////// 
void freeMode () {
  digitalWrite(Led_Rosso, HIGH);  // spegne il Led Rosso
  digitalWrite(Led_Verde, LOW);  // accende il Led Verde
  digitalWrite(Consenso, LOW);    // Consenso negato
  // attende la rimozione della Card per evitare il blocco immediato
  delay(3000);  
}
//////////// Test del Tasto di Programmazione //////////// 
bool monitorProgButton(uint32_t interval) {
  uint32_t now = (uint32_t)millis();
  while ((uint32_t)millis() - now < interval)  {
    // check on every half a second
    if (((uint32_t)millis() % 500) == 0) {
      if (digitalRead(progBtn) != LOW)
        return false;
    }
  }
  return true;
}  

Questo progetto, visto il contesto di utilizzo, prevede solo minime precauzioni per la sicurezza e la prevenzione da comportamenti fraudolenti: nei prossimi progetti affineremo tecniche di miglioramento della protezione e della sicurezza di accesso, contro intrusioni, sniffing e clonazione carte.

Progetto connesso: Controllo accessi su aree ristrette.