{"id":50768709,"url":"https://github.com/kengggg/openzk","last_synced_at":"2026-06-11T16:02:54.479Z","repository":{"id":362314090,"uuid":"1258266117","full_name":"kengggg/openzk","owner":"kengggg","description":"A clean, read-only Python client for ZKTeco standalone devices (reverse-engineered SDK protocol). Zero deps, typed, MIT.","archived":false,"fork":false,"pushed_at":"2026-06-03T14:29:24.000Z","size":694,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T16:13:30.924Z","etag":null,"topics":["access-control","attendance","biometric","face-recognition","fingerprint","python","reverse-engineering","zkteco"],"latest_commit_sha":null,"homepage":"https://kengggg.github.io/openzk/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kengggg.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-03T12:23:54.000Z","updated_at":"2026-06-03T14:40:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kengggg/openzk","commit_stats":null,"previous_names":["kengggg/openzk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/kengggg/openzk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kengggg%2Fopenzk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kengggg%2Fopenzk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kengggg%2Fopenzk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kengggg%2Fopenzk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kengggg","download_url":"https://codeload.github.com/kengggg/openzk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kengggg%2Fopenzk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34206492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","attendance","biometric","face-recognition","fingerprint","python","reverse-engineering","zkteco"],"created_at":"2026-06-11T16:02:53.539Z","updated_at":"2026-06-11T16:02:54.474Z","avatar_url":"https://github.com/kengggg.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# openzk\n\n[![CI](https://github.com/kengggg/openzk/actions/workflows/ci.yml/badge.svg)](https://github.com/kengggg/openzk/actions/workflows/ci.yml)\n[![Docs](https://img.shields.io/badge/docs-kengggg.github.io%2Fopenzk-blue.svg)](https://kengggg.github.io/openzk/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)\n\n📖 **Documentation: [kengggg.github.io/openzk](https://kengggg.github.io/openzk/)**\n\nA clean, **read-only** Python client for ZKTeco standalone access-control / time-attendance\ndevices, speaking their proprietary TCP protocol (port 4370).\n\n`openzk` is a modern, dependency-free alternative to older ZK libraries: it implements the\n**modern SDK handshake** that legacy clients omit, derives its command set by\n**reverse-engineering the official SDK** (rather than guessing), uses **typed models**, and\nships an easy, well-tested high-level API.\n\n\u003e **Read-only by design.** v1 only reads from the device (users, attendance, templates,\n\u003e photos, options). It never writes, clears, unlocks, or reboots — safe to point at a\n\u003e production access-control terminal.\n\n## Install\n\nNo PyPI release yet — install from Git:\n\n```sh\npip install \"git+https://github.com/kengggg/openzk\"\n# or, with uv:\nuv add \"git+https://github.com/kengggg/openzk\"\n```\n\n`openzk` has **zero runtime dependencies** (pure Python standard library).\n\n## Quickstart\n\n```python\nfrom openzk import ZKDevice\n\nwith ZKDevice(\"\u003cDEVICE_IP\u003e\", port=4370, password=0) as dev:\n    print(dev.device_info())                 # serial, firmware, platform, counts, capabilities\n    for u in dev.users():                    # list[User]\n        print(u.user_id, u.name)\n    for att in dev.attendance():             # streamed iterator — won't load 100k rows at once\n        print(att.user_id, att.timestamp, att.status)\n    for log in dev.op_logs():                # operation log\n        ...\n    photo = dev.user_photo(\"8\")              # bytes | None (JPEG)\n    faces = dev.face_templates()             # list[FaceTemplate]\n    fps   = dev.fingerprint_templates()      # list[FingerTemplate]\n    val   = dev.option(\"FaceFunOn\")          # raw device option\n```\n\nThe context manager handles connect → auth → SDK handshake → capability read, and restores\ndevice state + disconnects on exit. Commands the device doesn't support raise\n`ZKNotSupported`; unreachable/auth/protocol failures raise typed errors\n(`ZKUnreachable`, `ZKAuthFailed`, `ZKProtocolError`).\n\n## Scope (v1)\n\n| Area | Status |\n|------|--------|\n| Transport | TCP/4370 (USB/COM designed-for via the `Transport` interface, not yet implemented) |\n| Read: device info, users (incl. extended format), attendance, op-logs | ✅ |\n| Read: fingerprint \u0026 face templates, user photos, raw options | ✅ |\n| Writes / control (set user, upload photo, unlock, clear, reboot) | ❌ out of scope |\n\n## How the protocol was derived\n\n`openzk` talks the ZKTeco standalone SDK protocol. The wire framing (packet structure,\nchecksum, auth handshake) and the command **opcodes** were determined by\n**reverse-engineering the official ZKTeco SDK for interoperability** — disassembling the\nexported functions to read their opcode constants, then validating each parser against a\nreal device. The opcode table lives in [`src/openzk/opcodes.py`](src/openzk/opcodes.py); it\ncontains only factual numbers. **No proprietary ZKTeco code or binary is included or\nredistributed** in this repository. See [`tools/extract_opcodes.py`](tools/extract_opcodes.py)\nto regenerate the table from an SDK binary you supply yourself.\n\nSee [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the layered design.\n\n## Disclaimer\n\nThis project is **not affiliated with, endorsed by, or sponsored by ZKTeco**. \"ZKTeco\" and\nrelated marks belong to their respective owners. `openzk` exists for **interoperability** with\nhardware you own/operate. Use at your own risk. See [`DISCLAIMER.md`](DISCLAIMER.md).\n\n## Contributing\n\nContributions welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md). In short:\n\n```sh\nuv sync --extra dev\nuv run pytest            # unit tests (no device needed)\nuv run ruff check .\n```\n\nLive device tests are gated and skipped by default:\n\n```sh\nOPENZK_LIVE=1 OPENZK_HOST=\u003cyour-device-ip\u003e uv run pytest\n```\n\n## License\n\n[MIT](LICENSE) © 2026 Keng Susumpow\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkengggg%2Fopenzk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkengggg%2Fopenzk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkengggg%2Fopenzk/lists"}