СКУД «MAX» – бездротовий зчитувач RFID на ESP8266 або ESP32

Продовження роботи над проєктом СКУД “MAX”.
Arduino. Система контролю та управління доступом.
Arduino. СКУД «MAX v2.0»

Не завжди зручно і доцільно встановлювати дротові зчитувачі в тих місцях, де просяться до установки бездротові модулі. Тому дійшла черга до створення бездротової версії зчитувача.

Отже, для бездротового модуля не потрібен материнський модуль, тому що вся обробка відбувається в одному пристрої.

Вибір на чому робити – на ESP8266 або ESP32? А не потрібно вибирати, зробимо на обох платформах.

Отже, нам потрібні наступні компоненти:
1. esp8266 nodemcu v3 (була в наявності, але нічого не заважає зробити на D1 mini).
2. Міні Rc522 Rfid (мені до душі такий мініатюрний модуль).
3. Для другого варіанту плата ESP-WROOM-32.
4. Декілька Rfid карток, що йдуть в комплекті.

Схема підключення до esp8266:

ESP8266RFID
D4SDA
D5SCK
D7MOSI
D6MISO
GNDGND
D3RST
3.3v3.3v
Схема підключення esp8266 і RFID

Для роботи Rfid потрібна стандартна бібліотекаа MFRC522.h

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "GyverTimer.h"   

GTimer myTimer(MS);  

const char* ssid     = "videooko.net";     
const char* password = "*********";
const uint_fast16_t  DEVID = 999;

#define RST_PIN         27          
#define SS_PIN          25         

MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class

MFRC522::MIFARE_Key key; 
unsigned long uidDec, uidDecTemp;
int run = 0;

// Init array that will store new NUID 
byte nuidPICC[4];

/**
 * Helper routine to dump a byte array as hex values to Serial. 
 */
void printHex(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

/**
 * Helper routine to dump a byte array as dec values to Serial.
 */
void printDec(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], DEC);
  }
}

String server = "cardserver.videooko.net"; 
String unitID_in;


void handleReceivedMessage(String message) {
  StaticJsonDocument<500> doc;    //Memory pool. Поставил наугад для демонстрации

  DeserializationError error = deserializeJson(doc, message);

  // Test if parsing succeeds.
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
  /*   0 - GOOD not errors
       1 - Card is not connect to people
       2 - Card not activ
       3 - Card Blocking
       4 - Card UNKNOWN     */   
  Serial.println();
  Serial.println("----- DATA FROM CARD SERVER!!!  ----");

  const char* kod = doc["kod"];
  Serial.print("KOD CARD: ");
  Serial.println(kod);

  int c_status = doc["status"];
  Serial.print("Status card: ");
  Serial.println(c_status);

  int c_error = doc["error"];
  Serial.print("Error: ");
  Serial.println(c_error);
  Serial.println("------------------------------");

}


void sendhttpserver(){
    HTTPClient http;  
    String getstr;
    //Serial.println ("SEND to Server!!!");
    String mystr = String(uidDec);
    getstr = "http://"+server+"/check.php";
    http.begin(getstr);
    int httpCode = http.POST(getstr);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
      // Data to send with HTTP POST
    String httpRequestData = "kod="+mystr+"&id="+DEVID+"&GPS1=0&GPS2=0";           
    int httpResponseCode = http.POST(httpRequestData);
      //Serial.println(httpRequestData);
    if (httpCode > 0) {
      // выводим ответ сервера
      String payload = http.getString();
     // Serial.println(httpCode);
    //  Serial.println(payload);
      handleReceivedMessage(payload);
    }
    else {
      Serial.println("Помилка HTTP-запросу");
    }
    http.end();
}


void setup() { 
  Serial.begin(115200);
  while (!Serial);
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println(F("==========================================="));
  
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522 

  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }

  Serial.println(F("This code scan the MIFARE Classsic NUID."));
  Serial.print(F("Using the following key:"));
  printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
  
  Serial.println('\n');
  WiFi.begin(ssid, password);             // Connect to the network
  while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
    delay(500);
    Serial.print('.');
  }
  Serial.println('\n');
  Serial.println("Connection established");  
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); 
  //LedsSetup();
  myTimer.setInterval(3000);
}
 
void loop() {
  if (myTimer.isReady()) rfid.PCD_Init();

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! rfid.PICC_IsNewCardPresent()){
    //Serial.println(F("PICC_IsNewCardPresent"));
    //delay(5);
    return;
  }

  // Verify if the NUID has been readed
  if ( ! rfid.PICC_ReadCardSerial()){
    Serial.println(F("PICC_ReadCardSerial"));
    delay(5);
    return;
  }

  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  Serial.println(rfid.PICC_GetTypeName(piccType));

  // Check is the PICC of Classic MIFARE type
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  
    piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
    piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("Your tag is not of type MIFARE Classic."));
    return;
  }

  if (rfid.uid.uidByte[0] != nuidPICC[0] || 
    rfid.uid.uidByte[1] != nuidPICC[1] || 
    rfid.uid.uidByte[2] != nuidPICC[2] || 
    rfid.uid.uidByte[3] != nuidPICC[3] ) {
    Serial.println(F("A new card has been detected."));

    uidDec = 0;
    // Store NUID into nuidPICC array
    for (byte i = 0; i < 4; i++) {
      nuidPICC[i] = rfid.uid.uidByte[i];
      uidDecTemp = rfid.uid.uidByte[i];
      uidDec = uidDec * 256 + uidDecTemp;
    }
  

  
  //  Serial.print("Card UID: ");
  //  Serial.println(uidDec); // Виводимо UID в консоль.
    run=1;
    unitID_in = uidDec;


  }
  else { 
    Serial.println(F("Card read previously.")); 
    run=0;
  }

  // Halt PICC
  rfid.PICC_HaltA();

  // Stop encryption on PCD
  rfid.PCD_StopCrypto1();

  if (run){
    //Serial.println("RUN GAME - 1");
    sendhttpserver();
    run=0;
  }
}

Даний скетч сканує карту і по http відправляє дані на вказаний сервер. Відповідь приходить JSON його і розбираємо.

В процесі роботи з цим скетчем мені прийшов запит на розробку проекту обліку проїзду в міському транспорті жителів пільгової категорії. Такий собі бюджетний проект невеликого міста в Україні. Їм сподобалися напрацювання мого проекту СКУД на ардуїні, тому зацікавилися на його базі впровадити аналогічну систему на міському транспорті.

Визначено наступні умови

  1. Транспорт вже має або матиме у себе штатний WIFI з підключенням до інтернету.
  2. Всі запити повинні передаватися в режимі онлайн на сервер, де буде відбуватися перевірка електронних карток.
  3. Зчитувачі в транспорті не зберігають жодної інформації про картки. Режим роботи тільки онлайн.
  4. Розробка веб-додатку для роботи з картками.

Мінімальний веб-інтерфейс для роботи з картками.

Огляд тестового веб інтерфейсу

Отже, зчитувач… Для візуалізації обробки помилок і виняткових ситуацій зчитувач необхідно укомплектувати додатковою світловою індикацією.

Перша проба зчитувача

Тестування макету считувача RFID

Допрацьована версія в корпусі

На цьому етапі проект поки що зупинився в очікуванні подальшої зацікавленості в його розвитку або впровадженні.

2 коментарі до “СКУД «MAX» – бездротовий зчитувач RFID на ESP8266 або ESP32”

  1. Добрый день! Почему при компиляции скетча ошибка? –
    sketch_sep16a:86:16: error: no matching function for call to ‘HTTPClient::HTTPClient()’
    86 | HTTPClient http;

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *