Timetable Corner
Ce projet a été réalisé pendant la deuxième semaine d’intersemestre 2015 au Téléfab par Mina HE, Axel BAUDOT, Huu Trung THIEU et Tianshu YANG.
Constat
Pour les élèves de Télécom Bretagne, consulter leurs emplois du temps est fastidieux : le retrouver sur internet implique de s’authentifier, et de suivre de nombreux liens avant de trouver l’information qu’ils cherchent.
Cela est d’autant plus génant lorsque l’on souhaite savoir à la dernière minute (voire complètement en retard) dans quelle salle on doit se rendre.
Concept
Nous avons souhaité réaliser une borne qui, au passage du badge d’un élève, afficherait l’horaire et la salle de son prochain cours, et ce en accord avec les dernières informations disponible sur le site de l’école. C’est le Timetable Corner
Réalisation
Le lecteur de badge réalisé à partir d’une carte Arduino Uno utilise la technologie RFID/NFC pour identifier le badge.
L’école met à disposition des élèves un lien pour télécharger un emploi du temps au format iCalendar (.ics), à condition de posséder une clé pour identifier l’élève et accéder à son propre emploi du temps, sans besoin d’authentification. Un site web nous permet de stocker les profils des élèves, avec leurs identifiants de badges et de logiciel d’emploi du temps. Une fois que l’élève s’y est enregistré, le site sera capable de récupérer son prochain cours directement sur le site de l’école. Pour connaître son identifiant RFID, un élève peut passer son badge à la borne.
Au passage d’un badge, le circuit Arduino, muni d’une connection internet, envoie l’identifiant RFID du badge vers notre serveur, qui récupèrera sur les informations sur le site de l’école avant de les renvoyer vers le boîtier.
Le prochain cours est ensuite affiché sur un petit écran LCD.
La réalisation de ce projet a nécessité le recours au matériel suivant :
- Une carte Arduino
- Arduino ethernet board
- MicroRWD MF LP module
- Une 1uH antenne
- Un écran LCD
- RTC module
- Des LED
- Un buzzer
- Une résistance de 100 Ω
- Des fils
- Une breadboard
- Deux résistances de 1kΩ
La partie NFC lecteur :
Pour lire les tags RFID, nous utilisons un module Micro RWD, dont la datasheet est disponible ici → http://www.ibtechnology.co.uk/pdf/MFprot_LP.PDF.
Nous avons réalisé le montage ci-dessous et l’avons relié à notre Arduino Uno qui pouvait ensuite récupérer les identifiants RFID des tags passés devant l’antenne.
Nous ne disposions pas d’une antenne de 1μF, mais avons pu en imprimer une dans le département micro-ondes de Télécom Bretagne. La partie suivante détail le procédé.
Fabrication de l’antenne :
Nous avons bénéficiés de techniques quasi-industrielles pour réaliser notre antenne. Une méthode plus accessible est expliquée ici → http://www.instructables.com/id/RFID-Reader-Detector-and-Tilt-Sensitive-RFID-Tag/step2/Building-the-RFID-Antenna/
Pour imprimer notre antenne, nous avons commencé par en déterminer les dimensions et la forme grâce au logiciel antenna, qui calcule immédiatement l’inductance de l’antenne possédant les propriétés géométriques données.
Une exemple de géométrie permettant d’obtenir 1μF est représenté sur la figure : une bande de 1mm de diamètre enroulé en deux spires rectangulaires de 67mm sur 40mm. 1mm d’espace entre les deux spires.
On commence par découper un masque opaque représentant notre antenne. On en couvre une plaque comportant une couche de cuivre couverte de résine.
En passant le tout sous des UVs, la résine qui n’est pas couverte par le masque va être dégradée tandis que le reste reste intacte.
Un bain permet de retirer la résine dégradée. Reste une couche de cuivre, de la résine couvrant uniquement la forme de notre antenne.
En pulvérisant un produit sur la plaque, on peut retirer le cuivre ainsi dévoilé. Un dernier bain permet de retirer la résine restante et d’obtenir le motif de cuivre désiré.
Code arduino pour lire l’identifiant du badge :
#include<SoftwareSerial.h> int rx=10; int tx=11; SoftwareSerial S4(rx,tx); int CTS=8; int pin2=12; char msg; byte message; byte message2; int s4read; int s4available; int controle=0; int id[5]; int z=0; void Lire(){ s4read=S4.read(); s4available=S4.available(); Serial.print("S4.available()"); Serial.println(s4available); Serial.print("S4.read()"); Serial.println(s4read); } void Wait() { while (digitalRead(CTS)!=0) { } } void setup() { pinMode(CTS,INPUT); pinMode(pin2,INPUT); Serial.begin(9600); S4.begin(9600); delay(200); message=B01010101; message2=B01010011; Serial.println(digitalRead(CTS)); Lire(); Wait(); S4.write(message); Lire(); Wait(); S4.write(message2); Lire(); } void loop() { //if (Serial.available()>0) if (digitalRead(pin2)==0) { msg='U'; // msg=Serial.read(); //Serial.print("msg=:"); //Serial.println(msg); Wait(); S4.write(msg); } while (S4.available()>0) { s4read=S4.read(); delay(10); s4available=S4.available(); if (controle<5) { id[controle]=s4read;} controle++; if (controle==5){ Serial.println("id:"); for (z=1;z<5;z++) { Serial.print(id[z],HEX); } Serial.println(); } } controle=0; id[0]=0;id[1]=0;id[2]=0;id[3]=0;id[4]=0; }
Code arduino de l’affichage :
/* created 28 Jan 2015 by THT */ //-------------include h file----------- #include <SPI.h> #include <Ethernet.h> #include <LiquidCrystal.h> #include <Wire.h> #include <Time.h> #include <DS1307RTC.h> //-------------------------------------- //------------global variables----------- //------------variables for web //Mac address byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x1C, 0xEA }; // IP address of the server IPAddress server(10,29,224,28); // Set the static IP address to use if the DHCP fails to assign IPAddress ip(192,168,0,177); // Initialize the Ethernet client library with the IP address and port of the server that you want to connect to (port 80 is default for HTTP): EthernetClient client; // Data receive String data; //--------------------variables for showing /* initialize the library with the numbers of the interface pins of LCD The circuit: * LCD RS pin to digital pin 3 * LCD Enable pin to digital pin 2 * LCD D4 pin to digital pin 6 * LCD D5 pin to digital pin 7 * LCD D6 pin to digital pin 8 * LCD D7 pin to digital pin 9 * LCD R/W pin to ground */ LiquidCrystal lcd(3, 2, 6, 7, 8, 9); String errorl1 = "Inscrivez-vous en ligne votre identifiant: "; //String errorl2 = " sur notre site nextclass.resel.fr"; String errorl2 = "nextclass.resel.fr"; // ID of the student, from rfid int ID_student; // information String date_classe; String hour_classe; String Lname = "THIEU"; String room = "B03-042"; String classes = "Projet fil rouge"; //data receive from rfid String data_rfid = ""; //-------------------------------------- //---------------functions-------------- //clear one row on LCD void clear_row(LiquidCrystal lcd, int row){ lcd.setCursor(0,row); lcd.print(" "); } //show class's infomation on LCD void show_data(){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Votre prochain "); lcd.setCursor(0,1); lcd.print("cours: "); delay(2000); lcd.clear(); lcd.setCursor(0,0); lcd.print(date_classe); lcd.setCursor(0,1); lcd.print(hour_classe); delay(2000); lcd.clear(); lcd.setCursor(0,0); lcd.print("Nom: "); lcd.print(Lname); lcd.setCursor(0,1); lcd.print("Salle: "); lcd.print(room); delay(2000); clear_row(lcd,1); lcd.setCursor(0,1); lcd.print("Cours: "); lcd.print(classes); delay(2000); for(int i = 6; i>=0 ;i--){ clear_row(lcd,1); lcd.setCursor(i,1); lcd.print(classes); delay(500); } for(int i = 1; i <= classes.length(); i++){ clear_row(lcd,1); delay(50); lcd.setCursor(0,1); lcd.print(classes.substring(i)); delay(500); } date_classe = ""; hour_classe = ""; Lname = ""; room = ""; classes = ""; } //show day on LCD void show_time_day(int day, int month, int year){ clear_row(lcd,1); lcd.setCursor(0,1); if (day < 10){ lcd.print("0"); lcd.print(day); } else lcd.print(day); String month_char; switch(month){ case 1: month_char = "Janvier"; break; case 2: month_char = "Fevrier"; break; case 3: month_char = "Mars"; break; case 4: month_char = "Avril"; break; case 5: month_char = "Mai"; break; case 6: month_char = "Juin"; break; case 7: month_char = "Juiller"; break; case 8: month_char = "Aout"; break; case 9: month_char = "Septembre"; break; case 10: month_char = "Octobre"; break; case 11: month_char = "Novembre"; break; case 12: month_char = "Decembre"; break; } lcd.print("-"); lcd.print(month_char); lcd.print("-"); //lcd.print("20"); lcd.print(year); } //show time on LCD void show_time_hour(int minute, int hour, int sec){ clear_row(lcd,0); lcd.setCursor(0,0); if (hour < 10){ lcd.print("0"); lcd.print(hour); } else lcd.print(hour); lcd.print(":"); if (minute < 10){ lcd.print("0"); lcd.print(minute); } else lcd.print(minute); lcd.print(":"); if (sec < 10){ lcd.print("0"); lcd.print(sec); } else lcd.print(sec); } //get time and print time void get_print_time(){ tmElements_t tm; //get time if (RTC.read(tm)) { show_time_hour(tm.Minute,tm.Hour,tm.Second); show_time_day(tm.Day,tm.Month,tmYearToCalendar(tm.Year)); } else { if (RTC.chipPresent()) { Serial.println("The DS1307 is stopped. Please run the SetTime"); Serial.println("example to initialize the time and begin running."); Serial.println(); } else { Serial.println("DS1307 read error! Please check the circuitry."); Serial.println(); }}} //setIP void setIP(){ Serial.println("Setting IP"); lcd.clear(); lcd.setCursor(0,0); lcd.print("Setting IP ..."); if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // no point in carrying on, so do nothing forevermore: // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); } // give the Ethernet shield a second to initialize: delay(1000); Serial.println("Setting IP finished"); lcd.setCursor(0,0); lcd.print("Setting IP finished"); delay(1000); } //get data from server boolean get_data(String rfid){ lcd.clear(); delay(100); lcd.setCursor(0,0); lcd.print("Connecting..."); char c,c_old; String data=""; int count=1; boolean flag = false; //connect to server Serial.println("connecting..."); if (client.connect(server, 80)) { Serial.println("connected"); // Make a HTTP request: //client.println("GET /?id=badge&pass=badgeedt&url=http://www.google.fr/search?q=arduino"); client.print("GET /?id=badge&pass=badgeedt&url=http://nextclass.resel.fr/next_course.php?rfid="); client.println(rfid); client.println("Host: 10.29.224.28"); client.println("Connection: close"); client.println(); } else { // kf you didn't get a connection to the server: Serial.println("connection failed"); } //connect successfully while (count <6){ if (client.available()) { c = client.read(); if (c == '#'){ if (c_old == '#'){ lcd.clear(); /* for(int i=15; i>=0; i--){ lcd.setCursor(i,0); lcd.print(errorl1); delay(500); } */ for(int i=0; i<= errorl1.length()-16; i++){ clear_row(lcd,1); delay(50); lcd.setCursor(0,0); lcd.print(errorl1.substring(i,i+16)); delay(500); } lcd.setCursor(0,1); lcd.print(rfid); delay(2000); lcd.clear(); lcd.setCursor(0,0); lcd.print("sur le site"); lcd.setCursor(0,1); lcd.print(errorl2); delay(1500); lcd.setCursor(0,1); lcd.print("extclass.resel.fr"); delay(1500); lcd.setCursor(0,1); lcd.print("xtclass.resel.fr"); delay(1500); client.stop(); return false; /* Serial.print(errorl1); Serial.print(rfid); Serial.println(errorl2); client.stop(); return false; */ } //delay(10); switch(count){ case 1: Serial.println(data); date_classe = data; //Serial.print("date_classe "); //Serial.println(date_classe); delay(10); break; case 2: Serial.println(data); hour_classe = data; //Serial.print("hour_classe "); //Serial.println(hour_classe); delay(10); break; case 3: Serial.println(data); room = data; //Serial.print("room "); //Serial.println(room); delay(10); break; case 4: Serial.println(data); Lname = data; //Serial.print("Lname "); //Serial.println(Lname); delay(10); break; case 5: Serial.println(data); classes = data; //Serial.print("classes "); //Serial.println(classes); delay(10); break; } count++; data=""; c_old=c; } else{ data +=c; c_old=c; } } // if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); //client.stop(); break; } } client.stop(); return true; } //-------------------------------------- void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } // set up the LCD's number of columns and rows: lcd.begin(16, 2); // start the Ethernet connection: setIP(); Serial.println("Welcome to our application"); Serial.println("Visite us at nextclass.resel.fr"); } void loop() { //Serial.println("a"); char data_temp; int count = 0; if((Serial.available() >0) && (count == 0)){ data_temp = Serial.read(); lcd.clear(); delay(100); data_rfid += data_temp; count++; lcd.setCursor(0,0); lcd.print("Votre ID: "); lcd.setCursor(0,1); lcd.print(data_rfid); //Serial.print("data_temp "); //Serial.println(data_temp); /* if (data_temp < 58) data_temp = data_temp - 48; else data_temp = data_temp - 55; */ //Serial.println(data_rfid); while (count < 8){ if(Serial.available() >0){ data_temp = Serial.read(); //Serial.print("data_temp "); //Serial.println(data_temp); /* if (data_temp < 58) data_temp = data_temp - 48; else data_temp = data_temp - 55; */ //data_rfid = (data_rfid <<4) + data_temp; data_rfid +=data_temp; count++; //Serial.println(data_rfid); lcd.setCursor(0,1); lcd.print(data_rfid); } } lcd.setCursor(0,1); lcd.print(data_rfid); delay(2000); if(get_data(data_rfid)){ Serial.print("Jour: "); Serial.println(date_classe); Serial.print("Temps: "); Serial.println(hour_classe); Serial.print("Nom: "); Serial.println(Lname); Serial.print("Salle: "); Serial.println(room); Serial.print("Coures: "); Serial.println(classes); show_data(); } count =0; data_rfid=""; } else{ get_print_time(); /* lcd.clear(); delay(100); lcd.setCursor(0,0); lcd.print("Welcome to TB"); lcd.setCursor(0,1); lcd.print("nextclass.resel.fr"); delay(1000); lcd.setCursor(0,1); lcd.print("extclass.resel.fr"); delay(1000); lcd.setCursor(0,1); lcd.print("xtclass.resel.fr"); delay(1000); */ } } <pre>
Le site web: http://nextclass.resel.fr/
Voici la clé ADE qu’on demande pour s’inscrire.
Il est demandé à l’élève de s’inscrire sur un site web, afin que nous puissions connaître l’identifiant RFID de son badge, et la clé nous servant à accéder à son emploi du temps.
Lorsqu’un élève passe son badge, une requête est envoyé vers notre site, comportant le RFID du badge passé. Une base de donnée associant RFID et clé élève nous permet de récupérer l’emploi du temps de l’étudiant au format iCalendar (.ics).
Le site traite ce fichier, en extrait le prochain cours, et renvoie une réponse vers le boîtier sous le format : date#heure de début-heure de fin#nom de l’élève#intitulé du cours
Un projet de parseur iCalendar en PHP est disponible ici : https://code.google.com/p/ics-parser/
Conclusion et perspectives
Le Timetable corner permet de consulter son prochain cours d’un seul geste.
Reste à rendre l’enregistrement du badge un peu moins fastidieux, peut-être via une application Android et la fonction de lecteur NFC de nos smartphones ?