A production-ready asynchronous Python SDK for ControlID access control devices, supporting biometrics, networking, and complex time schedules.
Project description
ControlID Python SDK (Async)
A production-ready, high-performance asynchronous Python SDK for ControlID access control devices (iDAccess, iDFace, iDFlex, iDBlock, etc.).
Built on top of httpx and pydantic v2, this SDK provides robust abstractions over the ControlID API, gracefully handling undocumented firmware quirks, session management, and complex data schemas.
Features
- ⚡️ Fully Asynchronous: Built exclusively on
async/awaitandhttpxfor high-concurrency non-blocking I/O. - 🔑 Automatic Session Management: Handles logins and injects secure, URL-encoded tokens into requests.
- 🛡️ Pydantic Validation: Robust, type-hinted data models (
User,Card,AccessRule, etc.). - 🛠️ Quirk Resolution: Automatically manages device-specific API quirks (e.g., nested
whereclauses, strictmodify_objectsrouting, implicit schema limitations). - 📸 Facial Recognition: Push direct binary payload image uploads for iDFace enrollment.
- 📱 QR Code Support: Generate and register CRC-32 QR Code credentials safely.
- 🚪 Advanced Hardware Control: Interact with relays, GPIO pins, SecBoxes, turnstiles (catras), and ballot boxes.
- 📋 Dynamic Schemas: Native support for creating and interacting with custom device fields (
c_userstable).
Installation
pip install controlid-sdk
Quick Start
import asyncio
from controlid import ControlIDClient, User
async def main():
# Use as an async context manager for automatic session cleanup.
# We use verify=False typically because devices use self-signed SSL certificates.
async with ControlIDClient(
host="https://192.168.0.100",
user="admin",
password="password",
verify=False
) as client:
# 1. Fetch Users
users = await client.get_users()
print(f"Found {len(users)} users on device.")
# 2. Add a new user
user_id = await client.add_user(User(name="Jane Doe", registration="EMP-001"))
print(f"Created user with ID: {user_id}")
# 3. Open a Door (using internal relay)
await client.open_door(door_id=1)
# Or using an external SecBox (standard on iDFace/iDFlex installations)
# await client.open_sec_box(box_id=65793)
if __name__ == "__main__":
asyncio.run(main())
Supported Workflows
This SDK provides extensive high-level wrappers. Below are just a few examples.
(For complete runnable scripts, check the examples/ directory).
📸 Facial Recognition & Photo Upload
Unlike standard JSON requests, facial photo enrollment requires raw binary streaming.
The iDFace firmware is famously strict: if you upload a high-resolution, dense portrait (like a 2MB iPhone photo) or images where the face isn't perfectly centered, the device will silently reject the neural-network validation with a 400 Bad Request.
Our SDK examples handle this elegantly by using Pillow to instantly downscale huge images to < 40KB and < 600x600px before uploading:
from examples import helper
# Automatically loops through photos, shrinks them flawlessly, and registers the face!
await helper.enhance_user(client, user_id=10, user_ref="EMP")
Alternatively, you can skip local uploads entirely and trigger the device's physical screen so the person can enroll themselves live at the gate!
# The iDFace terminal will open its camera, display a 5-second countdown,
# analyze liveness, and automatically save the biometric hash!
await client.remote_enroll_face(user_id=10, auto=True, countdown=5)
📱 QR Code Credentials
The device expects CRC-32 integers when scanning standard QR codes. The SDK can help you register them correctly.
import binascii
def qr_hash(text: str) -> int:
return binascii.crc32(text.encode()) & 0xFFFFFFFF
# Give a user a QR code credential that matches the text "VISITOR-99"
await client.add_qr_code(user_id=10, qr_value=qr_hash("VISITOR-99"))
Note: Our examples/helper.py will automatically generate and save physical .png files of the QR Codes so you can test them instantly on your screen or phone.
🏢 Departments, Groups, and Access Rules
Organize your users logically and restrict their access using Rules and Groups.
# 1. Create a Department
group_id = await client.create_group("Engineering")
# 2. Create an Access Rule (e.g., 1 = Always Allowed, Priority = 0)
rule_id = await client.create_access_rule("24/7 Access", rule_type=1)
# 3. Link the Group to the Rule
await client.assign_group_access_rule(group_id, rule_id)
# 4. Add the user to the Group
await client.add_user_to_group(user_id=10, group_id=group_id)
🧩 Custom Fields (c_users)
Extend the device's native database schema dynamically to store your own business logic (e.g., CPF, Department Code).
from controlid import CustomField
# 1. Create the schema column (run once per device)
await client.add_custom_field(CustomField(
column_name="cpf",
name="CPF Number",
type="TEXT"
))
# 2. Write data for a specific user
await client.set_custom_user_data(user_id=10, cpf="123.456.789-00")
# 3. Read it back
custom_data = await client.get_custom_user_data(user_id=10)
print(custom_data) # {'cpf': '123.456.789-00', 'user_id': 10}
⚙️ System Monitoring
Get full diagnostic data from the device including uptime, memory usage, network details, and firmware version.
# Fetch extensive system telemetry
info = await client.get_system_information()
print(f"Uptime: {info['uptime']['days']} days")
print(f"Memory: {info['memory']['ram']['free']} / {info['memory']['ram']['total']} bytes")
print(f"MAC: {info['network']['mac']}")
print(f"Serial: {info['serial']}")
print(f"Version: {info['version']}")
🕒 Time Zones & Access Schedules
Define exactly when certain users or groups are allowed to enter.
from controlid import TimeSpan
# 1. Create a fuso horário
tz_id = await client.create_time_zone("Standard Business")
# 2. Add specific spans (intervals)
# Example: Mon-Fri, 08:00 (28800s) to 18:00 (64800s)
await client.add_time_spans([
TimeSpan(time_zone_id=tz_id, start=28800, end=64800, mon=1, tue=1, wed=1, thu=1, fri=1)
])
🧩 Generic Object API
Directory Structure
src/controlid/client.py: Core asynchronous logic and endpoints.src/controlid/models.py: Pydantic V2 definitions.src/controlid/constants.py: Enums and endpoint tables.examples/*.py: Fully self-contained scripts demonstrating every major use-case. Including a comprehensiverun_tests.pythat validates the entire API sequentially against live hardware.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file controlid_sdk-0.3.1.tar.gz.
File metadata
- Download URL: controlid_sdk-0.3.1.tar.gz
- Upload date:
- Size: 17.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7f34a984cf2fc727d30f12ad6a11e45b64305951795a79b7f62f1434a2ce1aa
|
|
| MD5 |
4cac837ef88666aa3a339313fb6c9ec3
|
|
| BLAKE2b-256 |
502a214ec14ea7d1aee270f342f4dcff08c31e3a97d1906dd9b9d309139420bc
|
File details
Details for the file controlid_sdk-0.3.1-py3-none-any.whl.
File metadata
- Download URL: controlid_sdk-0.3.1-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76bd4f8ddfb144c8fee3eac7f6181f60e63cb357d61d68e9dc378b801cfaf434
|
|
| MD5 |
102583db990d4faa51e08ccdfb1f1867
|
|
| BLAKE2b-256 |
34c7dbdaaaed5090bd4c67e7c3fcf79a74bb7de57f91a35696d93d09bc8491f4
|