Skip to content

Instantly share code, notes, and snippets.

@duncandoo
Created January 31, 2017 23:25
Show Gist options
  • Select an option

  • Save duncandoo/6b9c30af46371b0b625a490c9af4eb3f to your computer and use it in GitHub Desktop.

Select an option

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
/*
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