Skip to content

Instantly share code, notes, and snippets.

@brysonreece
Last active October 10, 2018 00:58
Show Gist options
  • Select an option

  • Save brysonreece/e97f38ec1e7f36dfb26a6d6781d2314c to your computer and use it in GitHub Desktop.

Select an option

Save brysonreece/e97f38ec1e7f36dfb26a6d6781d2314c to your computer and use it in GitHub Desktop.
Sends a MQTT packet to a subscribed topic after authenticating with a known NFC tag using the MFRC522 Reader
#include <ESP8266WiFi.h>
#include <SPI.h>
#include <MFRC522.h>
#include <PubSubClient.h>
/**
* LED = GPIO16
* RST = GPIO5
* SDA(SS) = GPIO4
* MOSI = GPIO13
* MISO = GPIO12
* SCK = GPIO14
* GND = GND
* 3.3V = 3.3V
*/
/** Whether to toggle Serial output */
const bool DEBUG_MODE = true;
/** WiFi Details */
const char* WIFI_SSID = "YOUR_WIFI_SSID_HERE";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD_HERE";
/** MQTT Details */
const char* MQTT_SERVER_HOST = "YOUR_MQTT_BROKER_HERE";
const uint16_t MQTT_SERVER_PORT = 1883;
const char* MQTT_SERVER_USER = "YOUR_MQTT_USER_HERE";
const char* MQTT_SERVER_PASSWORD = "YOUR_MQTT_PASSWORD_HERE";
const char* MQTT_CLIENT_ID = "YOUR_MQTT_CLIENT_ID_HERE";
const char* MQTT_OUT_TOPIC = "YOUR_MQTT_TOPIC_HERE";
const char* MQTT_TOPIC_ON_STATE = "ON";
/** Pin Mappings (see diagram above) */
const int SS_PIN = 4;
const int RST_PIN = 5;
const int LED_PIN = 16;
/** Reader config values */
const int SCAN_TIMEOUT_SEC = 5;
const int NUM_KEYS = 2;
const int UID_LENGTH = 7;
/** Keycard Struct */
struct Keycard {
byte uid[UID_LENGTH];
byte password[4];
};
/** Known Keycards */
const Keycard known_keys[2] = {
{
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // UID #1
{ 0xFF, 0xFF, 0xFF, 0xFF } // Password #1
},
{
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // UID #2
{ 0xFF, 0xFF, 0xFF, 0xFF } // Password #2
}
};
/** Various Clients */
WiFiClient espClient;
PubSubClient client(espClient);
MFRC522 mfrc522(SS_PIN, RST_PIN);
/** Timestamp of when we last scanned a known keycard */
unsigned long last_scanned = 0;
void setup() {
// Check if we're in debug mode
if (DEBUG_MODE) {
// If so, enable serial output
Serial.begin(115200);
}
// Wait a bit before printing to console
delay(50);
// Alert that we're booting
Serial.println("Booting...");
// Attempt WiFi connection
Serial.print("Connecting to Wifi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
// Keep trying until we're connected to WiFi
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
// Print out WiFi details
Serial.println("");
Serial.print("WiFi connected => IP Address: ");
Serial.println(WiFi.localIP());
// Set up our MQTT connection
client.setServer(MQTT_SERVER_HOST, MQTT_SERVER_PORT);
// Enable our RFID/NFC Reader
SPI.begin();
mfrc522.PCD_Init();
// Set up our indicator LED
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// If we're not connected to MQTT, attempt to
if (!client.connected()) {
mqtt_reconnect();
}
// Tell our MQTT callback to loop here
client.loop();
// Check if a card is held to the reader
if (!mfrc522.PICC_IsNewCardPresent()) {
// If not, don't do anything
delay(50);
return;
}
// Check if we can read from the card
if (!mfrc522.PICC_ReadCardSerial()) {
// If not, don't do anything
delay(50);
return;
}
// Check if the scanned card is known and authenticated
if (check_uid(mfrc522.uid)) {
// Ignore publishing to MQTT if it's been less than 5s since the last scan
if (millis() > (last_scanned + (SCAN_TIMEOUT_SEC * 1000))) {
// Print out MQTT intent
Serial.print("Publishing MQTT Data \"");
Serial.print(MQTT_TOPIC_ON_STATE);
Serial.print("\" to topic \"");
Serial.print(MQTT_OUT_TOPIC);
Serial.print("\" at ");
Serial.print(MQTT_SERVER_HOST);
Serial.print(':');
Serial.println(MQTT_SERVER_PORT);
// Turn our indicator LED on
digitalWrite(LED_PIN, LOW);
// Publish an MQTT packet
client.publish(MQTT_OUT_TOPIC, MQTT_TOPIC_ON_STATE);
// Update the timestamp of when we last read a card
last_scanned = millis();
// Wait a bit to allow the LED to stay on for indication
delay(250);
// Turn the LED off
digitalWrite(LED_PIN, HIGH);
}
}
}
/**
* Check if the scanned UID is known and can authenticate with the
* provided password
*/
bool check_uid(MFRC522::Uid uid) {
// Get an instance of the UID buffer
byte *buffer = uid.uidByte;
// Iterate over the known keys
for (int i = 0; i < NUM_KEYS; i++) {
// Get an instance of a known keycard
Keycard keycard = known_keys[i];
// Check that it's the correct size
if (uid.size != UID_LENGTH) {
continue;
}
// Check UID bytes
bool uidMismatch = false;
for (byte j = 0; j < UID_LENGTH; j++) {
// Skip remaining bytes
if (uidMismatch) {
continue;
}
// Check byte comparison
if (buffer[j] != keycard.uid[j]) {
uidMismatch = true;
}
}
// Skip keycard
if (uidMismatch) {
continue;
}
// Attempt authentication
byte pACK[] = {0, 0};
MFRC522::StatusCode status = mfrc522.PCD_NTAG216_AUTH(keycard.password, pACK);
// Check if authentication worked. If so, return
if (status == MFRC522::STATUS_OK) {
return true;
}
}
// UID provided failed. Return false
return false;
}
/**
* Attempts to connect to the provided MQTT broker
*/
void mqtt_reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
// Alert intent
Serial.print("Attempting MQTT connection... ");
// Attempt to connect
if (client.connect(MQTT_CLIENT_ID, MQTT_SERVER_USER, MQTT_SERVER_PASSWORD)) {
// Yay, we're connected
Serial.println("CONNECTED");
// Subscribe to the provided topic
client.subscribe(MQTT_OUT_TOPIC);
}
else {
// Print out error details
Serial.print("FAILED, rc = (");
Serial.print(client.state());
Serial.println(") | Trying again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment