СКУД “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);  // создать миллисекундный таймер (ms) (по умолч. в режиме интервала)

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

#define RST_PIN         27           // Configurable, see typical pin layout above
#define SS_PIN          25          // Configurable, see typical pin layout above

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 адреса не оприлюднюватиметься. Обов’язкові поля позначені *