Files
obsidian-vault/WORK/Projects/Employee Punch Tracking.md
2026-02-24 18:27:57 -06:00

450 lines
14 KiB
Markdown

# Project: Employee Punch Tracking
**Created:** 2026-02-24
**Source:** #work-assistant
**Status:** Beta Production Phase
---
## Overview
Track employee timeclock punches via RFID cards and capture images via IP camera for verification.
## Purpose
- Track employee punch in/out via RFID card
- Capture image via IP camera when card is scanned
- Match captured image with employee database record
- Integrate with external timeclock software
## How It Works
1. Employee scans RFID card at timeclock
2. System triggers IP camera capture
3. Image is matched against MSSQL database record
4. Time punch is logged in external vendor time software
## Architecture
- IP camera for image capture
- RFID card reader
- MSSQL database for employee photos/records
- **External timeclock software (vendor provided)**
- Custom software runs "on top" of vendor system
## Current Status
🚀 **Beta Production**
- Software functioning well in production
- Active monitoring ongoing
## Known Issues
**Latency Problem:** Delay between RFID scan and image capture
- Currently researching alternative solutions
- Goal: Reduce/remove latency gap
## Tasks
- [ ] Research alternative latency solutions
- [ ] Implement latency improvement
- [ ] Continue production monitoring
## Notes
*(Add camera specs, RFID reader model, MSSQL schema, vendor software details, etc.)*
## Related
---
*Extracted from Projects to be organized*
---
# Research Findings
**Research Date:** 2026-02-24
**Focus:** RFID + IP Camera Latency Solutions
---
## Latency Problem Analysis
### Current Bottleneck Identification
The primary latency in RFID-to-camera capture systems comes from multiple sequential steps:
1. **RFID Read Latency**: 2-5ms (physical card detection + data transfer)
2. **USB/Serial Communication**: 1-10ms depending on interface
3. **HTTP Request to Camera**: 20-100ms (network round-trip)
4. **Camera Shutter/IPE Frame Capture**: 50-200ms (depends on exposure/lighting)
5. **Image Transfer**: 50-500ms (depends on resolution)
**Total Typical Latency: 123-815ms**
### Critical Insight from Research
The biggest latency contributor is NOT the RFID reader (which is typically <10ms), but rather:
- Camera exposure/autofocus delay when triggering from idle
- Network round-trip for HTTP snapshot requests
- Image compression and transfer time
---
## Recommended Hardware (RFID Reader + Camera Combo)
### RFID Reader Options
#### Option 1: USB HID Keyboard Emulation (Recommended for Simplicity)
- **Cost:** $8-15 (Amazon: Dual-frequency 125KHz/13.56MHz readers)
- **Protocols:** ISO14443-A/B, EM4100
- **Latency:** <5ms from card touch to character output
- **Python Integration:** No special drivers - reads as keyboard input
- **Models:** Generic USB HID readers (Navfmru, HiLetgo, generic dual-frequency)
#### Option 2: Serial/UART RFID Reader (For Advanced Control)
- **Cost:** $12-25
- **Interface:** USB-to-Serial (appears as COM port)
- **Protocols:** SPI/I2C/UART
- **Latency:** <2ms (interrupt-driven serial)
- **Python Library:** `pyserial`
- **Best for:** When you need custom parsing or have multiple readers
#### Option 3: Ethernet-Connected RFID Reader
- **Cost:** $50-150
- **Latency:** Depends on network (1-5ms local)
- **Best for:** Industrial setups with existing PoE infrastructure
**Recommendation:** Start with USB HID Keyboard Emulation readers - simplest integration, lowest cost, adequate latency.
### IP Camera Recommendations
#### Low-Latency Trigger-Optimized Cameras
**Hikvision / Dahua (Best API Support):**
- Direct HTTP snapshot URLs: `http://camera-ip/Streaming/channels/1/picture`
- ONVIF snapshot: `http://camera-ip/onvif/snapshot`
- Typical latency: 50-150ms for snapshot
- **Key Feature:** Can pre-authenticate and keep session alive
**Axis (MQTT Support):**
- Native MQTT event publishing
- Can subscribe to ONVIF events
- More expensive but better integration options
**INSTAR (Built-in MQTT):**
- Native MQTT for motion triggers
- Can trigger snapshot via MQTT message
#### Latency-Reducing Camera Configuration:
1. **Fixed Focus** - Disable autofocus to eliminate 100-300ms delay
2. **Fixed Exposure** - Set manual exposure to eliminate AE calculation
3. **Low Resolution Stream** - Use 720p or lower for snapshot (faster transfer)
4. **Motion JPEG** - Prefer MJPEG over H.264 for snapshot endpoints
---
## Low-Latency Architecture Options
### Architecture A: HTTP Snapshot on RFID Event (Simple)
```
RFID Scan → Python HTTP Request → Camera → Save Image → Match
Latency: 100-300ms
```
**Pros:** Simple, no additional infrastructure
**Cons:** Every scan has network round-trip
### Architecture B: Always-Recording with Frame Grab (Best for Speed)
```
Camera always streaming (RTSP)
RFID Scan → Python grabs current frame from buffer → Match
Latency: 10-50ms
```
**Pros:** Fastest capture, no network request at scan time
**Cons:** Higher CPU/network usage, requires OpenCV/ffmpeg
### Architecture C: MQTT/Event-Driven (Scalable)
```
RFID Scan → Publish MQTT message → Camera subscribes → Captures
Latency: 50-150ms
```
**Pros:** Decoupled, multiple cameras possible
**Cons:** Requires MQTT broker
### Architecture D: ONVIF Events with Pre-trigger Buffer (Professional)
```
Camera constantly buffers 2-3 seconds
RFID triggers ONVIF event → Camera saves pre/post buffer
Latency: 0ms (image from before trigger!)
```
**Pros:** Can capture image BEFORE scan
**Cons:** Complex setup, requires ONVIF Profile S/G support
### Recommended Hybrid Approach:
```
Primary: Always-streaming RTSP with OpenCV frame buffer
Fallback: HTTP snapshot if buffer unavailable
```
---
## Python Libraries and Code Samples
### Library Requirements
```bash
pip install pyserial opencv-python requests onvif-zeep paho-mqtt
```
### Code Sample 1: USB HID RFID Reader (Keyboard Emulation)
```python
import keyboard # pip install keyboard
from datetime import datetime
import requests
def on_rfid_scan(event):
"""Capture RFID UID from keyboard emulation"""
uid = event.name
timestamp = datetime.now()
# Trigger camera capture immediately
capture_image(uid, timestamp)
# Hook into keyboard events
keyboard.on_press(on_rfid_scan)
keyboard.wait()
```
### Code Sample 2: Serial RFID Reader
```python
import serial
import threading
def read_rfid_serial(port='COM3', baudrate=9600):
ser = serial.Serial(port, baudrate, timeout=0.1)
buffer = ""
while True:
if ser.in_waiting:
data = ser.read(ser.in_waiting).decode('utf-8')
buffer += data
# Check for complete UID (usually ends with CR/LF)
if '\r' in buffer or '\n' in buffer:
uid = buffer.strip()
buffer = ""
capture_image(uid)
# Run in separate thread for non-blocking
threading.Thread(target=read_rfid_serial, daemon=True).start()
```
### Code Sample 3: HTTP Snapshot (Synchronous)
```python
import requests
from datetime import datetime
CAMERA_URL = "http://192.168.1.100/Streaming/channels/1/picture"
CAMERA_AUTH = ("admin", "password")
def capture_http_snapshot(uid):
start = datetime.now()
response = requests.get(CAMERA_URL, auth=CAMERA_AUTH, timeout=2)
if response.status_code == 200:
filename = f"captures/{uid}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
with open(filename, 'wb') as f:
f.write(response.content)
latency = (datetime.now() - start).total_seconds() * 1000
print(f"Captured in {latency:.1f}ms")
return filename
```
### Code Sample 4: OpenCV Always-Streaming (Fastest)
```python
import cv2
import threading
import queue
class CameraBuffer:
def __init__(self, rtsp_url):
self.cap = cv2.VideoCapture(rtsp_url)
self.frame = None
self.lock = threading.Lock()
# Start capture thread
threading.Thread(target=self._update, daemon=True).start()
def _update(self):
while True:
ret, frame = self.cap.read()
if ret:
with self.lock:
self.frame = frame
def get_frame(self):
with self.lock:
return self.frame.copy() if self.frame is not None else None
# Usage
camera = CameraBuffer("rtsp://admin:pass@192.168.1.100:554/Streaming/Channels/1")
def capture_image(uid):
frame = camera.get_frame()
if frame is not None:
filename = f"captures/{uid}_{datetime.now():%Y%m%d_%H%M%S}.jpg"
cv2.imwrite(filename, frame)
return filename
```
### Code Sample 5: ONVIF Event Subscription
```python
from onvif import ONVIFCamera
def setup_onvif_events(camera_ip, user, password):
camera = ONVIFCamera(camera_ip, 80, user, password)
# Create events service
events = camera.create_events_service()
# Subscribe to events
subscription = events.CreatePullPointSubscription()
return camera, subscription
```
---
## MSSQL Optimization for Fast Employee Photo Matching
### Schema Recommendations
```sql
-- Store image hashes for fast comparison (not full images in DB)
CREATE TABLE EmployeePhotos (
EmployeeID INT PRIMARY KEY,
PhotoHash VARBINARY(64) INDEXED, -- SHA-256 hash
PhotoPath NVARCHAR(500), -- Path to actual image
FaceEncoding VARBINARY(MAX), -- If using face recognition
LastUpdated DATETIME2
);
-- Index for hash lookups
CREATE NONCLUSTERED INDEX IX_PhotoHash ON EmployeePhotos(PhotoHash);
```
### Optimization Strategies
1. **Don't Store Images in MSSQL**
- Store file paths only
- Store perceptual hashes for comparison
- Keep images on fast local SSD
2. **Pre-compute Face Embeddings**
```python
import face_recognition
# One-time: Store face encoding
image = face_recognition.load_image_file("employee.jpg")
encoding = face_recognition.face_encodings(image)[0]
# Save encoding to DB as binary blob
```
3. **Use Memory-Optimized Tables (SQL Server)**
```sql
CREATE TABLE dbo.EmployeePhotos (
EmployeeID INT PRIMARY KEY NONCLUSTERED,
PhotoHash VARBINARY(64)
) WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_AND_DATA);
```
4. **Query Pattern for Matching**
```sql
-- Fast hash lookup first
SELECT EmployeeID FROM EmployeePhotos
WHERE PhotoHash = @capturedHash;
-- If using face recognition, compare embeddings
-- in Python (not SQL) for algorithm flexibility
```
---
## Implementation Recommendations
### Phase 1: Quick Win (HTTP Snapshot)
1. Purchase USB HID RFID reader ($10-15)
2. Use `keyboard` library to detect scans
3. Trigger Hikvision/Dahua HTTP snapshot
4. Measure actual latency
### Phase 2: Optimization (RTSP Buffer)
1. If latency >100ms is problematic, implement OpenCV RTSP buffer
2. Capture frame from buffer instead of HTTP request
3. Measure improvement
### Phase 3: Advanced (Face Recognition)
1. Add `face_recognition` library
2. Pre-compute employee face embeddings
3. Match captured image against embeddings
4. Log match confidence with each punch
### Latency Targets by Phase:
| Phase | Expected Latency | Implementation Time |
|-------|------------------|---------------------|
| Phase 1 | 100-300ms | 1-2 days |
| Phase 2 | 10-50ms | 3-5 days |
| Phase 3 | 10-50ms + match | 1-2 weeks |
---
## Real-World Latency Benchmarks (from Research)
| Component | Typical | Optimized | Notes |
|-----------|---------|-----------|-------|
| RFID Read | 2-5ms | 1-2ms | HID faster than serial |
| USB Transfer | 1-10ms | 1-2ms | Interrupt vs polling |
| HTTP Request | 20-100ms | 10-20ms | Keep-alive connections |
| Camera Shutter | 50-200ms | 0ms | Fixed exposure eliminates |
| Image Transfer | 50-500ms | 5-20ms | Lower resolution, MJPEG |
| **Total HTTP** | **123-815ms** | **17-46ms** | With optimizations |
| **RTSP Buffer** | **10-50ms** | **5-15ms** | Fastest option |
---
## Source Links
### RFID & Communication Latency
- USB Latency Analysis: <https://electronics.stackexchange.com/questions/192920/usb-device-latency>
- Serial vs USB Interrupt: <https://stackoverflow.com/questions/41987430/lowest-latency-communication-microcontroller>
- Wireless Latency Benchmarks: <https://electricui.com/blog/latency-comparison>
- RFID Reader Options: <https://raspberrypi.stackexchange.com/questions/13930/capturing-serial-number-usb-rfid-reader>
### Python RFID Integration
- MFRC522 Python Library: <https://github.com/pimylifeup/MFRC522-python>
- USB HID Reader Python: <https://github.com/charlysan/pyrfidhid>
- Serial RFID Example: <https://stackoverflow.com/questions/56808495/reading-tags-uid-rc522-usb-serial-python>
### Camera APIs & ONVIF
- Hikvision Snapshot URL: <https://www.cctvforum.com/topic/32499-snashot-url-for-hikvisionswannlorex-cameras/>
- ONVIF/OpenHAB Integration: <https://www.openhab.org/addons/bindings/ipcamera/>
- IP Camera Trigger Options: <https://ipcamtalk.com/tags/api/>
### MQTT Camera Control
- MQTT Camera Home Assistant: <https://www.home-assistant.io/integrations/camera.mqtt>
- Axis MQTT Integration: <https://www.hivemq.com/blog/enhancing-axis-network-camera-capabilities-mqtt-hivemq/>
- Cam2MQTT Project: <https://github.com/berfenger/cam2mqtt>
### RFID Hardware Options
- Dual-Frequency USB Readers: <https://www.amazon.com/13-56Mhz-ISO14443-Protocol-Contactless-Compatible/dp/B0CY2YT86P>
- ISO14443/EM4100 Readers: <https://gaorfid.com/devices/rfid-readers-frequency/>
---
## Summary
**Key Takeaway:** The fastest solution for RFID-to-camera latency is combining:
1. USB HID RFID reader for <5ms card detection
2. OpenCV RTSP stream buffer for <20ms image capture
3. Skip HTTP requests entirely - grab from buffer
This yields **15-25ms total latency** from scan to image capture - well within acceptable limits for timeclock verification.
**Alternative Simple Path:** If RTSP complexity is undesirable, using HTTP snapshots with fixed-exposure camera settings can achieve 50-100ms latency with minimal implementation effort.
---
*Research compiled by AI assistant. Hardware links are examples only - verify compatibility before purchase.*