Realizziamo una serratura a comando elettrico che si apre grazie ad un codice, sempre diverso, generato dal nostro cellulare sulla base di un algoritmo che tiene conto dell’orario.
Se siete clienti di una banca on-line, probabilmente già utilizzate un apparecchio chiamato “token” per accedere ai servizi di home-banking o per autorizzare le operazioni.
Questi dispositivi, spesso simili a dei portachiavi, sono dotati di un display sul quale appare -ogni tot secondi o alla pressione di un tasto- un codice numerico sempre differente chiamato OTP (one-time password); il codice è tipo un rolling-code dei radiocomandi a elevata sicurezza e viene generato con un algoritmo pseudo-casuale che tiene conto anche del timestamp, ossia dell’orario attuale.
Recentemente hanno iniziato a diffondersi anche i soft-token, ovvero applicazioni per smartphone che generano i medesimi codici senza la necessità di avere con sè un ulteriore dispositivo fisico.
Il progetto che vi presentiamo in questo articolo vi consentirà di realizzare una serratura che può essere aperta inserendo, tramite un tastierino alfanumerico, un codice generato da un’applicazione presente sul vostro smartphone.
Come vedremo sarà possibile, tramite semplici modifiche allo sketch di Arduino, legare una serratura ad uno o più cellulari e modificarne il comportamento.
Schema elettrico serratura elettronica con Arduino
Il codice OTP
La generazione dei codici OTP parte da alcuni dati iniziali cui viene applicato un algoritmo, ovvero una serie di operazioni matematiche che trasformano tali dati in un codice numerico.
L’algoritmo è deterministico: partendo dai medesimi dati iniziali, si ottiene sempre lo stesso codice.
Perché il codice generato cambi, è quindi necessario che almeno uno dei dati di partenza sia variabile; allo scopo i token più diffusi utilizzano come dato variabile il numero di clic sul pulsante (quindi ad ogni pressione del pulsante viene generato un nuovo codice) oppure un valore legato a data e ora attuali.
Non c’è normalmente comunicazione diretta tra chi genera i codici (nel nostro caso l’applicazione sul cellulare) e chi li valida (la serratura): la verifica del codice inserito avviene grazie al fatto che entrambi condividono gli stessi dati di partenza e lo stesso algoritmo e quindi possono, in ogni istante, generare il medesimo codice (vedi Fig. 1).

Fig. 1
Esistono diversi algoritmi per la generazione dei codici e alcuni produttori utilizzano, inoltre, sistemi chiusi, rendendo i propri token compatibili solo con applicazioni “certificate”.
Per il nostro progetto, abbiamo deciso di adottare un algoritmo open, definito dalla specifica RFC6238 – “TOTP: Time-Based One-Time Password Algorithm” in questo modo sarà possibile generare i codici da una qualsiasi applicazione o token fisico compatibile con tale specifica.
L’algoritmo si basa su una chiave segreta (shared secret) e sul valore di timestamp Unix, ovvero il numero di secondi trascorsi dalla data Epoch, corrispondente alla mezzanotte del giorno 01/01/1970. Molto importante, lo vedremo nuovamente in seguito, è che tale timestamp sia espresso secondo il fuso orario UTC e che smartphone e serratura siano sincronizzati proprio con l’orario.
Se ormai tutti i cellulari si mantengono sincronizzati automaticamente via Internet, per la nostra serratura sarà fondamentale avere a disposizione un “orologio” quanto più preciso possibile, che nello specifico otteniamo con un modulo RTC.
Per generare dei codici che variano ogni n secondi, si divide il timestamp per la durata in secondi desiderata e si prende il solo quoziente della divisione: tale numero sarà costante per tutta la durata dell’intervallo. Nella Tabella 1 vediamo alcuni esempi per capire meglio il meccanismo.

Tabella 1
L’hardware della serratura
La serratura che realizzeremo sarà basata su una scheda Arduino, al quale applicheremo uno shield cui collegheremo:
• un tastierino alfanumerico a membrana per l’inserimento dei codici;
• un display seriale per visualizzare lo stato della serratura e i codici inseriti;
• un relé per attivare un carico esterno (ad esempio una elettroserratura) se il codice inserito è corretto;
• un buzzer per generare segnalazioni acustiche;
• due LED (uno rosso e l’altro verde) per visualizzare lo stato della serratura;
• un RTC (real-time clock) per avere a disposizione sempre un valore di timestamp aggiornato e corretto;
• una batteria tampone per alimentare l’RTC anche se la scheda non è alimentata.
Per rendere più facile la realizzazione del progetto, abbiamo preparato uno shield che comprende tutti i componenti sopra elencati, il cui schema elettrico è illustrato in queste pagine.
Il Real Time Clock è un integrato DS1307 della Maxim/Dallas e si avvale di un quarzo (Q1) da 32.768 kHz che fornisce la frequenza base per l’oscillatore interno; l’integrato è un contatore BCD che conta secondi, minuti, ore, giorni, mesi e anni, provvisto di 56 byte di RAM statica non volatile; il componente determina automaticamente quali sono i mesi con meno di 31 giorni e ad effettuare la correzione per l’anno bisestile.
L’orologio può operare nelle modalità 12 o 24 ore, con indicazione delle ore antimeridiane (AM) e di quelle pomeridiane (PM). Le informazioni sull’ora e la data vengono collocate in un apposito registro e trasferite all’esterno al microcontrollore di Arduino mediante l’I²C-bus del quale il chip è provvisto; Arduino fa da unità master dell’I²C-Bus, mentre il chip della Maxim-Dallas è lo slave.
Oltre a ciò, il DS1307 dispone di un’uscita di clock programmabile: più esattamente, rende disponibile un’onda quadra ricavata dalla frequenza di clock dell’orologio (determinata, a sua volta, dal quarzo da 32.768 kHz collegato ai piedini 1 e 2) che, mediante un apposito divisore interno, può essere divisa di frequenza ottenendo 1 Hz, 4.096 kHz, 8.192 kHz o l’intero clock.
Le frequenze ottenibili non sono state scelte a caso: per esempio, 1 Hz può servire a far lampeggiare i due punti o il punto dei secondi di un eventuale display che mostra l’ora, in un’applicazione da orologio stand-alone.
La condizione dell’uscita di clock ausiliario (SQWE, piedino 7) si definisce impostando opportunamente lo stato logico dei bit RS0 (0) ed RS1 (1) del registro di controllo, secondo quanto mostrato nell’apposito riquadro; ad esempio, 1 Hz si ottiene con entrambi i bit a zero. Si noti che quando sia il quarto (SQWE) che il settimo bit (OUT) si trovano a zero logico, l’uscita di clock si pone fissa a livello basso; se, invece, il bit 7 è ad uno logico e il 4 a zero, l’uscita assume costantemente lo stato alto.
Nel nostro shield l’uscita SQW pilota in modo sink un LED, facendolo pulsare alla stessa frequenza dell’onda quadra prodotta; inoltre, tramite il ponticello JSQW possiamo decidere se far leggere o no ad Arduino, tramite la linea A3, il segnale corrispondente.
Come accennato, questo clock ausiliario può servire per attivare dei visualizzatori o scandire certe sequenze: per esempio far suonare un cicalino ogni secondo, il tutto senza impegnare Arduino in routine di temporizzazione.
Il DS1307 dispone anche di un circuito di controllo in grado di verificare la mancanza o l’insufficienza dell’alimentazione principale (Vcc) e fare in modo che la tensione occorrente al proprio funzionamento venga prelevata dalla batteria di backup, nel nostro caso una pila a bottone CR2032 da 3 V, che garantisce un’autonomia di circa 6 mesi in assenza di alimentazione e che deve essere collegata tra il piedino 3 (Vbat) e la massa (pin 4, ossia GND).
La sezione di controllo dell’alimentazione è dimensionata in modo da svolgere due compiti: preservare la memoria in cui sono contenuti i dati sull’ora e la data attuali e mantenere attivo il contatore dell’orologio. Il primo viene svolto conservando nella RAM non volatile le informazioni corrispondenti, mentre il secondo è espletato dall’alimentazione di riserva presa dalla pila o batteria tampone collegata fra il piedino 3 e il 4.
La sezione di controllo dell’alimentazione interviene sulle altre funzioni del DS1307, bloccando la comunicazione con l’I²C-bus e la generazione dell’eventuale segnale di clock ausiliario SQW, in modo da minimizzare il consumo di energia ed estendere quanto più possibile l’autonomia.
L’intervento della protezione avviene quando la tensione letta tra il piedino dell’alimentazione principale (8) e massa (4) è minore di 1,25 volte la tensione della pila.
Il modulo RTC, che deve essere alimentato con una tensione continua ben stabilizzata del valore di 5 volt, assorbe una corrente (davvero esigua) dell’ordine di 1,5 milliampere, che scende a 500 nA quando ad alimentarlo è la pila. I 5 volt vengono prelevati dall’omonima linea di Arduino (5V).
Per conoscere l’ora e la data, Arduino deve interrogare il DS1307 mediante l’I²C-bus di cui il chip è provvisto; ad ogni interrogazione, il DS1307 risponde inviando all’ATmega (sempre lungo il suo bus I²C) la risposta e le informazioni su ora e data. Nel nostro shield l’RTC è quindi collegato ai due pin SDA e SCL di Arduino; le due resistenze da 1 kohm R2 ed R3 fungono da resistenze di pull-up per il bus I²C, che serve al microcontrollore ATmega di Arduino a interrogare il DS1307 per chiedergli l’orario e leggerlo.
Il relé è comandato dal pin 13 di Arduino tramite il transistor T1; mentre il diodo D1 serve a sopprimere la tensione inversa che la bobina del relé genera quando il transistor va in interdizione.
Il LED LD4, collegato con la sua resistenza in serie e a sua volta in parallelo alla bobina del relé, si accende quando RL1 è attivo. Due ulteriori LED, uno rosso e uno giallo, sono collegati ai pin 11 (LD3) e 12 (LD2) di Arduino tramite due resistenze di limitazione della corrente. Il cicalino viene pilotato dal pin 6 di Arduino.
Sullo shield, infine sono presenti due connettori a strip: uno a 8 pin cui collegare la tastiera a membrana e uno a 3 pin a cui collegare il display LCD a interfaccia seriale. La morsettiera tripolare consente invece di collegare un carico esterno al relé: il contatto centrale della morsettiera è il normalmente chiuso (NC), mentre quelli laterali sono il contatto normalmente aperto (NO) e quello comune (C).
Piano di montaggio
Elenco componenti
R1: 470 ohm R2: 4,7 kohm R3: 4,7 kohm R4: 10 kohm R5: 4,7 kohm R6: 100 ohm R7: 470 ohm R8: 470 ohm R9: 1 kohm C1: 100 nF ceramico C2: 220 µF 16 VL elettrolitico D1: 1N4148 LD1: LED 5mm verde LD2: LED 5mm giallo LD3, LD4: LED 5mm rosso T1: BC547 RL1: Relé minaitura 5V BUZ1: Buzzer senza elettronica Q1: Quarzo 32,768 kHz BATT: Porta batteria CR2032 U1: DS1307 LCD: Display LCD seriale Varie: - Morsetto 3 vie - Strip maschio 2 vie - Strip maschio 3 vie - Strip maschio 8 vie - Strip Maschio/Femmina 6 vie - Strip Maschio/Femmina 8 vie (2 pz.) - Strip Maschio/Femmina 10 vie - Strip Maschio/Femmina 2x3 vie - Zoccolo 4+4 - Jumper - Batteria CR2032 - Tastiera a membrana 4x4 - Circuito stampato S1234
Lo sketch della serratura con OTP
Codice Serratura Elettronica con OTP
Lo sketch da installare in Arduino è scaricabile dal link qui riportato dopo aver fatto il login. Per la sua compilazione, è necessario installare tre librerie:
• keypad;
• RTClib;
• TOTP Library.
Tutte le librerie posso essere installate tramite il Library Manager incluso nelle versioni più recenti dell’IDE di Arduino; dal menu Sketch impartiamo il comando Include Library –> Manage Libraries. Inseriamo il nome della libreria nel campo di ricerca e, una volta trovata, clicchiamo sul pulsante Install come indicato in Fig. 2.
Analizziamo ora lo sketch, partendo dall’interfacciamento verso le periferiche esterne. Grazie allo shield, il tastierino alfanumerico viene automaticamente collegato a otto pin digitali di Arduino (2-3-4-5 per le righe, 7-8-9-10 per le colonne).

Fig. 2
Il Listato 1 mostra come viene utilizzata la libreria Keypad per leggere correttamente i tasti premuti: per prima cosa viene definita la dimensione della tastiera (4 righe x 4 colonne); quindi è configurato il suo layout (i vari tasti e la loro posizione) e infine i pin di Arduino a cui è collegata.
Una volta effettuata la corretta configurazione, all’interno dello sketch sarà possibile leggere il tasto premuto con l’istruzione keypad.getKey(): tale istruzione restituisce una variabile di tipo char contenente il simbolo del tasto premuto o la costante NO_KEY se non è stato premuto alcun tasto.
Il display LCD scelto per il progetto è di tipo seriale, ovvero è possibile controllarlo con un solo pin digitale di Arduino inviando semplici istruzioni. Per non impegnare la seriale hardware di Arduino (utilizzata, come vedremo in seguito, per poter configurare l’RTC), all’interno dello sketch è stata definita una seriale software che utilizza il pin A2 come pin di trasmissione dati (TX) verso il display. Inviando via seriale un carattere al display, questo lo visualizza nella posizione corrente del cursore, spostando poi quest’ultimo di un carattere a destra o sulla riga sottostante se si è raggiunto la fine della riga.
Fa eccezione il carattere 254 (0xFE) che consente di inviare al display un comando e il carattere 124 (0x7C) che consente di regolare l’intensità della retroilluminazione.
Nello sketch vengono utilizzati i comandi per spostare il cursore all’inizio della prima riga (comando 128) e all’inizio della seconda riga (comando 192) come illustrato nel Listato 2.
Listato 1
// configurazione della tastiera #define KEY_ROWS 4 #define KEY_COLUMNS 4 char keys[KEY_ROWS][KEY_COLUMNS] = { {‘1’,’2’,’3’,’A’}, {‘4’,’5’,’6’,’B’}, {‘7’,’8’,’9’,’C’}, {‘*’,’0’,’#’,’D’} }; byte rowPins[KEY_ROWS] = {5, 4, 3, 2}; byte colPins[KEY_COLUMNS] = {10, 9, 8, 7}; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEY_ROWS, KEY_COLUMNS);
Listato 2
void pulisciSchermo() { displaySerial.write(254); displaySerial.write(128); displaySerial.write(“ “); displaySerial.write(“ “); } void aggiornaSecondaRiga() { displaySerial.write(254); displaySerial.write(192); displaySerial.write(“PIN --> “); displaySerial.write(254); displaySerial.write(200); for(int i = 0; i <= codiceIndex; i++) displaySerial.write(codiceInserito[i]); }
Il buzzer scelto non è di tipo attivo, quindi per emettere una nota acustica dobbiamo alimentarlo con una tensione variabile unidirezionale (o anche alternata) alla frequenza della nota desiderata; nel nostro caso ci viene in aiuto la funzione tone(pin, frequenza) di Arduino, che consente di generare sul pin indicato un’onda quadra della frequenza specificata.
Nel nostro caso l’istruzione utilizzata è tone(PIN_BUZZER, 440); che fa generare ad Arduino un’onda quadra alla frequenza di 440 Hz, allo scopo di far emettere al cicalino una nota acustica corrispondente al “La internazionale”, vale a dire la frequenza del diapason (LA4). Il pin è chiamato come definito nell’inizializzazione degli I/O di Arduino, all’interno del setup.
Vediamo ora la parte più importante dello sketch: all’interno del loop() viene continuamente verificato se è stato ricevuto un nuovo carattere via seriale o se è stato premuto un tasto sul tastierino numerico. Nel primo caso, il carattere viene aggiungo ad un buffer e, se si stratta del carattere di NEWLINE (0x0A), si passa ad interpretare il comando ricevuto.
Nel secondo caso, la nuova cifra inserita viene aggiunta ad un buffer e, se si è completato il codice di 6 cifre; tale codice viene verificato. Possono verificarsi due casi particolari: alla pressione del tasto * viene cancellata l’ultima cifra inserita, mentre alla pressione del tasto # viene cancellato l’intero codice fin qui inserito.
Le righe di codice che riguarda la verifica del codice inserito con la tastiera è quello che trovate nel Listato 3; commentiamolo brevemente: per prima cosa viene letto il valore di timestamp attuale dall’RTC. Quindi questo viene diviso per 30, corrispondente all’intervallo di validità di ogni codice.
Quindi, grazie alla funzione totp.getCodeFromSteps(), vengono generati i 3 codici OTP relativi all’intervallo attuale, a quello precedente e a quello successivo; l’utilizzo di tre codici consente infatti un piccolo disallineamento tra l’orario presente nell’RTC e quello del cellulare. I tre codici sono quindi confrontati con quello inserito via tastiera e, se uno corrisponde, la serratura viene aperta.
Listato 3
DateTime now = rtc.now(); long GMT = now.unixtime(); long timeStep = GMT / 30; bool codiceOk = false; for(int i = -1; i <= 1; i++) { har* codiceGenerato = totp.getCodeFromSteps(timeStep + i); if(strcmp(codiceInserito, codiceGenerato) == 0) codiceOk = true; }
Setup
Per poter utilizzare la serratura, per prima cosa è necessario installare sul proprio smartphone una applicazione in grado di generare codici OTP con l’algoritmo scelto.
Per iOS ed Android è possibile installare dal relativo market l’applicazione Google Authenticator. Tutte le applicazioni sono gratuite:
• Google Authenticator per iOS
• Google Authenticator per Android
Come spiegato all’inizio dell’articolo, è necessario che applicazione e sketch su Arduino coindividano la medesima chiave privata per poter generare gli stessi codici; per semplificare la configurazione abbiamo preparato un’applicazione web all’indirizzo http://www.lucadentella.it/OTP/.
Dopo aver inserito una password di dieci caratteri a piacere, premere il pulsante GO: apparirà l’array da inserire in Arduino e codice o QRCode per configurare l’app. É anche possibile cambiare il nome dell’account che sarà visualizzato dall’app al di sotto dei codici generati (Fig. 3). Il valore del campo Arduino HEX array va riportato nel file CONFIG.h dello sketch (Fig. 4).

Fig. 3

Fig. 4
Mentre per configurare l’app sarà possibile –dal menu di aggiunta nuovo account– decidere di inserire manualmente il codice o di inquadrare con la fotocamera del telefono il QRCode per una configurazione automatica (Fig. 5).
In entrambi i casi, una volta ultimata la configurazione l’applicazione inizierà a generare i codici (Fig. 6).
Dobbiamo infine verificare l’orario presente sull’RTC, ricordando che deve essere quanto più possibile sincronizzato con quello dello smartphone e secondo il fuso orario UTC (non è invece necessario che lo smartphone sia configurato su tale fuso orario perché è l’applicazione stessa a fare la corretta conversione rispetto all’ora locale).

Fig. 5

Fig. 6
Lo sketch consente di configurare l’RTC tramite comandi seriali: apriamo il Serial Monitor e configuriamolo per 9.600 baud con Newline come line ending (Fig. 7). Se inviamo il carattere?, lo sketch determinerà la visualizzazione dell’orario corrente (Fig. 8).
Se tale orario non è corretto, è possibile aggiornarlo inviando il comando !ggMMaahhmmss.
Ad esempio per configurare il giorno 01/02/2016 alle 10:30:20 il comando da inviare sarà !010216103020. Se il comando è corretto, Arduino risponderà con la conferma della configurazione e visualizzerà il nuovo orario (Fig. 9).

Fig. 7

Fig. 8

Fig. 9
Configurazione della serratura
Lo sketch scritto per il progetto consente alcune personalizzazioni, effettuabili modificando il file CONFIG.h. Per prima cosa, è possibile modificare il comportamento della serratura scegliendo tra due diverse modalità alternative l’una all’altra:
• MODO_IMPULSO = la serratura rimane aperta per tot millisecondi e poi si chiude automaticamente;
• MODO_STABILE = la serratura rimane aperta fino alla pressione di un tasto.
Se è stata scelta la modalità IMPULSO, è possibile cambiare la costante TEMPO_APERTURA per definire il tempo (specificare il numero di millisecondi) in cui la serratura rimarrà aperta a seguito di ogni attivazione del relé. Se invece si è scelta la modalità STABILE, è possibile cambiare la costante TASTO_CHIUSURA per scegliere quale tasto sarà utilizzato per chiudere la serratura (molto importante è che il tasto scelto sia sempre indicato tra apici singoli!).
Infine è possibile disattivare il suono del buzzer commentando la riga #define BUZZER_ON.
Detto ciò concludiamo ricordando che il relé montato sullo shield permette di gestire utilizzatori che assorbano fino a 1 ampere in circuiti funzionanti al massimo a 60 Vcc: quindi elettroserrature che tipicamente vanno a 12/24 Vcc o ca. Se intendete gestire carichi di maggior potenza dovete utilizzare un servo relé di cui alimentare la bobina attraverso lo scambio C/NO del relé posto sullo shield, che utilizzerete quindi come interruttore. L’isolamento galvanico sarà assicurato dal servo relé.