You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The camera API has six adapters and a capability model, none of it written down. Anyone plugging in a new camera today has to reconstruct the design from registry.py, base.py and the route
handlers. Two questions have no answer in the repo: do I even need a new adapter (the rtsp, url and rest adapters cover a lot with config alone), and what exactly must my class
implement.
What it adds
One guide at pyro_camera_api/pyro_camera_api/camera/adapters/README.md: what an adapter is for,
a table of the six existing ones to check before writing code, the capture() contract, the
capabilities and how far to go, a commented skeleton, and the pitfalls. The root README.md
links to it and gains the missing rest adapter in its list.
It lives in the adapters directory so GitHub renders it when browsing the folder, which is where
you land when you go look at existing adapters. Same convention as tools/ and setup_presets/.
Worth a look later
Documented as-is, not changed here:
An implicit contract sits next to the explicit one. Six methods are resolved by hasattr()
in the routes and declared nowhere in base.py (set_auto_focus, focus_finder, start_zoom_focus, get_ptz_preset, set_ptz_preset, reboot_camera). An adapter can
implement both mixins fully, pass mypy, and still 400 on six endpoints. Worst case is silent:
without reboot_camera, main.py never starts the stuck detector and logs nothing.
Streaming is outside the adapter layer. Stream URLs are built in core/config.py from the
IP, assuming RTSP on 554 with a Reolink or Linovision path. A camera off that convention
captures fine and cannot stream.
adapter: "reolink" degrades silently. Speed tables are keyed by exact model, so the
generic value falls back to the 823S2 calibration with only a warning.
Checked every claim in the guide against the code. Docs only, CI green, nothing risky. A few things are inaccurate enough to mislead someone writing an adapter.
focus_finder() is not hasattr()-guarded. The optional-methods table lists it under the methods routes look up with hasattr() and degrade gracefully. routes_focus.py:122 only checks isinstance(cam, FocusMixin), then calls cam.focus_finder(...) at line 149 unguarded. A FocusMixin adapter without focus_finder raises AttributeError and returns 500, not a clean 400. Same correction applies to "still 400 on six endpoints" in the PR description.
The rest row omits response. The table lists url, headers, json_path, encoding, but response (rest.py:50, default "image") is the switch that enables the JSON path. Left out, json_path and encoding are ignored and the capture silently fails.
The url adapter dispatches on the literal string CGIProxy.fcgi (url.py:161), not on the presence of usr/pwd. "It exposes a snapshot URL returning an image directly, use url" is a trap: a credential free public snapshot URL falls into the digest branch and returns None with "requires inline credentials". Worth one sentence.
focus_position is applied once per patrol cycle, after the return to pose 0 (patrol.py:115-124), not on every pass over a preset.
Nits:
/control/reboot returns 501, not 400 (routes_control.py:973). Real paths are /control/reboot/{camera_ip} and /control/zoom/{camera_ip}/{level}.
"Required configuration" overstates: ip_address falls back to the registry key, poses/azimuths default to []. Only rtsp_url and url actually make build_camera_object return None.
Step 3 "export in __init__.py": the registry imports the modules directly and __init__.py currently exports 4 of 6 (no Linovision, no Mock). Convention rather than wiring.
Verified correct: the base.py contract and mixin semantics, isinstance to 400 on the mixin routes, import time registry build, the reolink speed table fallback with warning (routes_control.py:72), stream URLs built in core/config.py from the IP on 554, the stuck detector silently skipped without reboot_camera (main.py:84), both reboot_camera snippets, the Linovision set_auto_focus stub behaviour, and the patrol move_camera("ToPos", idx=pose, speed=50) loop.
Fix the focus_finder row and the response field, the rest is polish. The "is my camera already supported" table is the part that saves real work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Docs only, no code changes.
Why
The camera API has six adapters and a capability model, none of it written down. Anyone plugging in a new camera today has to reconstruct the design from
registry.py,base.pyand the routehandlers. Two questions have no answer in the repo: do I even need a new adapter (the
rtsp,urlandrestadapters cover a lot with config alone), and what exactly must my classimplement.
What it adds
One guide at
pyro_camera_api/pyro_camera_api/camera/adapters/README.md: what an adapter is for,a table of the six existing ones to check before writing code, the
capture()contract, thecapabilities and how far to go, a commented skeleton, and the pitfalls. The root
README.mdlinks to it and gains the missing
restadapter in its list.It lives in the adapters directory so GitHub renders it when browsing the folder, which is where
you land when you go look at existing adapters. Same convention as
tools/andsetup_presets/.Worth a look later
Documented as-is, not changed here:
hasattr()in the routes and declared nowhere in
base.py(set_auto_focus,focus_finder,start_zoom_focus,get_ptz_preset,set_ptz_preset,reboot_camera). An adapter canimplement both mixins fully, pass mypy, and still 400 on six endpoints. Worst case is silent:
without
reboot_camera,main.pynever starts the stuck detector and logs nothing.core/config.pyfrom theIP, assuming RTSP on 554 with a Reolink or Linovision path. A camera off that convention
captures fine and cannot stream.
adapter: "reolink"degrades silently. Speed tables are keyed by exact model, so thegeneric value falls back to the 823S2 calibration with only a warning.