AbstractCamera
Camera control abstractions for Python and the Abstract* ecosystem: one
thread-safe orchestrator (CameraManager) drives any camera family behind a
session protocol — tethered PTP bodies over libgphoto2, the machine's own
cameras (macOS AVFoundation), and a scriptable simulator for camera-less
development and tests. A CameraHub pilots several cameras at once (one
worker per camera, hardware-validated with four simultaneously), with
per-device capture folders under ~/Pictures/<device>/.
What you get
- A high-level orchestrator:
CameraManager— live view (latest-JPEG + measured fps), honest config dials backed by a write-verification ledger (every write is confirmed or explicitly declared reverted), single/burst/movie capture, focus actions, an absolute-deadline intervalometer with JSONL manifests, live-view detection (lightning/meteor/motion) with auto-fire, a rolling pre-capture buffer, and automatic capture downloads. - Family adapters (hardware-validated):
adapters/- Nikon Z (validated on a Z6 II): exposure-blocking triggers, lazy config settling, live-view-gated writes, movie prohibit pre-checks, wedge recovery.
- Sony Alpha (validated on an A7R IV): async write settling with
verify-retry,
[-2]busy backoff,prioritymodegating, press-and-hold bursts, silent-AF-refusal detection, fetch-on-announce downloads (sdram slot eviction), honest unconfirmable-movie receipts. - Webcam (validated on a MacBook Pro camera): honest capability surface — one real dial (resolution), stills that are video frames and say so, genuinely confirmable in-process MP4 recording, detection and intervalometer riding the frame stream.
- DWARF smart telescope (network/Wi-Fi, DwarfLab API v2): RTSP live view, device-table exposure/gain dials, album-backed captures that download over Wi-Fi, and the MOUNT as family actions — GOTO (RA/Dec or solar-system), joystick slews, calibration, astro autofocus.
- Generic PTP fallback for unknown tethered bodies.
- Multi-camera piloting:
hub.py— aCameraHubruns one manager/worker per connected camera (concurrent live views, sequences and recordings), tracks an ACTIVE selection for single-panel hosts, and derives stable device identities (model slug + serial disambiguation) that name the per-device capture folders<root>/<device>/[<sequence>/]with an on-device/local save policy. - Transport drivers + discovery:
drivers/,discovery.py— non-invasivelist_cameras()across transports (no device opened, no LED, no permission prompt at list time). Webcam identity is the AVFoundation uniqueID and capture opens THAT device natively (ADR 0009: names cannot point at the wrong camera); Continuity iPhones labeled, never auto-picked. - A simulator that is a drop-in gphoto2 module:
sim/gphoto2.pywith Nikon Z6 II and Sony A7R IV personalities reproducing hardware-measured quirks (ABSTRACTCAMERA_FAKE=1). - Device media downloads, one abstraction across devices (ADR 0011):
abstractcamera downloadcopies ALL media a device holds into~/Pictures/<device>/— USB-mounted cards (auto-detected by album signature) or the DWARF album over Wi-Fi (--host);--deletefrees the device after size-verified copies (protected device state like the DWARF's dark library always stays). Per-deviceMediaStoreadapters ride one sync engine that owns all safety rules; PTP-card stores (Sony/Nikon) are the named next adapters. - A CLI for manual checks:
abstractcamera list/abstractcamera preview/abstractcamera download(self-contained local operations). Detection runs in-process and its events are readable through the capability's event API (camera_get_events//v1/camera/events); waking a durable workflow on motion is a consumer built at a framework entry (gateway run / flow), not a camera-shipped daemon. - AbstractCore integration (ADR 0012): installing abstractcamera beside
AbstractCore auto-registers the
cameracapability (entry pointabstractcore.capabilities_plugins) — open/close cameras, capture photos and bounded video clips, arm motion/lightning/meteor detection with auto-capture — plus an explicit AI tool set:from abstractcamera.integrations.abstractcore_tools import camera_toolsthenllm.generate("Take a photo if something moves", tools=camera_tools()). Elevencamera_*tools (includingcamera_preview_photo— look without firing the shutter) ship with a classification map (captures_environmentis the privacy fact approval layers key on).
Install
pip install abstractcamera # webcam + simulator (numpy + OpenCV)
pip install "abstractcamera[gphoto2]" # + tethered PTP bodies (libgphoto2)
pip install "abstractcamera[clips]" # + MP4 clip/movie encoding (PyAV)
pip install "abstractcamera[raw]" # + RAW capture thumbnails (rawpy)
pip install "abstractcamera[dwarf]" # + DWARF smart telescopes (Wi-Fi)
pip install "abstractcamera[all]" # everything above
Quickstart
from abstractcamera import CameraManager, list_cameras
for camera in list_cameras():
print(camera["id"], camera["name"])
manager = CameraManager()
status = manager.connect() # default: first PTP body, else webcam
manager.set_config_value("iso", "800") # confirmed/reverted via the ledger
manager.request_trigger() # capture -> auto-download + catch log
jpeg, seq = manager.get_latest_frame() # live view
manager.start_interval_sequence(interval_s=5.0, count=10)
manager.disconnect()
Camera-less development: set ABSTRACTCAMERA_FAKE=1 and every transport is
replaced by the simulator (scriptable via abstractcamera.sim.gphoto2.configure).
How it fits together
flowchart LR
Host[Host app / CLI] --> CM[CameraManager]
CM --> W[worker thread: one owner of all camera I/O]
W --> AD[family adapter: Nikon Z / Sony Alpha / webcam / generic]
AD --> S[CameraSession: gphoto2.Camera / WebcamSession / simulator]
D[discovery + drivers] --> CM
The manager owns everything family-independent (scheduling windows, the
write ledger, downloads, detection, the watchdog); the adapter owns every
family quirk; the session speaks the pinned wire protocol
(wire.py, values pinned to libgphoto2).
Architecture decisions live in docs/adr/.
Honesty principles (ADR 0004)
Capabilities never pretend: a webcam exposes no ISO dial instead of a fake
one; Sony movie recording is labeled unconfirmable over USB; every config
write is confirmed against the body or explicitly reported reverted; webcam
names are reported from the same device object the session captures from
(ADR 0009 — positional guessing is gone).
Documentation
- docs/getting-started.md
- docs/architecture.md
- docs/api.md
- docs/faq.md · docs/troubleshooting.md
- docs/adr/ — architecture decision records
- AI-readable: llms.txt, llms-full.txt
AbstractFramework ecosystem
AbstractCamera is part of the AbstractFramework ecosystem (https://github.com/lpalbou/AbstractFramework), alongside AbstractCore, AbstractVision, AbstractVoice, and friends. It was extracted from the BlackPixel desktop editor's hardware-validated tethering stack (2026-07-12) through a 3-agent adversarial design review.
License
MIT — see LICENSE.
Metadata
Release files for abstractcamera 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| abstractcamera-0.2.1.tar.gz | 361.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| abstractcamera-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 555.0 kB
Release files / abstractcamera-0.2.1.tar.gz
| Download URL | abstractcamera-0.2.1.tar.gz |
|---|---|
| Size | 361.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e14d1a0a5d679622560c2bc05de677a28ddf5939868c5079f79b03ac45b9b3cc
|
|
BLAKE2b-256 checksum How to use checksums |
8b07c8f5e6b223ec613672781488bd526015c437ea5ed6c1cb4d5362ab1881b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / abstractcamera-0.2.1-py3-none-any.whl
| Download URL | abstractcamera-0.2.1-py3-none-any.whl |
|---|---|
| Size | 194.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e1f1c973b09d835456d7debab430b42f21daa206f29dbfeec50c7b18b8766f8d
|
|
BLAKE2b-256 checksum How to use checksums |
7a785d43205a78cd0f93090340dd35fa631b9c97608d736a1baf6ef239ca17bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log