addicttux
Published © GPL3+

Access Control with Ruby on Rails + ESP32 + RFID

Access control proof of concept using Ruby on Rails with ESP32 and RFID

IntermediateProtip7,610
Access Control with Ruby on Rails + ESP32 + RFID

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
ESP32
Espressif ESP32
×1
Relay (generic)
×1
RGB LCD Shield Kit, 16x2 Character Display
RGB LCD Shield Kit, 16x2 Character Display
×1
I2C LCD
×1
NeoPixel Ring: WS2812 5050 RGB LED
Adafruit NeoPixel Ring: WS2812 5050 RGB LED
×1
RFID Module (Generic)
×1
Buzzer
Buzzer
×1
Pushbutton Switch, Pushbutton
Pushbutton Switch, Pushbutton
×1

Software apps and online services

Tinkercad
Autodesk Tinkercad
circuito.io
circuito.io
Fritzing
Arduino IDE
Arduino IDE
Linux (Mint)

Story

Read more

Custom parts and enclosures

Case

Schematics

Connections Diagram

Code

Code

C/C++
#include <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Tone32.h> //https://github.com/lbernstone/Tone
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <string>

#define ON  1
#define OFF 0

#define BUZZER_CHANNEL 0
#define RELAY_PIN      2
#define NEOPIXEL_PIN   4
#define RFID_SS_PIN    14
#define BUZZER_PIN     15
#define RFID_RST_PIN   27
#define STRIPSIZE      16
#define LANGUAGE_PIN   34

#define OPEN_DOOR              0
#define DOOR_CLOSES_IN         1
#define DONT_FORGET_CLOSE_DOOR 2
#define THE_DOOR               3
#define ERROR_CARD             4
#define NOT_FOUND              5
#define ACCESS                 6
#define GRANTED                7
#define ACTIVATING             8
#define PORTS                  9
#define CONNECTED_TO           10
#define OFFICEYA_NETWORK       11
#define CONNECTING             12
#define ACTIVATING_RFID        13
#define RFID_ACTIVATED         14
#define NO_NETWORK             15
#define LANGUAGE_CHANGED       16
#define ACUTAL_LANGUAGE        17
#define INNOVATING             18
#define SOLUTIONS              19
#define MAX_ELEMENTS           20

const String english[MAX_ELEMENTS]  = {"Open the door",
                                       "It closes in:",
                                       "Dont forget to",
                                       "CLOSE the door",
                                       "Error, card",
                                       "not found",
                                       "ACCESS",
                                       "GRANTED",
                                       "Activating",
                                       "Ports...",
                                       "Connecting to",
                                       "OfficeYA Network",
                                       "Connecting...",
                                       "Activating RFID",
                                       "RFID Activaded",
                                       "Network not AVBL",
                                       "Language changed",
                                       "Using English",
                                       "** Innovating **",
                                       "*** Solutions **"};
const String spanish[MAX_ELEMENTS]  = {"Abra la puerta",
                                       "Se cierra en: ",
                                       "No olvide CERRAR",
                                       "la puerta",
                                       "ERROR, tarjeta",
                                       "no LOCALIZADA",
                                       "ACCESO",
                                       "AUTORIZADO",
                                       "Activando",
                                       "Puertos...",
                                       "Conectando a la",
                                       "red de OfficeYA",
                                       "Conectando...",
                                       "Activando RFID",
                                       "Activado RFID",
                                       "Red no disponible",
                                       "Cabmio de idioma",
                                       "Usando ESPANOL",
                                       "** Innovando ***",
                                       "** Soluciones **"};
const int lcdColumns                = 18;
const int lcdRows                   = 2;
int language                        = 1; // 1 = Spanish, 0 = English
int prev_language                   = 9;
int loop_counter                    = 1;
boolean incrementing                = true;
String card                         = "";
String messages[MAX_ELEMENTS];

MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN);
LiquidCrystal_I2C lcd(0x3F, lcdColumns, lcdRows);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRIPSIZE, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

void lcdMessage(String text1, String text2, int delayms = 500) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(text1);
  lcd.setCursor(0, 1);
  lcd.print(text2);
  delay(delayms);
}

void changeLanguage() {
  if (language != prev_language) {
    if (language == 1) {
      for (int i = 0; i <= MAX_ELEMENTS; i++) {
        messages[i] = spanish[i];
      }
    } else {
      for (int i = 0; i <= MAX_ELEMENTS; i++) {
        messages[i] = english[i];
      }
    }
    prev_language = language;
    if (language == 1) {
      language = 0;
    } else {
      language = 1;
    }
  }
  lcdMessage(messages[LANGUAGE_CHANGED], messages[ACUTAL_LANGUAGE], 1500);
}

void lightIt(int led, uint32_t color, int wait) {
  strip.setPixelColor(led, color);
  strip.show();
  delay(wait);
}

void colorWipe(uint32_t c, uint8_t wait, int mode = 1) {
  if (mode == 1) {
    for (uint16_t i = 0; i < strip.numPixels(); i++) {
      lightIt(i, c, wait);
    }
  } else {
    for (uint16_t i = (strip.numPixels() - 1); i > 0; i--) {
      lightIt(i, c, wait);
    }
    lightIt(0, c, wait);
  }
}

void relayMode(int mode, int delayms = 500) {
  if (mode == 1) {
    lcdMessage(messages[OPEN_DOOR], "", 100);
    digitalWrite(RELAY_PIN, HIGH);
    lcdMessage(messages[OPEN_DOOR], messages[DOOR_CLOSES_IN], 0);
    for (int i = 0; i < 10; i++) {
      lcd.setCursor(14, 1);
      lcd.print(10 - i);
      if (i != 0) {
        lcd.setCursor(15, 1);
        lcd.print(" ");
      }
      colorWipe(strip.Color(0, 200, 0), 28);
      delay(104);
      colorWipe(strip.Color(0, 0, 0), 28);
    }
  } else {
    lcdMessage(messages[DONT_FORGET_CLOSE_DOOR], messages[THE_DOOR], 100);
    digitalWrite(RELAY_PIN, LOW);
    delay(delayms);
  }
}

void errorSound() {
  colorWipe(strip.Color(200, 0, 0), 25);
  lcdMessage(messages[ERROR_CARD], messages[NOT_FOUND]);
  for (int i = 0; i < 4; i++) {
    tone(BUZZER_PIN, 150, 200, BUZZER_CHANNEL);
    tone(BUZZER_PIN, 125, 225, BUZZER_CHANNEL);
  }
  noTone(BUZZER_PIN, BUZZER_CHANNEL);
  delay(3000);
  colorWipe(strip.Color(0, 0, 0), 25, 0);
}

void okSound() {
  lcdMessage(messages[ACCESS], messages[GRANTED], 500);
  tone(BUZZER_PIN, 350, 150, BUZZER_CHANNEL);
  tone(BUZZER_PIN, 275, 250, BUZZER_CHANNEL);
  tone(BUZZER_PIN, 350, 150, BUZZER_CHANNEL);
  noTone(BUZZER_PIN, BUZZER_CHANNEL);
}

void checkLanguage() {
  if (digitalRead(LANGUAGE_PIN) == 1) {
    Serial.println("Push button pushed, changing language");
    changeLanguage();
  }
}

uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;
  for (j = 0; j < 256; j++) {
    for (i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i + j) & 255));
    }
    checkLanguage();
    strip.show();
    delay(wait);
  }
}

void detectCardRFID(){
  if ( ! rfid.PICC_IsNewCardPresent() || ! rfid.PICC_ReadCardSerial() ) {
    if (incrementing){
      if (loop_counter <= 15){
        checkLanguage();
        loop_counter++;
      } else {
        lcdMessage(messages[INNOVATING], messages[SOLUTIONS], 0);
        loop_counter = 15;
        incrementing = false;
      }
    } else {
      if (loop_counter >= 1){
        checkLanguage();
        loop_counter--;
      } else {
        lcdMessage("*** OfficeYA ***", "Business Centers", 0);
        loop_counter = 0;
        incrementing = true;
      }
    }
    return;
  }  else {
    Serial.print(F("Card UID:"));
    for (byte i = 0; i < rfid.uid.size; i++) {
      card += rfid.uid.uidByte[i];
      Serial.print(rfid.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(rfid.uid.uidByte[i], HEX);
    }
    Serial.println();
    Serial.print("Decimal: ");
    Serial.println(card);
    Serial.println();
  }
}

void verifyAccessRights(){
  if (card != "") {
    String url = "";
    if (WiFi.status() == WL_CONNECTED) {
      HTTPClient http;
      url = "http://youripaddress/status/" + card + ".json";
      http.begin(url);
      http.addHeader("Content-Type", "text/plain");
      int httpResponseCode = http.POST("");
      if (httpResponseCode > 0) {
        if ( strcmp("ok", http.getString().c_str()) == 0 ) {
          okSound();
          relayMode(ON);
          relayMode(OFF, 1000);
        } else {
          errorSound();
        }
      } else {
        errorSound();
      }
      http.end();
    } else {
      lcdMessage("ERROR:", messages[NO_NETWORK], 2000);
    }
  }
}

void setup() {
  char* ssid = "";
  char* password = "";
  ssid = "yourssid";
  password = "yourpassword";
  Serial.begin(115200);
  changeLanguage();
  delay(100);

  strip.begin();
  strip.setBrightness(25);
  strip.show();
  colorWipe(strip.Color(0, 0, 0), 1);

  lcd.init();
  lcd.backlight();

  lcdMessage(messages[ACTIVATING], messages[PORTS]);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LANGUAGE_PIN, INPUT);

  lcdMessage(messages[CONNECTED_TO], messages[OFFICEYA_NETWORK]);
  Serial.print("*** Connecting to network: ");
  Serial.print(ssid);
  Serial.println(" ***");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    lcdMessage(messages[CONNECTING], "", 500);
  }
  Serial.println("");
  Serial.println("Connected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  lcdMessage(messages[ACTIVATING_RFID], messages[RFID_ACTIVATED]);
  SPI.begin();
  rfid.PCD_Init();
  delay(10);

  digitalWrite(RELAY_PIN, LOW);
  lcdMessage("*** OfficeYA ***", "Business Centers", 1);
}

void loop() {
  card = "";
  rainbow(15);
  detectCardRFID();
  verifyAccessRights();
}

Credits

addicttux

addicttux

2 projects • 21 followers

Comments