├── LICENSE ├── LTS.py ├── README.md ├── RFIDTags.ino └── serverTest.py /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, David Smerkous and Oliver Warne 2 | 3 | BY DOWNLOADING THIS SOFTWARE YOU AGREE TO THESE TERMS!!! 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 6 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 7 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR 8 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 9 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 10 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 11 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 12 | -------------------------------------------------------------------------------- /LTS.py: -------------------------------------------------------------------------------- 1 | import MySQLdb 2 | import time 3 | import config 4 | 5 | from sys import exit 6 | 7 | 8 | class MyDB(object): 9 | _conn = None 10 | _cur = None 11 | _last_id = None 12 | 13 | def __init__(self): 14 | self._conn = MySQLdb.connect(host=config.host, 15 | user=config.user, 16 | passwd=config.passwd, 17 | db=config.db) 18 | self._cur = self._conn.cursor() 19 | self._last_id = self._cur.lastrowid 20 | 21 | 22 | def query(self, query, params=None): 23 | if params is not None: 24 | self._cur.execute(query, params) 25 | self._last_id = self._cur.lastrowid 26 | final = self._cur.fetchone() 27 | self._conn.commit() 28 | return final 29 | else: 30 | final = self._cur.execute(query) 31 | self._last_id = self._cur.lastrowid 32 | self._conn.commit() 33 | return final 34 | 35 | 36 | def __del__(self): 37 | self._conn.close() 38 | 39 | def wipearray(): 40 | DB = MyDB() 41 | 42 | DB.query("DROP TABLE IF EXISTS learners") 43 | 44 | DB.query('''CREATE TABLE learners( 45 | `learner_id` INT AUTO_INCREMENT, 46 | `first_name` VARCHAR(45) NOT NULL, 47 | `last_name` VARCHAR(45) NOT NULL, 48 | `year` INT(3) NOT NULL DEFAULT 0, 49 | `notes` VARCHAR(255), 50 | `location` INT(3) NOT NULL DEFAULT 0, 51 | `check_in_time` INT(11) NOT NULL DEFAULT 0, 52 | `rfid` VARCHAR(36) NOT NULL DEFAULT 0, 53 | PRIMARY KEY (`learner_id`))''') 54 | 55 | 56 | ### I did this because in the bottom class, creating a learner requires inserting first_name and such else. In order to insert 57 | ### a name or whatever, you need an ID to insert it to. In order to get an ID, you need a name. Hence the issue 58 | ### Was there a better way of doing it? No doubt. 59 | ### Are there way more pressing issues? No doubt. 60 | def createLearner(first_name,last_name,year=None,rfid=None): 61 | """Creates a learner and returns the ID of that learner 62 | :param first_name: First name (string) 63 | :param last_name: Last name (string) 64 | :return: ID of learner just created (int) 65 | """ 66 | DB = MyDB() 67 | create_query = ("INSERT INTO learners " 68 | "(first_name,last_name,year,location,check_in_time,rfid) " 69 | "VALUES (%(first_name)s,%(last_name)s,%(year)s,0,0,%(rfid)s)") 70 | create_data = { 71 | 'first_name' : first_name, 72 | 'last_name' : last_name, 73 | 'year' : 0 if year is None else year, 74 | 'rfid' : 0 if rfid is None else rfid, 75 | } 76 | 77 | DB.query(create_query,params=create_data) 78 | 79 | id = DB._last_id 80 | 81 | return int(id) 82 | 83 | def learnerfromRFID(RFID): 84 | """ Creates a learner object 85 | :param RFID: RFID of learner (string) 86 | :return: Learner object (LTSBacked) 87 | """ 88 | DB = MyDB() 89 | try: 90 | id = DB.query("SELECT learner_id FROM learners WHERE rfID = %s",RFID)[0] 91 | except TypeError: 92 | raise ValueError('No learner with RFID:{}'.format(RFID)) 93 | learner = LTSBackend(id) 94 | return learner 95 | 96 | 97 | ### WTF PYTHON? Why do I need to put this stupid object parameter in order for setters to work? 98 | class LTSBackend(object): 99 | 100 | def __init__(self, ID): 101 | # Grr this is a weird way of doing it 102 | # Basically the "Nones" are just telling python to execute the properties 103 | self.ID = ID 104 | self._first_name = None 105 | self._last_name = None 106 | self._Notes = None 107 | self._Location = None 108 | self._RFID = None 109 | 110 | 111 | @property 112 | def first_name(self): 113 | DB = MyDB() 114 | 115 | # TODO : Implement some form of checking before returning ID 116 | return DB.query("SELECT first_name FROM learners WHERE learner_id = %s", (self.ID))[0] 117 | 118 | @first_name.setter 119 | def first_name(self,new_name): 120 | DB = MyDB() 121 | 122 | DB.query("""UPDATE learners 123 | SET first_name=%(new_name)s 124 | WHERE learner_id=%(id)s""", 125 | params={'new_name' : new_name, 126 | 'id' : self.ID}) 127 | 128 | # The reason I do the select is to make sure that it actually inserted it into the database 129 | # I should probably remove these to save speed. 130 | self._first_name = DB.query("SELECT first_name FROM learners WHERE learner_id = %s", (self.ID))[0] 131 | 132 | @property 133 | def last_name(self): 134 | DB = MyDB() 135 | return DB.query("SELECT last_name FROM learners WHERE learner_id = %(ID)s",{'ID' : 1})[0] 136 | 137 | @last_name.setter 138 | def last_name(self,new_name): 139 | DB = MyDB() 140 | 141 | DB.query("""UPDATE learners 142 | SET last_name=%(new_name)s 143 | WHERE learner_id=%(id)s""", 144 | params={'new_name' : new_name, 145 | 'id' : self.ID}) 146 | 147 | self._last_name = DB.query("SELECT last_name FROM learners WHERE learner_id = %(ID)s",{'ID' : 1})[0] 148 | 149 | @property 150 | def Notes(self): 151 | DB = MyDB() 152 | 153 | return DB.query("SELECT notes FROM learners WHERE learner_id = %(ID)s",{'ID' : 1})[0] 154 | 155 | @Notes.setter 156 | def Notes(self,new_notes): 157 | DB = MyDB() 158 | 159 | DB.query("""UPDATE learners 160 | SET notes=%(new_notes)s 161 | WHERE learner_id=%(id)s""", 162 | params={'new_notes' : new_notes, 163 | 'id' : self.ID}) 164 | 165 | self._Notes = DB.query("SELECT notes FROM learners WHERE learner_id = %(ID)s",{'ID' : 1})[0] 166 | 167 | @property 168 | def Location(self): 169 | DB = MyDB() 170 | 171 | return DB.query('SELECT location FROM learners WHERE learner_id= %s', (self.ID))[0] 172 | 173 | @Location.setter 174 | def Location(self, location): 175 | DB = MyDB() 176 | 177 | # check_in_time is in unixtime 178 | DB.query("""UPDATE learners 179 | SET check_in_time = %(unix_time)s 180 | WHERE learner_id= %(id)s""", 181 | params={'unix_time' : time.time(), 182 | 'id' : self.ID}) 183 | DB.query("""UPDATE learners 184 | SET location = %s 185 | WHERE learner_id= %s""", 186 | (location, self.ID)) 187 | 188 | self._Location = DB.query('SELECT location FROM learners WHERE learner_id= %s', (self.ID)) 189 | 190 | @property 191 | def RFID(self): 192 | DB = MyDB() 193 | 194 | return DB.query('SELECT rfid FROM learners WHERE learner_id= %s', (self.ID))[0] 195 | 196 | @RFID.setter 197 | def RFID(self,newRFID): 198 | DB = MyDB() 199 | 200 | DB.query("""UPDATE learners 201 | SET rfID = %s 202 | WHERE learner_id= %s""", 203 | (newRFID,self.ID)) 204 | 205 | return DB.query('SELECT rfid FROM learners WHERE learner_id= %s', (self.ID))[0] 206 | 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InternetRFIDTags 2 | Made for the academy high school management system 3 | 4 | Want to give suggestions? Go on ahead and contact us and/or use email smerkousdavid@gmail.com 5 | 6 | ##Before we Begin 7 | Before we can start scanning cards and sending them to our Telnet/TCP server we need some libraries 8 | Get UIPEthernet here https://github.com/ntruchsess/arduino_uip 9 | 10 | get MFRC522 here https://github.com/miguelbalboa/rfid 11 | 12 | Put both of these libraries in Program Files(x86)/Arduino/Libraries/ 13 | Restart arduino 14 | 15 | ##Hardware 16 | 1. Arduino Nano (You can always modify your code to fit your device) 17 | 2. MFRC522 with MAIFARE cards 18 | 3. Jumper wires (Male to Male) (Male to Female) 19 | 4. enc28j60 ethernet module/sheild 20 | 5. RGB LED 21 | 6. 3V OR 5V greater than 700 mileamp AC-DC converter 22 | 23 | ##Setup 24 | 1. Attach arduino to breadboard (If nano or micro) 25 | 2. Look up online for the pinout of your board to find the SPI setup(Change values below) 26 | 3. Connect arduino pin 10 (SS) to ethernet module ss or CS 27 | 4. Connect arduino pin 12 (MISO) to rfid MISO and ethernet SO 28 | 5. Connect arduino pin 11 (MOSI) to rfid MOSI and ethernet SI 29 | 6. Connect arduino pin 13 (SCK) to rfid SCK and ethernet SCK 30 | 7. Connect arduino pin 9 to rfid RST pin 31 | 8. Connect arduino pin 8 to rfid SSN 32 | 9. Connect arduino pin 5 to green led, 4 to blue and 3 to red 33 | 10. Connect your AC to DC to the + and - on your breadboard 34 | 11. Ground your arduino to the ac to dc 35 | 12. Connect VCC and GND on both rfid and ethernet to the ac-dc (REMEMBER THESE DEVICES ARE ONLY 3v!!!!! do not supply 5v) If problem use resistors to bring the voltage to 3v 36 | 13. Wire VCC pin on LED to the arduino 3v or ac-dc 3v 37 | 14. Connect ethernet cable to module and make sure it is on the same network as your computer 38 | 15. Plug USB cable from computer to arduino 39 | 16. Connect computer to same network 40 | 41 | ##Modify code to fit your needs 42 | 1. The code is pretty well commented so you can just go in and modify certain parts but one thing for sure is the ehternet module 43 | 2. Mac address can stay the same (Unless you're planning to build multiple of these) 44 | 3. If you are using a 192.168. base ip network you can keep the ip 45 | 4. Again you can keep the dns, only time to change is to 8.8.4.4 46 | 5. run ipconfig to find your gateway, the default is 192.168.1.1(If you don't know it) (The code currently is 192.168.1.5) 47 | 6. run command prompt and type ipconfig to figure out your computers ip address 48 | 7. scroll down to find SEND TO SERVER, and input the ip of your computer or if your port forwarded your router to your public ip address 49 | 8. MAKE SURE YOU HAVE PYTHON AND RUN THE SERVER (Remember it's just an example code we used for our presentation to the school, so the python server was already premade and almost not modified you can use any Telnet/TCP server) 50 | 51 | ##Running the code 52 | 1. Plug AC-DC power to the wall 53 | 2. Make sure your arduino is currently connected to the computer 54 | 3. Make sure both device are on the same network 55 | 4. Flash your modified arduino code or if the one I have works for you then great(Almost no chance you will have to modify it) 56 | 5. Start your Python, C++ script or whatever Telnet/TCP server on your network 57 | 6. Restart your arduino to be safe 58 | 7. Wait until the light turns blue and try scanning a card, if your server got the ID of the card then your ready to go 59 | 8. Remember what the lights means Purple/fading red means booting up 60 | 9. Red means any error such as the card was at a weird angle and/or the server didn't respond in time 61 | 10. Green means pass so the server responded with a go and you can read your next card 62 | 11. Blue means waiting/loading waiting for a card or response 63 | 12. If your arduino starts to lag out and takes over 30 seconds to show a red light means that the arduino ethernet module couldn't connect to the server at all. This could be caused by multiple things first your arduino doesn't have enough power and the arduino ethernet module is struggeling to send a packet or that your computer server isn't running or that your arduino and computer are not on the same network. 64 | 13. If your arduino keeps lagging out then try these tricks to fix them 65 | 66 | 67 | 1. Turn off windows firewall 68 | 2. go into advanced firewall settings and allow inbound/outbound port 23 69 | 3. port forward you router to your computer with port 23 70 | 4. If you are wireless connect the arduino straight into the router and your computer to the same one 71 | 5. Buy a more heavy duty AC-DC power adapter 72 | 6. Else maybe you input your ip address or connecting address wrong 73 | 74 | 75 | 14. Either than that contact me at smerkousdavid@gmail.com if there are any problems 76 | 15. YOUR GOOD TO GO!!1 77 | 78 | 79 | 80 | 81 | ##### I am not responsible for damaged devices, if unhandled properly your device will be damaged. Make sure your careful because I have once literally toasted an arduino uno, and it was my fault not the guy giving the tutorial. So be careful! 82 | -------------------------------------------------------------------------------- /RFIDTags.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------- 3 | * MFRC522 Arduino 4 | * Reader/PCD Nano v3 5 | * Signal Pin Pin 6 | * ---------------------------------- 7 | * RST/Reset RST D9 8 | * SPI SS NSS D10 9 | * SPI MOSI MOSI D11 10 | * SPI MISO MISO D12 11 | * SPI SCK SCK D13 12 | */ 13 | 14 | // THE FIRST LIBRARY THAT NEEDS TO BE INSTALLED IS UIP ETHERNET SECOND IS MFRC522 BOTH ARE ON GITHUB 15 | 16 | #include //Only needed for the cheaper ENC2j28 ethernet module 17 | 18 | #include //For the selection of the key 19 | #include //The RFID key library 20 | 21 | #define RST_PIN 9 // Configurable, see typical pin layout above - This is for the Arduino Nano - For RFID 22 | #define SS_PIN 8 //WE ARE USING 8 FOR RFID BECAUSE THE ETHERNET MODULE USES 10 23 | 24 | byte sector = 0; 25 | byte blockAddr = 0; ////////Access certain sector/blocks in the card, trailer block is the last block 26 | byte trailerBlock = 1; 27 | 28 | int red = 3; 29 | int blue = 4; //Pins for RGB LED 30 | int green = 5; 31 | 32 | EthernetClient client; //ETHERNET INSTANCE 33 | 34 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 35 | 36 | MFRC522::MIFARE_Key key; //Set key instance 37 | 38 | signed long timeout; //TIMEOUT SO IT DOESN'T SIT THERE FOREVER 39 | 40 | void setup() 41 | { 42 | //UI BEGIN 43 | pinMode(red, OUTPUT); 44 | pinMode(blue, OUTPUT); //Init the RGB LED 45 | pinMode(green, OUTPUT); 46 | Reset(); //Start with leds off 47 | 48 | Serial.begin(9600); //Start computer connection with a rate of 9600 bits per second 49 | //UI END 50 | 51 | //ETHERNET MODULE INITIAL 52 | SPI.begin(); // Init SPI bus 53 | uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; //MAC = 000102030405 54 | IPAddress mip(192,168,1,160); //IP = 192.168.1.160 55 | IPAddress mdns(8,8,8,8); //DNS = 8.8.8.8 56 | IPAddress mgate(192,168,1,1); //GATEWAY = 192.168.1.1 (Default for most routers) 57 | IPAddress msubnet(255,255,255,0); //SUBNET = 255.255.255.0 58 | Ethernet.begin(mac, mip, mdns, mgate , msubnet); //CONNECT USING ABOVE 59 | Serial.println("Succesful connection"); 60 | // END OF ETHERNET 61 | 62 | for(int t = 255; t > 0; t--) 63 | { 64 | analogWrite(red, t); ////More of show but let at least a second between the SPI of the ethernet and RFID 65 | delay(10); 66 | } 67 | 68 | //RFID INITIAL 69 | mfrc522.PCD_Init(); // Init MFRC522 card 70 | 71 | for (byte i = 0; i < 6; i++) { // Prepare the key which is 6 of 0xFF 72 | key.keyByte[i] = 0xFF; // using FFFFFFFFFFFFh which is the default at chip delivery from the factory 73 | } 74 | 75 | Serial.println(F("Scan a Card")); 76 | dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); //Get key byte size Usually (6) 77 | timeout = 0; 78 | delay(1000); //Wait for module bootup(They should already be done but just to be safe) 79 | Reset(); //Turn all lights off 80 | } 81 | //END RFID INITIAL 82 | 83 | void loop() //Run forever 84 | { 85 | // Look for new cards 86 | if ( ! mfrc522.PICC_IsNewCardPresent()) 87 | { 88 | digitalWrite(blue, LOW); 89 | return; 90 | } 91 | 92 | // Select one of the cards 93 | if ( ! mfrc522.PICC_ReadCardSerial()) 94 | return; 95 | 96 | digitalWrite(blue, HIGH); //Show user that card has been read 97 | 98 | 99 | byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 100 | 101 | // Check for compatibility with Mifare card 102 | if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 103 | && piccType != MFRC522::PICC_TYPE_MIFARE_1K 104 | && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 105 | Error(); //Error light 106 | return; //Don't run anything below 107 | } 108 | 109 | byte status; 110 | byte buffer[18]; //Buffer amount of 18 bytes, which is a about a half a block worth 111 | byte size = sizeof(buffer); 112 | 113 | 114 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 115 | if (status != MFRC522::STATUS_OK) { 116 | Serial.print(F("PCD_Authenticate() failed: ")); //Remember the FFFFF... You need to identify the card before accessing 117 | //Serial.println(mfrc522.GetStatusCodeName(status)); error 118 | Error(); //Error light 119 | return; 120 | } 121 | 122 | 123 | // Read data from the block 124 | status = mfrc522.MIFARE_Read(blockAddr, buffer, &size); //Read the addr with a buffer 2 times (18bytes) 125 | if (status != MFRC522::STATUS_OK) { 126 | Serial.print(F("MIFARE_Read() failed: ")); 127 | //Serial.println(mfrc522.GetStatusCodeName(status)); error 128 | Error(); 129 | } 130 | // Halt PICC 131 | mfrc522.PICC_HaltA();//Stop the SPI comm with the card so you can free the line to the ethernet controller 132 | // Stop encryption on PCD 133 | mfrc522.PCD_StopCrypto1(); 134 | 135 | // AFTER DONE READING CARD SEND TO SERVER 136 | if (client.connect(IPAddress(192,168,1,100),23)) //port <1000 is priveleged, MAKE SURE FIREWALL IS OFF 137 | { 138 | timeout = millis()+1000; //Get current time (since boot) and add 1000ms for a 1 second timeout 139 | Serial.println("Client connected"); 140 | const String ID = dump_byte_array(buffer, size); 141 | client.println(ID); 142 | Serial.println("sent :" + ID); 143 | delay(10); 144 | while(client.available()==0) 145 | { 146 | if (timeout - millis() < 0) //If greater than one second just leave 147 | goto close; 148 | } 149 | int size; 150 | while((size = client.available()) > 0) //if pass earlier test have a 30 second timeout 151 | { 152 | uint8_t* msg = (uint8_t*)malloc(size); 153 | size = client.read(msg,size); //Read the memorry allocated msg, with the allocation to (size = client) 154 | Serial.write(msg,size); 155 | if(size == sizeof("g") - 1) 156 | { 157 | Pass(); //Finally you pass every test and get a response from the computer 158 | } 159 | else 160 | { 161 | Error(); //Dang the card number didn't match any in the SQL server 162 | } 163 | free(msg);//Clear the allocated memory 164 | } 165 | close: 166 | client.stop(); //Close the TCP socket 167 | } 168 | else 169 | { 170 | Serial.println("Couldn't connect to Server"); //If passed the 30 second timeout just show you coudn't connect to server 171 | ConnectionError(); //Flash repediatly to show there was an error connecting to the TCP server 172 | } 173 | //END OF SENDING TO SERVER 174 | 175 | Reset(); //RESTART LOOP WITH NO LEDS ON 176 | } 177 | 178 | // TURN THE BUFFER ARRAY INTO A SINGLE STRING THAT IS UPPERCASE WHICH EQUALS OUR ID OF THE SECTOR AND BLOCK 179 | String dump_byte_array(byte *buffer, byte bufferSize) { 180 | String out = ""; 181 | for (byte i = 0; i < bufferSize; i++) { 182 | //Serial.print(buffer[i] < 0x10 ? " 0" : " "); 183 | //Serial.print(buffer[i], HEX); 184 | out += String(buffer[i] < 0x10 ? " 0" : " ") + String(buffer[i], HEX); 185 | } 186 | out.toUpperCase(); //Make all cards uppercase, because the buffered reading will make them lower case 187 | out.replace(" ", ""); //No spaces so cards don't get wacky length 188 | return out; //Return the dump_byte_array String which is the ID of the card 189 | } 190 | //END DUMP_BYTE_ARRAY 191 | 192 | //BELOW ARE THE LED METHODS 193 | void Error() 194 | { 195 | digitalWrite(red, LOW); 196 | delay(700); 197 | digitalWrite(red, HIGH); 198 | } 199 | 200 | void Pass() 201 | { 202 | digitalWrite(green, LOW); 203 | delay(700); 204 | digitalWrite(green, HIGH); 205 | } 206 | 207 | void Reset() 208 | { 209 | digitalWrite(red, HIGH); 210 | digitalWrite(blue, HIGH); 211 | digitalWrite(green, HIGH); 212 | } 213 | 214 | void ConnectionError() 215 | { 216 | digitalWrite(red, LOW); 217 | delay(400); 218 | digitalWrite(red, HIGH); 219 | delay(400); 220 | digitalWrite(red, LOW); 221 | delay(400); 222 | digitalWrite(red, HIGH); 223 | delay(400); 224 | digitalWrite(red, LOW); 225 | } 226 | } 227 | //END OF FILE 228 | -------------------------------------------------------------------------------- /serverTest.py: -------------------------------------------------------------------------------- 1 | import SocketServer 2 | import sys 3 | from random import randint 4 | from LTS import * 5 | 6 | 7 | class MyTCPHandler(SocketServer.BaseRequestHandler): 8 | """ 9 | The RequestHandler class for our server. 10 | 11 | It is instantiated once per connection to the server, and must 12 | override the handle() method to implement communication to the 13 | client. 14 | """ 15 | 16 | def handle(self): 17 | self.data = self.request.recv(1024).strip() 18 | print self.client_address 19 | print self.data 20 | if len(self.data) != 36: 21 | sys.exit() 22 | 23 | try: 24 | # Load learner 25 | learner = learnerfromRFID(self.data) 26 | learner.Location = randint(0,31) 27 | self.request.sendall("g") 28 | 29 | except Exception as e: 30 | print "SOMETHING BROKE" 31 | print e.message 32 | self.request.sendall("bb") 33 | 34 | if __name__ == "__main__": 35 | print 'STARTING' 36 | HOST, PORT = '', 23 37 | 38 | # Create the server, binding to localhost on port 9999 39 | server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) 40 | 41 | # Activate the server; this will keep running until you 42 | # interrupt the program with Ctrl-C 43 | server.serve_forever() 44 | --------------------------------------------------------------------------------