Skip to main content

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/await and httpx for 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 where clauses, strict modify_objects routing, 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_users table).
  • 🔄 Safe UUID Handling: Built-in methods to serialize data seamlessly into strictly typed JSON structures (stringifying non-standard primitives) preventing pipeline execution failures in loosely coupled components.
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)

# Fingerprint capture uses ControlID's `biometry` enrollment type.
await client.remote_enroll(
    user_id=10,
    credential_type="fingerprint",
    save=True,
    sync=True,
)

# Read a card without creating a card or user record on the terminal.
card = await client.remote_enroll(
    user_id=None,
    credential_type="rfid_card",
    save=False,
    sync=True,
)
print(card["card_value"])

📱 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 & Control

Get diagnostic data and perform administrative hardware actions.

# 1. Fetch extensive system telemetry
info = await client.get_system_information()
print(f"Serial:  {info['serial']}")
print(f"Version: {info['version']}")

# 2. Synchronize Clock (force device to use current UTC)
import time
await client.set_system_time(int(time.time()))

# 3. Administrative Actions
# await client.reboot()
# await client.generate_device_id() # Force cloud ID refresh

🕒 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

Firmware Compatibility Matrix

Since ControlID access control terminals run varying firmware versions, some API fields and tables may not be supported on all devices:

Feature / Model iDFace iDAccess / iDFlex iDBlock / Turnstiles Notes
Card.type ⚠️ Supported only on newer firmware ⚠️ Supported only on newer firmware N/A Older firmwares lack the type column in the cards table. Exclude it by leaving Card.type = None.
Custom Database Fields ✅ Fully Supported ⚠️ Depends on firmware version N/A Add custom fields (e.g. cpf to c_users) via client.add_custom_field().
Facial Templates ✅ Fully Supported N/A N/A Enrollment and image upload functions require a device camera sensor.

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 comprehensive run_tests.py that validates the entire API sequentially against live hardware.

License

MIT

Metadata

Release files for controlid-sdk 0.4.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for controlid-sdk 0.4.5
File Size Uploaded
controlid_sdk-0.4.5.tar.gz 24.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for controlid-sdk 0.4.5
File Interpreter ABI Platform
controlid_sdk-0.4.5-py3-none-any.whl Python 3 none any Details

Total release size: 43.4 kB

Release files / controlid_sdk-0.4.5.tar.gz

Download URL controlid_sdk-0.4.5.tar.gz
Size 24.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e479d1c74a0e729ad7b08707f4a78a9e72eaaeed995d82d2b8ba2687e003bdfa
BLAKE2b-256 checksum
How to use checksums
11496857a69d1fdc7048ae5f7ee0227bd21094b801da7efabe8c5e408fe8b64f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / controlid_sdk-0.4.5-py3-none-any.whl

Download URL controlid_sdk-0.4.5-py3-none-any.whl
Size 19.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
01c5d0bbc7a7c0667333060f5f2eee04c7f8dd641ef66920b8efd0eb0add0641
BLAKE2b-256 checksum
How to use checksums
9ef2ac2e8deea18bdead0c6502a3cd05bf815b117e8197bc524bd9ec1e7585ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

0.4.7

2 release files

This release

0.4.5 This release

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page