Aakvatech Limited - HFSECURITY X05

Practical Guide to integrate an HFSECURITY X05 (or similar biometric terminal) with Frappe/ERPNext, you typically choose one of four patterns depending on what the device/SDK actually exposes.

 · 3 min read

1) Pick the integration pattern (best → worst)

A) Device pushes events to your server (HTTP webhook)

Best: near real-time, no polling, fewer duplicates. If the device can be configured to POST attendance logs to a URL (some devices call this “ADMS”, “cloud”, “push”, “HTTP upload”), do this.

Frappe side

  • Create an endpoint: /api/method/your_app.api.attendance_ingest
  • Validate payload + device token
  • Insert into an “Attendance Raw Log” doctype
  • Deduplicate by (device_id, user_id, timestamp, event_type)

B) Frappe polls device API (REST/TCP SDK wrapper)

If the X05 SDK provides a network API (REST/JSON or a TCP protocol), you run a scheduled pull.

  • Frappe Scheduled Job every 1–5 minutes
  • Pull “new logs since last_cursor”
  • Store raw logs → transform into ERPNext Attendance

C) Device exports logs to CSV/Excel (manual or shared folder)

Fallback when API is unavailable. You can still automate:

  • Upload file to Frappe (File doctype)
  • Background job parses + imports

D) Direct database access to device storage

Rare and fragile. Avoid unless vendor explicitly supports it.


2) What to build in Frappe (clean architecture)

Create a custom app (e.g. biometric_integration) with these doctypes:

  1. Biometric Device
  • device_id (unique)
  • name
  • ip/host, port
  • mode (PUSH / PULL / FILE)
  • auth_token / api_key
  • last_sync_at
  • last_cursor (string/int depending on API)
  1. Biometric User Map
  • device_user_id (e.g. employee code on device)
  • employee (Link to Employee)
  • Optional: biometric_type / site
  1. Attendance Raw Log
  • device (Link)
  • device_user_id
  • event_time (Datetime)
  • event_type (IN/OUT/UNKNOWN)
  • source_payload (JSON text)
  • hash (unique) for dedupe

Then a transformer that converts Raw Logs → ERPNext:

  • either directly creates Employee Checkin (recommended if you use ERPNext Shift/Attendance tooling)
  • or directly creates Attendance if you have a simpler policy

3) Minimal webhook endpoint (PUSH) in Frappe

Create your_app/api.py:

import frappe
import hashlib
import json

@frappe.whitelist(allow_guest=True)
def attendance_ingest():
    # Read raw body
    raw = frappe.request.get_data(as_text=True) or "{}"
    data = json.loads(raw)

    # Example: simple token auth (customize)
    token = frappe.get_request_header("X-Device-Token")
    device_id = data.get("device_id")
    device = frappe.get_doc("Biometric Device", {"device_id": device_id})
    if token != device.auth_token:
        frappe.throw("Unauthorized", frappe.PermissionError)

    events = data.get("events", [])
    inserted = 0

    for e in events:
        device_user_id = str(e.get("user_id"))
        event_time = e.get("time")  # ISO string expected
        event_type = (e.get("type") or "UNKNOWN").upper()

        # Dedup hash
        key = f"{device_id}|{device_user_id}|{event_time}|{event_type}"
        h = hashlib.sha1(key.encode()).hexdigest()

        if frappe.db.exists("Attendance Raw Log", {"hash": h}):
            continue

        doc = frappe.get_doc({
            "doctype": "Attendance Raw Log",
            "device": device.name,
            "device_user_id": device_user_id,
            "event_time": event_time,
            "event_type": event_type,
            "hash": h,
            "source_payload": json.dumps(e),
        })
        doc.insert(ignore_permissions=True)
        inserted += 1

    frappe.db.commit()
    return {"ok": True, "inserted": inserted}

Then add a background job to transform Raw Logs into Employee Checkin (or Attendance), to keep ingestion fast and reliable.


4) Scheduled polling job (PULL) skeleton

In hooks.py:

scheduler_events = {
  "cron": {
    "*/2 * * * *": [
      "your_app.jobs.pull_attendance"
    ]
  }
}

In your_app/jobs.py:

import frappe

def pull_attendance():
    devices = frappe.get_all("Biometric Device",
                            filters={"mode": "PULL", "disabled": 0},
                            fields=["name", "device_id", "host", "port", "last_cursor"])

    for d in devices:
        # 1) call vendor SDK / REST API here to fetch new events since last_cursor
        # events, new_cursor = fetch_from_device(d.host, d.port, d.last_cursor)

        # 2) insert into Attendance Raw Log (same dedupe approach)
        # 3) update last_cursor, last_sync_at
        pass

Your fetch_from_device() will depend on what the X05 SDK provides (REST endpoints vs a DLL/so vs Android SDK).


5) Practical integration tips (the stuff that saves you days)

  • Always store raw logs first, then transform. Raw logs are your audit trail.
  • Deduplicate aggressively. Devices often resend.
  • Use Employee Checkin if you want shifts, late/early, policies. It’s the cleanest ERPNext path.
  • Handle offline clock drift: store device time and server receive time; consider NTP on device.
  • If you have multiple sites/devices, include device/site in the mapping.

No comments yet.

Add a comment
Ctrl+Enter to add comment