IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP32 & Cảm biến: Bài 38 – Đọc cảm biến vân tay AS608 / R307: nhận diện vân tay & theo dõi realtime

Cảm biến vân tay AS608 / R307 là lựa chọn rất phổ biến trong các dự án IoT kiểm soát truy cập: cửa thông minh, tủ đồ, phòng lab, máy chấm công mini… Module xử lý toàn bộ thuật toán nhận dạng bên trong, ESP32 chỉ cần giao tiếp UART → ổn định, dễ triển khai, phù hợp production nhỏ.

1) AS608 / R307 làm được gì?

Hai module này có tính năng gần như tương đương:

  • Đăng ký (Enroll) vân tay
  • Nhận diện (Match / Search)
  • Lưu ID vân tay trong bộ nhớ trong
  • Trả về kết quả nhận dạng + độ tin cậy
  • Giao tiếp UART TTL

Thông số chính

  • Điện áp: 3.3 – 5V
  • Giao tiếp: UART
  • Tốc độ baud mặc định: 57600
  • Bộ nhớ: ~ 100–200 vân tay (tuỳ module)

👉 Điểm mạnh: không cần xử lý ảnh hay ML trên ESP32.

2) Use case IoT thực tế

  • Khoá cửa thông minh
  • Check-in phòng học / phòng lab
  • Tủ thiết bị cá nhân
  • Access control cho IoT Gateway
  • Kết hợp dashboard + log truy cập realtime

3) Chuẩn bị phần cứng

  • ESP32 (DevKit / ESP32-C3 / ESP32-S3)
  • Cảm biến vân tay AS608 hoặc R307
  • Dây jumper
  • (Tuỳ chọn) relay / solenoid lock để mở khoá

4) Nối dây AS608 / R307 ↔ ESP32 (UART)

Module thường có các chân: VCC, GND, TX, RX

Kết nối khuyến nghị (ESP32 dùng UART2):

FingerprintESP32
VCC5V (hoặc 3V3 nếu module hỗ trợ)
GNDGND
TXGPIO16 (RX2)
RXGPIO17 (TX2)

📌 Lưu ý:

  • TX của sensor → RX của ESP32
  • RX của sensor → TX của ESP32

5) Nguyên lý hoạt động

  1. ESP32 gửi lệnh qua UART
  2. Cảm biến:
    • Quét vân tay
    • So sánh với DB nội bộ
  3. Trả về:
    • finger_id
    • confidence
    • match / no match
  4. ESP32:
    • Gửi kết quả lên IoT Dashboard
    • Có thể kích hoạt relay / action

6) Cài thư viện Arduino

Trong Arduino IDE → Library Manager:

  • Adafruit Fingerprint Sensor Library

Thư viện này hỗ trợ tốt cho AS608 / R307.

7) Code

Ví dụ 1 — Serial-only (đọc vân tay local + in Serial Monitor)

Mục tiêu:

  • Kiểm tra wiring UART đúng chưa
  • Sensor có phản hồi không
  • Quét vân tay → in ra Matched/Not matched, ID, Confidence
  • Không Wi-Fi/MQTT (chạy đơn giản, ổn định để debug)
#include <Arduino.h>
#include <Adafruit_Fingerprint.h>

#define FP_RX 16
#define FP_TX 17
#define FP_BAUD 57600

HardwareSerial FPSerial(2);
Adafruit_Fingerprint finger(&FPSerial);

void setup() {
  Serial.begin(115200);
  delay(200);

  FPSerial.begin(FP_BAUD, SERIAL_8N1, FP_RX, FP_TX);
  finger.begin(FP_BAUD);

  Serial.println("=== Fingerprint Serial-only Test ===");

  if (!finger.verifyPassword()) {
    Serial.println("[ERROR] Fingerprint sensor not found or wrong password!");
    while (true) delay(1000);
  }

  Serial.println("[OK] Fingerprint sensor ready.");
  Serial.println("Place your finger on the sensor...");
}

void loop() {
  // 1) Capture image
  uint8_t p = finger.getImage();
  if (p == FINGERPRINT_NOFINGER) {
    delay(80);
    return;
  }
  if (p != FINGERPRINT_OK) {
    Serial.println("[WARN] getImage failed");
    delay(200);
    return;
  }

  // 2) Convert image to template
  p = finger.image2Tz();
  if (p != FINGERPRINT_OK) {
    Serial.println("[WARN] image2Tz failed");
    delay(200);
    return;
  }

  // 3) Search in database
  p = finger.fingerFastSearch();
  if (p == FINGERPRINT_OK) {
    Serial.print("[MATCH] ID=");
    Serial.print(finger.fingerID);
    Serial.print(" | confidence=");
    Serial.println(finger.confidence);
  } else {
    Serial.println("[NO MATCH] Finger not recognized");
  }

  // Small delay to avoid spamming
  delay(800);
}

✅ Kết quả Serial kỳ vọng:

  • [OK] Fingerprint sensor ready.
  • Đặt tay: hiện [MATCH] ID=... confidence=... hoặc [NO MATCH]

Ví dụ 2 — IoT / MQTT (đọc vân tay + gửi log realtime lên Cloud)

Mục tiêu:

  • Nhận diện vân tay
  • Gửi event lên MQTT để IoT Dashboard hiển thị log realtime
  • Format event gọn, dễ mở rộng
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Adafruit_Fingerprint.h>

#define FP_RX 16
#define FP_TX 17
#define FP_BAUD 57600

#define PUBLISH_COOLDOWN_MS 800

// WiFi
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";

// MQTT
const char* MQTT_HOST = "mqtt.iotlabs.vn";
const int   MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_USER";
const char* MQTT_PASS = "YOUR_PASS";

const char* PROJECT_ID = "demo_project";
const char* DEVICE_ID  = "esp32_fingerprint_01";

HardwareSerial FPSerial(2);
Adafruit_Fingerprint finger(&FPSerial);

WiFiClient espClient;
PubSubClient mqtt(espClient);

unsigned long lastPublish = 0;

uint32_t nowSeconds() {
  return (uint32_t)(millis() / 1000);
}

void wifiConnect() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(300);
}

void mqttConnect() {
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  while (!mqtt.connected()) {
    mqtt.connect(DEVICE_ID, MQTT_USER, MQTT_PASS);
    delay(500);
  }
}

void publishResult(bool matched, int fingerId, int confidence) {
  String topic = String("iotlabs/") + PROJECT_ID + "/" + DEVICE_ID + "/event";

  StaticJsonDocument<256> doc;
  doc["ts"] = nowSeconds();
  doc["type"] = "fingerprint";

  JsonObject data = doc.createNestedObject("data");
  data["matched"] = matched;
  data["finger_id"] = fingerId;
  data["confidence"] = confidence;

  char payload[256];
  size_t n = serializeJson(doc, payload, sizeof(payload));
  mqtt.publish(topic.c_str(), payload, n);
}

void setup() {
  Serial.begin(115200);
  delay(200);

  FPSerial.begin(FP_BAUD, SERIAL_8N1, FP_RX, FP_TX);
  finger.begin(FP_BAUD);

  Serial.println("=== Fingerprint MQTT Mode ===");

  if (!finger.verifyPassword()) {
    Serial.println("[ERROR] Fingerprint sensor not found!");
    while (true) delay(1000);
  }

  wifiConnect();
  mqttConnect();

  Serial.println("[OK] Ready. Place your finger...");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) wifiConnect();
  if (!mqtt.connected()) mqttConnect();
  mqtt.loop();

  // Rate-limit publishing
  if (millis() - lastPublish < PUBLISH_COOLDOWN_MS) {
    delay(50);
    return;
  }

  uint8_t p = finger.getImage();
  if (p == FINGERPRINT_NOFINGER) {
    delay(80);
    return;
  }
  if (p != FINGERPRINT_OK) {
    Serial.println("[WARN] getImage failed");
    delay(200);
    return;
  }

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK) {
    Serial.println("[WARN] image2Tz failed");
    delay(200);
    return;
  }

  p = finger.fingerFastSearch();
  if (p == FINGERPRINT_OK) {
    Serial.printf("[MATCH] ID=%d | confidence=%d\n", finger.fingerID, finger.confidence);
    publishResult(true, finger.fingerID, finger.confidence);
  } else {
    Serial.println("[NO MATCH]");
    publishResult(false, -1, 0);
  }

  lastPublish = millis();
}

So sánh

  • Ví dụ 1 (Serial-only)
    • ✅ Dễ test phần cứng, debug nhanh
    • ✅ Không phụ thuộc Wi-Fi/MQTT
    • ❌ Không có log dashboard, không lưu lịch sử
  • Ví dụ 2 (MQTT/Cloud)
    • ✅ Có log realtime trên IoT Dashboard
    • ✅ Dễ làm rule cảnh báo (failed attempts, ngoài giờ…)
    • ❌ Phụ thuộc Wi-Fi/MQTT (nên test bằng Ví dụ 1 trước)

8) Dashboard realtime

Realtime log:

  • Finger ID
  • Thời gian
  • Trạng thái: matched / failed
  • Confidence

Card gợi ý:

  • Total access today
  • Failed attempts
  • Last access user

Rule cảnh báo:

  • Failed > 5 lần / phút → cảnh báo an ninh
  • Truy cập ngoài giờ → notify admin

9) Quy trình đăng ký vân tay (Enroll)

Thông thường:

  1. Chạy sketch enroll (1 lần)
  2. Đặt vân tay 2–3 lần
  3. Gán finger_id
  4. Lưu vào bộ nhớ module

👉 Enroll không cần làm lại sau khi reset ESP32.

10) Gợi ý mở rộng

  • Kết hợp relay / khoá điện
  • Phân quyền user theo finger_id
  • Lưu lịch sử vào DB (audit log)
  • Kết hợp RFID + Fingerprint (2FA)
  • Offline-first: cho phép mở khoá ngay cả khi mất mạng