Created
January 31, 2017 23:25
-
-
Save duncandoo/6b9c30af46371b0b625a490c9af4eb3f to your computer and use it in GitHub Desktop.
Arduino IDE code to run an ESP8266 with a RFID reader to get and keep a list of authorised tags over MQTT. When an authorised tag is presented a relay is activated
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| espRFIDRelaycontroller by Duncan McPherson | |
| Use a RFID-RC522 and ESP8266-12e to control a relay to activate | |
| a machine for authorised users. Pick up the list of authorised users from an MQTT server. | |
| */ | |
| #include <EEPROM.h> // To read and write PICC's UIDs from/to EEPROM | |
| #include <SPI.h> // RC522 Module uses SPI protocol | |
| #include <MFRC522.h> // Library for Mifare RC522 Device | |
| #include <ESP8266WiFi.h> // To use WiFi to communicate with the mothership | |
| #include <IPStack.h> | |
| #include <Countdown.h> | |
| #include <MQTTClient.h> // Library for MQTT publishing and subscribing to get the authorised users from the mothership | |
| #include <ArduinoJson.h> // To parse the incoming messages | |
| const uint8_t relayPin = 16; // Nominate a pin to control the relay | |
| // ************* Stuff for reading cards with MFRC522 ******************* | |
| boolean successfulRead = false; // Whether or not a card has been read | |
| byte presentedCard[4]; // The UID of the card just presented | |
| const uint8_t ss_pin = 4; // Nominate a pin to slave select the MFRC522 | |
| const uint8_t rst_pin = 5; // Nominate a pin to reset the MFRC522 | |
| MFRC522 mfrc522(ss_pin, rst_pin); // define the MFRC522 | |
| // ************* Stuff for seting up WiFi ****************************** | |
| const char* ssid = "mcphersons"; | |
| const char* password = "ericthered"; | |
| WiFiClient wiFiClient; | |
| // ************* Stuff for setting up MQTT client subscriptions ******** | |
| char* mqttBroker = "192.168.0.2"; | |
| int port = 1883; | |
| char* clientID = "GeorgeLathenby"; | |
| char* user = "duncandoo_lathe"; | |
| char* pw = "........."; | |
| char* topic = "confidential/somakeit/space/tags/#"; | |
| int arrivedCount = 0; | |
| IPStack ipstack(wiFiClient); | |
| MQTT::Client<IPStack, Countdown, 50, 1> client = MQTT::Client<IPStack, Countdown, 50, 1>(ipstack); | |
| MQTT::Message message; | |
| char* topicTag = "confidential/somakeit/space/tags/ffffffff"; // example of MQTT topic we need | |
| // ************* Stuff for JSON parsing ***************************** | |
| StaticJsonBuffer<128> jsonBuffer; | |
| char* json = "{\"member_id\": \"007\",\"member_name\":\"George Lathenby\",\"roles\":[1,3,9,11]}"; | |
| void setup() { | |
| //pinMode(LED_BUILTIN, OUTPUT); // intialize the builtin led pin which | |
| // will be used to denote activation and Rx. | |
| pinMode(relayPin, OUTPUT); // Initialize the relayPin | |
| digitalWrite(relayPin, LOW); // Make sure the relay is off at the start | |
| Serial.begin(115200); // start a serial port | |
| SPI.begin(); // start SPI bus | |
| mfrc522.PCD_Init(); // start the MFRC522 | |
| EEPROM.begin(512); // start the EEPROM and define it's size | |
| //run once to set the initial storedCard for testing then wipe it | |
| // // byte storedCard[4] = { 0x29, 0x80, 0xc, 0x3b }; | |
| // EEPROM.write( 0, 1 ); | |
| // for ( byte i = 0 ; i < 4 ; i++ ) { | |
| // EEPROM.write( i+1 , storedCard[i] ); | |
| // } | |
| // EEPROM.commit(); | |
| } | |
| void loop() { | |
| Serial.print("Present your card to be assessed."); | |
| do { | |
| successfulRead = getID(); // Check if a card has been read successfully | |
| } | |
| while (!successfulRead); // go no further until a card is read successfully | |
| if (checkID(presentedCard)) { | |
| digitalWrite(relayPin, HIGH); // Turn the relay on | |
| boolean relayState = digitalRead(relayPin); | |
| Serial.printf("You may use the lathe. The relay should be on and it is %u.\n", relayState); | |
| //Check for new users | |
| connectWiFi(); | |
| connectMQTT(); | |
| while (true) { | |
| //leave the relay on or some other stuff that might happen, like a time limit | |
| Serial.println("Waiting for message"); | |
| client.yield(1000); | |
| addNewUsers( checkMessage( topicTag , json ) ); | |
| //digitalWrite(relayPin, LOW); | |
| } | |
| } | |
| else { | |
| //keep the relay off | |
| digitalWrite(relayPin, LOW); // Just to make sure | |
| boolean relayState = digitalRead(relayPin); | |
| Serial.printf("You are not authorised. Extermination will now commence. The relay should be off and it is %u.\n", relayState); | |
| Serial.println("If you think you really should be able to use the lathe present your card again and I'll check with the mothership..."); | |
| //Double check for new users | |
| connectWiFi(); | |
| connectMQTT(); | |
| char buf[100]; | |
| strcpy(buf, "Hello World! QoS 0 message"); | |
| message.qos = MQTT::QOS0; | |
| message.retained = false; | |
| message.dup = false; | |
| message.payload = (void*)buf; | |
| message.payloadlen = strlen(buf)+1; | |
| int rc = client.publish(topicTag, message); | |
| client.yield(5000); | |
| addNewUsers( checkMessage( topicTag , json ) ); | |
| //It would be nice to put a bit here to allow a different card to interrupt the connecting to WiFi and MQTT, to run in parallel | |
| } | |
| } | |
| // Function to check for card being read // | |
| boolean getID() { | |
| if ( ! mfrc522.PICC_IsNewCardPresent()) { | |
| delay(500); // Look for a card being presented every 500ms until one is found | |
| return false; | |
| } | |
| if ( ! mfrc522.PICC_ReadCardSerial()) { | |
| // Check the card that has been found has been read | |
| return false; | |
| } | |
| Serial.print("Card UID: "); | |
| for (byte i = 0; i < 4; i++) { | |
| presentedCard[i] = mfrc522.uid.uidByte[i]; // Print the UID to serial as hex values | |
| Serial.print(presentedCard[i], HEX); | |
| } | |
| Serial.println(); | |
| mfrc522.PICC_HaltA(); // Stop reading the card and tell it to switch off | |
| return true; | |
| } | |
| // function to check a card against list stored in EEPROM | |
| boolean checkID( byte testCard[] ) { | |
| byte users = EEPROM.read(0); //EEPROM[0] stores the number of authorised cards that need to be checked against | |
| byte storedCard[4]; // The UID of a card read from memory | |
| for ( byte user = 0 ; user < users ; user++) { | |
| for ( byte i = 0 ; i < 4 ; i++) { | |
| storedCard[i] = EEPROM.read( user * 4 + 1 + i ); //each UID is 4 bytes long and takes up 4 slots in EEPROM | |
| } | |
| boolean match = true; // assume there is a match | |
| for ( byte i = 0; i < 4; i++ ) { | |
| if ( testCard[i] != storedCard[i]) { | |
| match = false; // if any byte doesn't match fail | |
| } | |
| } | |
| if (match) { | |
| Serial.print("Welcome user number "); | |
| Serial.println(user, DEC); | |
| return true; | |
| } | |
| else { | |
| return false; | |
| } | |
| } | |
| } | |
| //function to connect to Wifi | |
| void connectWiFi() { | |
| delay(10); | |
| Serial.print("Connecting to "); | |
| Serial.println(ssid); | |
| WiFi.begin(ssid, password); | |
| while (WiFi.status() != WL_CONNECTED) { | |
| delay(500); | |
| Serial.print("."); | |
| } | |
| Serial.println(""); | |
| Serial.print("WiFi connected to IP address "); | |
| Serial.println(WiFi.localIP()); | |
| } | |
| //function to connect to MQTT server | |
| void connectMQTT() { | |
| Serial.print("Connecting to "); | |
| Serial.print(mqttBroker); | |
| Serial.print(":"); | |
| Serial.println(port); | |
| int rc = ipstack.connect(mqttBroker, port); | |
| if (rc != 1) | |
| { | |
| Serial.print("rc from TCP connect is "); | |
| Serial.println(rc); | |
| } | |
| Serial.println("MQTT connecting"); | |
| MQTTPacket_connectData data = MQTTPacket_connectData_initializer; | |
| data.MQTTVersion = 3; | |
| data.clientID.cstring = clientID; | |
| data.username.cstring = user; | |
| data.password.cstring = pw; | |
| rc = client.connect(data); | |
| if (rc != 0) | |
| { | |
| Serial.print("rc from MQTT connect is "); | |
| Serial.println(rc); | |
| } | |
| Serial.println("MQTT connected"); | |
| rc = client.subscribe(topic, MQTT::QOS1, messageArrived); | |
| if (rc != 0) | |
| { | |
| Serial.print("rc from MQTT subscribe is "); | |
| Serial.println(rc); | |
| } | |
| Serial.print("MQTT subscribed to topic: "); | |
| Serial.println(topic); | |
| } | |
| // function to handle callbacks from MQTT broker | |
| void messageArrived(MQTT::MessageData& md) { | |
| MQTT::Message &message = md.message; | |
| char* topic = md.topicName.cstring; | |
| Serial.print("Message "); | |
| Serial.print(++arrivedCount); | |
| Serial.print(" arrived: qos "); | |
| Serial.print(message.qos); | |
| Serial.print(", retained "); | |
| Serial.print(message.retained); | |
| Serial.print(", dup "); | |
| Serial.print(message.dup); | |
| Serial.print(", packetid "); | |
| Serial.println(message.id); | |
| Serial.print("Topic "); | |
| Serial.println(topic); | |
| Serial.print("Payload "); | |
| Serial.println((char*)message.payload); | |
| json = (char*)message.payload; | |
| topicTag = (char*)topic; | |
| } | |
| // function to check if message contains a new authorised user | |
| byte* checkMessage(char *topicTag , char *json ) { | |
| JsonObject &root = jsonBuffer.parseObject(json); | |
| byte len1 = sizeof(root["roles"]) / sizeof(root["roles"][0]); | |
| int roles[len1]; | |
| for ( byte i = 0 ; i < len1 ; i++ ) { | |
| roles[i] = root["roles"][i]; | |
| } | |
| byte len2 = sizeof(roles) / sizeof(roles[0]); | |
| byte newUser[4] = { 0xff, 0xff, 0xff, 0xff }; | |
| for ( byte i ; i < len2 ; i++ ) { | |
| if ( roles[i] == 11 ) { // check if the list of roles includes 11, which is lathe user | |
| char *UID = &topicTag[strlen(topicTag)-8]; | |
| for ( byte i = 0 ; i < 4 ; i++ ) { | |
| newUser[i] = UID[i]; | |
| } | |
| } | |
| } | |
| return newUser; | |
| } | |
| // function to write new authorised cardNumber into EEPROM | |
| void addNewUsers(byte newUser[]) { | |
| byte users = EEPROM.read(0); //EEPROM[0] stores the number of authorised cards that need to be checked against | |
| byte storedCard[4]; // The UID of a card read from memory | |
| for ( byte user = 0 ; user < users ; user++) { // Check if the newUser is already in EEPROM by comparing against every user | |
| for ( byte i = 0 ; i < 4 ; i++) { | |
| storedCard[i] = EEPROM.read( user * 4 + 1 + i ); //each UID is 4 bytes long and takes up 4 slots in EEPROM | |
| } | |
| boolean match = true; // assume there is a match | |
| for ( byte i = 0; i < 4; i++ ) { | |
| if ( newUser[i] != storedCard[i]) { | |
| match = false; // if any byte doesn't match fail | |
| } | |
| } | |
| if (match) { | |
| Serial.print("User is already authorised and is number "); | |
| Serial.println(user, DEC); | |
| } | |
| else { | |
| users += users; // increment the number of users | |
| EEPROM.write(0, users); | |
| for ( byte i = 0 ; i < 4 ; i++ ) { | |
| EEPROM.write( users * 4 + 1 + i , newUser[i] ); | |
| } | |
| EEPROM.commit(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment