Case study

Syncing a Biometric Attendance Device With .NET

Ten days on a device that answered after a restart and went silent the moment anyone used it. The fix was not in the code, and shipping it meant admitting that.

.NETDevice SDKBackground workerHRMS
Role
Backend developer
Where
Vertex Special Technologies
When
Late 2024
01

What it needed to do

The HRMS we were building tracked attendance, leave and the rest of the employee lifecycle. Attendance was supposed to come from a physical biometric device on the wall: an employee puts a finger on it, and a few moments later that punch exists in our system, attached to the right employee, on the right date, ready for leave calculations and payroll.

Nobody wanted to think about the device. It was supposed to be one integration among many.

02

Why it was hard

An SDK with no home

There was an SDK. There was no official site to get it from. Finding a copy I could trust, and working out what it expected, cost days before a single line of integration code existed.

No response at all

Before any of that, it would not answer a plain ping. Not from the command line, not from anything I wrote. A device on the same network that does not respond gives you nothing to debug against.

Nothing to report

Four days in, still no working connection and no update worth giving the team. That is its own kind of pressure, and it changes how you debug: badly, and faster than you should.

03

Ten days

What made this hard was not difficulty. It was that the device was intermittently reachable, which is worse than never. Every time it answered, I believed the problem was solved.

  1. Days 1–4Every method I could find for reaching the device. No ping, no SDK, no response. No update to give.
  2. Day 5Away on graduation leave, twelve hours on a bus from Dharan. A call from my lead: it is working. The device answered a ping and the SDK read from it. I went home relieved.
  3. Day 6Back at the office. Brought the device to my desk. No ping. No SDK. Relief gone.
  4. Day 6First theory: our network. Client isolation on the router, something in the office WLAN blocking device-to-device traffic. Plausible, and wrong.
  5. Day 6Restarted the device. Ping worked. SDK worked. Same network as before, which quietly killed the router theory I had just built.
  6. Day 6Punched in to test a real record. Pinged again. Dead.
  7. Day 10The pattern, finally: the device answered after a restart and stopped answering the moment anyone punched in or out. Not the network. Not my code. The device dropped its network stack on use.

Ten days for one sentence. The reason it took that long is that the device kept producing evidence for whichever theory I had at the time. Working after a restart looked like a network fix. Failing at the office looked like a firewall. Every intermittent success sent me back down a path I had already been down.

There was nothing to read when it died. No status page, no log, no error. It went back to exactly the day-one condition: no answer to a ping, no answer to the SDK. A component that fails loudly tells you where to look. This one just left.

I never proved the mechanism. What I had was a reproducible rule — reachable after a restart, gone after a punch — and that turned out to be enough to make the decision.

04

The decision

At some point the right engineering answer stops being “debug harder” and becomes “this component is not fit for purpose.”

I had spent ten days on a device that could not stay on the network through a single fingerprint scan. I could have kept going: packet captures, firmware, the vendor. But the thing I was fighting was not going to become reliable, and the system I was building needed to sync attendance every day for years without anyone thinking about it.

So I stopped, wrote up what I had found, and recommended the company buy a different device: a ZKTeco unit with a documented SDK. That is a harder conversation than it sounds when you are a trainee ten days into a task with nothing to show. It reads as giving up.

The replacement was integrated in a day. SDK located, device reachable, reading logs, wired into the .NET project. The ten days were not the work. The ten days were finding out that the work was impossible with what I had.

What that bought

A documented SDK, a device that stays on the network, and an integration that has not needed defending since. Against roughly one day of procurement and an admission that the first ten days produced no code.

05

What I built

Before this, HR exported the data off the device by hand and moved it into the system. The integration replaces that export.

  • The ZKTeco SDK wrapped behind an interface, so the rest of the HRMS talks about attendance rather than about a device
  • A background worker service in .NET pulling attendance logs on a schedule
  • Punches resolved per employee per day: the first scan of the day is the clock-in, the last is the clock-out, and everything between is ignored

The schedule follows the office, not the clock

The worker runs twice a day, half an hour after each end of the working day. If the office starts at 9:00 it syncs at 9:30; if it ends at 18:00 it syncs at 18:30.

That is the whole design decision, and it comes from what the data means rather than from what the device could do. A day's attendance is two facts, and neither exists until people have arrived or left. Polling every few minutes would have produced the same two facts and a great deal more noise, at the cost of talking constantly to a device on an office network. Waiting until the answer exists, then asking once, was the smaller system.

The half hour is slack for people arriving late, and it means a sync that fails still has the rest of the day to be noticed and rerun.

We ran it at Vertex across 35+ employees. That is a small number, and it is the honest one: throughput was never the difficulty here. Two reads a day for a few dozen people is nothing to a background worker. The hard part was a device that had to answer both times, every working day, without anyone remembering it existed.

06

What I would do differently

Time-box the unknown

Four days of silence was too long. A day and a half of “I cannot reach this device at all” should have been escalated, not absorbed. The information that the hardware might be the problem was worth more to the team early than a working integration was late.

Write down the evidence

I kept the state of the investigation in my head, which is why an intermittent device could keep resetting my theories. A log of what I tried and what happened would have surfaced the punch-in pattern days earlier.