Skip to main content

aiocamera

Camera as a service — discover, capture, and serve camera frames over ZMQ.

A background daemon automatically detects connected cameras (Intel RealSense, Luxonis OAK, generic USB webcams), continuously captures frames, and serves the latest frame on demand via ZMQ IPC. Includes a CLI, a Python client library, and a browser-based MJPEG debug viewer.

Install

pip install aiocamera                # core only (opencv, pyzmq, numpy, click)
pip install "aiocamera[realsense]"   # + pyrealsense2 (pyrealsense2-macosx on macOS)
pip install "aiocamera[oak]"         # + depthai
pip install "aiocamera[all]"         # everything

aiocamera uses OpenCV's contrib build (opencv-contrib-python), as aprilcube does, so both install together. Do not add opencv-python to the same environment: both wheels provide cv2. For development, pip install -e ".[all]".

macOS

Intel publishes no pyrealsense2 wheels for macOS. There the realsense extra installs pyrealsense2-macosx instead, which builds the same pyrealsense2 module (Apple Silicon, macOS 15+).

librealsense needs root on macOS to open a RealSense. With one connected, aiocamera start asks for your password through sudo and runs the daemon as root, and only the daemon and the camera queries behind the setup prompts: your profiles stay yours, and aiocamera status, clients and web-debug work as you. aiocamera stop signals the root daemon through sudo, so it may ask for the password again. There is no need to run aiocamera itself with sudo.

CLI

aiocamera start                        # uses latest matching profile, or prompts
aiocamera start --fresh                # ignore saved profiles, prompt and optionally save
aiocamera start --profile my_setup     # use a specific saved profile
aiocamera status                       # show detected cameras and active streams
aiocamera stop                         # stop the daemon
aiocamera profiles                     # list all saved configuration profiles
aiocamera web-debug [PORT]             # MJPEG viewer at http://localhost:PORT (default 8080)

# Runtime reconfiguration (while service is running)
aiocamera config rs_234322071225 --resolution 1280x720 --fps 30
aiocamera config rs_234322071225 --exposure 500
aiocamera config rs_234322071225 --exposure auto
aiocamera config rs_234322071225   # list supported modes

Python API

Start / Stop

import aiocamera

# Start the daemon
aiocamera.start()                          # uses latest matching profile, or prompts
aiocamera.start(fresh=True)                # ignore profiles, prompt, offer to save
aiocamera.start(profile="my_setup")        # use a specific saved profile
aiocamera.start(camera_configs={           # explicit configs, no prompts or profiles
    "rs_234322071225": {"resolution": [1280, 720], "fps": 30, "exposure": 500},
})
# Returns PID, or None if already running

aiocamera.stop()                           # stop the daemon

A camera's config, in a profile or camera_configs, may also choose its streams and whether it opens at all. A config keyed by a camera type (realsense, oak, webcam) applies to every camera of that type without one of its own:

aiocamera.start(camera_configs={
    "rs_234322071225": {"resolution": [640, 480], "fps": 60, "streams": ["color"]},  # no depth
    "webcam": {"enabled": False},                                                   # no webcams
})

A RealSense opens color and depth by default, and aligns depth to color when both run. aiocamera start --fresh asks for both and saves them in the profile.

Client

from aiocamera import CameraClient

with CameraClient() as client:
    cameras = client.list_cameras()
    status  = client.status()

    # Get frame at capture resolution
    frame = client.get_frame("rs_234322071225_color")  # numpy.ndarray

    # Get frame at a specific resolution (resized server-side)
    frame = client.get_frame("rs_234322071225_color", resolution=(320, 240))

    # Set a default resolution for all subsequent get_frame() calls
    client.set_resolution(320, 240)
    frame = client.get_frame("rs_234322071225_color")  # 320x240
    client.set_resolution(0, 0)                        # clear → back to capture resolution

    # Runtime reconfiguration
    modes = client.get_supported_modes("rs_234322071225")  # valid (w,h,fps) combos
    client.set_config("rs_234322071225", resolution=(1280, 720), fps=30)  # blocking
    client.set_exposure("rs_234322071225", 500)     # immediate, no restart
    client.set_exposure("rs_234322071225", None)     # auto exposure

    # Intrinsics
    intrinsics = client.get_intrinsics("rs_234322071225")
    K = client.get_intrinsics_matrix("rs_234322071225")  # 3x3 numpy array

Camera IDs

Camera IDs are based on serial numbers for stability across plug/unplug cycles:

Type ID format Example
RealSense rs_{serial} rs_234322071225
OAK oak_{mxid} oak_18443010A1B2C3D4
Webcam webcam{n} webcam0

Stream names are {camera_id}_{stream} — e.g. rs_234322071225_color, rs_234322071225_depth, oak_18443010A1B2C3D4_CAM_A.

Supported Cameras

Type SDK Streams Install extra
Intel RealSense pyrealsense2 color, depth [realsense]
Luxonis OAK depthai per-socket (CAM_A, CAM_B, ...) [oak]
USB Webcam OpenCV color (included)

Architecture

aiocamera daemon
├── discovery: RealSense → OAK → webcam (avoids double-counting)
├── per-camera capture threads (as fast as possible)
├── frame store (dict: stream_id → latest numpy frame)
├── reconfigure coordination (per-driver threading events)
└── ZMQ REP socket (ipc:///tmp/aiocamera.sock)

aiocamera client (CameraClient)
└── ZMQ REQ socket → get_frame / set_config / set_exposure / list_cameras / status / stop

Files

  • ~/.config/aiocamera/camera_configs.json — saved configuration profiles (matched by camera serial set)
  • /tmp/aiocamera.pid — daemon PID file
  • /tmp/aiocamera.log — daemon log output
  • /tmp/aiocamera.sock — ZMQ IPC socket

aiocamera was called pycaas before its first release. Profiles saved by pycaas (~/.config/pycaas/camera_configs.json) are used until a profile is saved under aiocamera. A running pycaas daemon holds the cameras: stop it (pycaas stop) before aiocamera start.

Metadata

Release files for aiocamera 0.1.2

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

Source distribution (sdist)

Source distribution for aiocamera 0.1.2
File Size Uploaded
aiocamera-0.1.2.tar.gz 29.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aiocamera 0.1.2
File Interpreter ABI Platform
aiocamera-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 61.7 kB

Release files / aiocamera-0.1.2.tar.gz

Download URL aiocamera-0.1.2.tar.gz
Size 29.3 kB
Tags Source
SHA-256 checksum
How to use checksums
557856abf4f7bea034b766f905f92c89d593fecb1bfe7c9d8f51669bd6e786a2
BLAKE2b-256 checksum
How to use checksums
6c69435e34b53f44bf734af1b6de0c9eb2425cc2b453be96ce3b2dda6560efaf
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 Oct 6, 2026.

Transparency log

Release files / aiocamera-0.1.2-py3-none-any.whl

Download URL aiocamera-0.1.2-py3-none-any.whl
Size 32.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
163a7239ce579c6522bcada446fb30a7efb623521425fd2c34ab823e07c9fa9f
BLAKE2b-256 checksum
How to use checksums
e40f7e833d20daf84cf3bc31c66a6ae78f2e6cb3c1f92a152538bc1b8d7bd2c1
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 Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

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