ip cameras
Service Summary: The DrHeck Camera Hub (https://cam.drheck.dev) provides automatic LAN discovery, low-latency live video and MP3 audio streaming, two-way RTSP ONVIF backchannel voice talk, YOLOv8n + hardware AI event capture with a web-viewable timeline and text metadata log, optical zoom/spotlight/siren3D hardwareclick-to-zoom and optional auto-zoom on moving objects, smart floodlight/IR/LED controls, privacy sleep mode, bandwidth adaptation, and a sideloadable Google TV interface for the Reolink PoE IP cameras on 10.0.0.0/24. Access is restricted via Authentik ForwardAuth to members of the camera_access group (luke, ikura, and haruka).
Hardware Inventory & Detected Cameras
Two Reolink RLC-811A (P430) 4K 8MP PoE Spotlight IP cameras are connected to the 10.0.0.0/24 LAN on interface eth77 of host ul with static DHCP leases on danknasty:
| Property | Camera 1 (RLC-811A (122)) |
Camera 2 (RLC-811A (123)) |
|---|---|---|
| IPv4 Address (Static Lease) | 10.0.0.122 (host cam1) |
10.0.0.123 (host cam2) |
| MAC Address | ec:71:db:f1:25:5a |
ec:71:db:6d:84:ce |
| Vendor / OUI | Reolink (ec:71:db) |
Reolink (ec:71:db) |
| Model / Item No. | RLC-811A / P430 |
RLC-811A / P430 |
| Hardware Revision | IPC_560B158MP |
IPC_560B158MP |
| Firmware Version | v3.1.0.4695_2504301440 |
v3.1.0.4695_2504301440 |
| Serial Number | 141484731968753 |
141484731989233 |
| Ethernet Link | 100M_FULL (802.3af PoE) |
100M_FULL (802.3af PoE) |
| Optical Zoom Range | 5X Motorized (ZoomPos 0..28, FocusPos 0..238 |
5X Motorized (ZoomPos 0..28, FocusPos 0..238 |
| Illumination | IR Night Vision (auto/close) + 450 lm Warm Floodlight (1..100%) |
IR Night Vision (auto/close) + 450 lm Warm Floodlight (1..100%) |
| Audio | 16 kHz 8 kHz G.711 PCMU) + Siren |
16 kHz 8 kHz G.711 PCMU) + Siren |
time.google.com:123 (America/New_York EDT/EST)
time.google.com:123 (America/New_York EDT/EST)
Camera Services, Network Ports & Internal Operation
On firmware v3.1.0.4695_2504301440, Reolink cameras lock down legacy plaintext web/streaming ports out of the box and expose only the proprietary Baichuan management port (9000/tcp) until explicitly instructed to enable standard streaming protocols.
1. Port & Service Matrix (cmd_id = 37 GetNetPort / cmd_id = 36 SetNetPort)
| Service | Protocol / Port | Factory Default | Active State on ul |
Purpose & Operation |
|---|---|---|---|---|
Baichuan (server) |
9000/tcp |
Enabled | Enabled | Proprietary binary + XML control, telemetry, snapshot, PTZ/zoom, AI/motion alarm, and configuration bus. |
RTSP (rtsp) |
554/tcp, 554/udp |
Disabled | Enabled (Auto-enabled by cam) |
Real-Time Streaming Protocol serving hardware-encoded main (H.265 4K) and sub (H.264 360p) 16 kHz AAC track3 PCMU/8000) speaker talkback. |
ONVIF (onvif) |
8000/tcp |
Disabled | Disabled (Toggleable) | Open Network Video Interface Forum profile for third-party NVR integration. |
RTMP (rtmp) |
1935/tcp |
Disabled | Disabled (Toggleable) | Flash/RTMP H.264 sub-stream (rtmp://<ip>:1935/bcs/channel0_sub.bcs). |
HTTP (http) |
80/tcp |
Disabled | Disabled (Toggleable) | Embedded camera web UI and /cgi-bin/api.cgi JSON endpoint. |
HTTPS (https) |
443/tcp |
Disabled | Disabled (Toggleable) | Self-signed TLS embedded camera web UI and /cgi-bin/api.cgi JSON endpoint. |
2. How the Baichuan Protocol (9000/tcp) Works
All discovery, hardware control, and instantaneous snapshots are performed over TCP port 9000 using Reolink's Baichuan protocol:
- Binary Framing Header: Every Baichuan packet begins with a 20-byte or 24-byte little-endian binary header starting with magic bytes
0xf0debc0a, followed bycmd_id(uint32), payload length (uint32),channel_id(uint8), status code (200OK,400Bad Request), and payload offset. - Modern Nonce Authentication (
cmd_id = 1):- The client sends an initial unauthenticated
cmd_id = 1request. - The camera replies with an XML
<Encryption>challenge containing a random<nonce>. - The client computes uppercase MD5 digests of
username + nonceandpassword + nonce(truncated to 31 characters) and submits the authenticated login frame. - Once authenticated, payload bodies are encrypted using AES-128-CFB (or XOR stream cipher depending on message class) keyed from the session nonce.
- The client sends an initial unauthenticated
KeyComplete Baichuan Command IDs Used bycam.drheck.dev:cmd_id = 80(GetDevInfo): Model (RLC-811A), item number (P430), firmware version, serial number.cmd_id = 37/36(GetNetPort/SetNetPort): Inspects and enablesrtsp(554/tcp),onvif(8000/tcp),rtmp(1935/tcp),http(80/tcp), andhttps(443/tcp).cmd_id = 76/75(GetLocalLink/SetLocalLink): Reads or writes DHCP vs. static IPv4 settings and MAC address.cmd_id = 182(Snap): Captures an immediate hardware-encoded JPEG frame (main4K orsub640x360) directly over the control socket in~110 ms.cmd_id = 56/57(GetEnc/SetEnc): Reads and updates H.265/H.264 resolution, frame rate (frame),andtarget bitrate (bitRatein kbps), and audio track embedding (<audio>1</audio>) formainStreamandsubStream.cmd_id = 26/25(GetImage/SetImage): Reads and updates ISP sensor parameters (bright,contrast,saturation,hue,sharpen,DayNightDayNight/modeauto|color|black&white,nr3d).
cmd_id = 264/,265mirror(GetAudioCfg/,SetAudioCfg): Reads and updates speaker volume ().0..100flipcmd_id = 44/45(GetOsd/SetOsd): Reads and updates On-Screen Display overlays, including the Reolink logo watermark (<OsdChannelName><enWatermark>0|1</enWatermark></OsdChannelName>), camera nameoverlayoverlay, and timestamp overlay.
cmd_id = 288 (SetWhiteLed manual) & cmd_id = 289 / 290 (FloodlightTask): Controls manual spotlight toggle (0|1), brightness (1..100), automatic lighting mode (0 Off/Manual, 1 Smart Night AI Trigger, 3 Night Schedule), duration (60..600s), and AI trigger classes (people,vehicle,dog_cat).
cmd_id = 208 / 209 (LedState): Controls Infrared Night Vision LEDs (<OsdChannelNamestate>auto|close</state>) and the front power status LED (<lightState>open|close</lightState>).
cmd_id = 263 (AudioAlarmPlay) & cmd_id = 232 / 231 (GetAudioAlarm / SetAudioAlarm): Triggers manual 1x siren or configures automatic siren on AI/motion alarm (<AudioTask><enable>0|1</enable></OsdChannelNameAudioTask>, disabled 0 by default)cmd_id = 264 / 265 (GetAudioCfg / SetAudioCfg) & cmd_id = 439 / 440 (GetAudioNoise / SetAudioNoise): Controls speaker volume (0..100) and level 0..3).
cmd_id = 574 / 575 (get_privacy_mode / set_privacy_mode) & cmd_id = 52 / 53 (GetMask / SetMask): Toggles hardware Privacy / Sleep mode (<OsdDatetimesleepState><sleep>0|1</sleep></sleepState>) and hardware privacy masks (<Shelter><enable>0|1</enable></OsdDatetimeShelter>cmd_id = 288290SetWhiteLedGetWhiteLed<FloodlightManual><status>0|1</status></FloodlightManual>1..100).
cmd_id = 295 (StartZoomFocus), cmd_id = 445 (Set3DPos), & cmd_id = 224 / 225 (GetAutoFocus / SetAutoFocus): ZoomPos 0..28FocusPos 0..238), executes 3D area click-to-zoom (posX, posY, posWidth, posHeight in 0..1000 normalized coordinates), and locks/unlocks autofocus (disable 0|1).
cmd_id = 276342 / 343 (AudioAlarmPlayGetAiAlarm / SetAiAlarm) & cmd_id = 46 / 47 (GetMdAlarm / SetMdAlarm): 0..100) and stay-time (0..8s) for people, vehicle, dog_cat, face, plus general motion sensitivity (1..50).
cmd_id = 38 / 39 (GetNtp / SetNtp), cmd_id = 104 / 105 (SystemGeneral), cmd_id = 106 / 107 (Dst), & cmd_id = 23 (reboot): Configures NTP synchronization (time.google.com:123), US Daylight Saving Time, EDT/EST clock sync, and device reboot.
3. RTSP Stream Endpoints & ONVIF Two-Way Audio Backchannel (554/tcp)
Once rtspEnable = 1 is set via Baichuan cmd_id = 36, each camera serves two RTSP streams:streams plus an ONVIF two-way audio backchannel track:
- Sub Stream (Low-Latency H.
264)264 + AAC Audio + PCMU Backchannel):rtsp://admin:<password>@10.0.0.122:554/h264Preview_01_sub rtsp://admin:<password>@10.0.0.123:554/h264Preview_01_subEncodedas track1: H.264 High Profile (yuv420p,640x360, default10 fpsat256 kbps, GOP =4,recvonly).
track2: MPEG4-GENERIC AAC-hbr (16 kHz mono recvonly).
track3 (when negotiated with Require: www.onvif.org/ver20/backchannel): G.711 PCMU (PCMU/8000, payload type 0, sendonly) for transmitting two-way voice audio directly to the camera's built-in speaker.
Main Stream (4K UHD H.265/HEVC):
rtsp://admin:<password>@10.0.0.122:554/h265Preview_01_main
rtsp://admin:<password>@10.0.0.123:554/h265Preview_01_main
Encoded as HEVC / H.265 (yuvj420p, 3840x2160, default 25 fps at 6144 kbps, GOP = 2) with 16 kHz mono AAC audio.
Architecture of cam.drheck.dev
The web service on host ul (/data/docker/cam) bridges the isolated IPv4 camera LAN (10.0.0.0/24) to an authenticated, browser-compatible HTTPS service at https://cam.drheck.dev.
| Component | Configuration on Host ul |
|---|---|
| Service Directory | /data/docker/cam (app.py, static/index.html, static/tv.html, tests/app_test.py) |
| Persistent State & Models | /data/docker/cam/data/cameras.json, /data/docker/cam/data/yolov8n.onnx (13 MB), /data/docker/cam/data/events/ (events.json + <event_id>.jpg) |
| Container Name | cam (, Python 3.12 + FastAPI + reolink-aio + onnxruntime + Pillow + numpy + espeak-ng + FFmpeg 7.1) |
| ULA IPv6 Binding | [fd77:7777:5010:0:1337:f1ac:d00d:ca30]:8000 on eth77 |
| Nginx Reverse Proxy | /etc/nginx/sites-available/cam (X-Accel-Buffering: no, proxy_buffering off, X-Authentik-Groups |
| Authentik SSO & Group | ProxyProvider (cam-provider, ForwardAuth) -> Application (cam) bound to Group (camera_access) |
| Backup & Restore | /home/luke/git/backups/ul/scripts/backup/cam & /home/luke/git/backups/ul/scripts/restore/cam (.tar.xz + par2 -r10) |
HowKey Subsystems Implemented in cam.drheck.devapp.py Communicates With the Cameras
- Zero-Config Discovery (
discover_cameras):- Reads the host kernel ARP table (
/proc/net/arpmounted read-only at/host_proc_arp).
- Reads the host kernel ARP table (
Filters formatches ReolinkIEEE MAC OUI prefixesOUIs (ec:71:dband,9c:8e:cd)and probes TCP ports9000and554across10.0.0.0/24(excluding infrastructure router/switch IPs).
9000/tcp, queries cmd_id = 80cmd_id = 37cmd_id 80, 37, 76, 5626, 264, 44, cmd_id289, 208, 232, 439, 574, 52, 224, 38, 46, 342), and cmd_id = 264rtspRTSP (554/tcp) inspect_reolink_cameraSetNetPort(rtspEnable=1)encoding (cmd_id = 36<audio>1</audio>)mjpeg_stream_generatorevent_monitor_loop, record_camera_event):
StandardAwebbackgroundbrowsersmonitorcannotcoroutinenatively(event_monitor_loop)decodesamplesrawsub-streamRTSPsnapshots from online, non-sleeping cameras every3.5 seconds, computing downscaled160x90grayscale pixel frame-differences (compute_frame_motion).
>= 2.2% of frame pixels) or <img>GOPPOST = 41–2 secondRLC-811Ayuv420p(progressive)mjpegformat=yuvj420p-strict unofficial/api/cameras/{ip}/mjpegcapture_event) occurs, classify_snapshot_yolo <150yolov8n.onnx via onnxruntime, ~62 ms 640x640 input with IoU 0.45 Non-Maximum Suppression).
Clean Unannotated Snapshots + Text Metadata: /data/docker/cam/data/events/<event_id>.jpg, while the detected class labels, confidence percentages (confidence_pct), normalized target coordinates (box_norm), trigger types (people, vehicle, dog_cat, motion, manual), frame motion percentage, and EDT/EST timestamp (format_edt_timestamp) are recorded in /data/docker/cam/data/events/events.json and displayed in the Detection Event Timeline & Metadata Log on https://cam.drheck.dev/.
Optional Auto-Zoom on Moving Objects (apply_auto_zoom_on_box):
auto_zoom_motion, off by default).
When enabled, detecting a moving person/object or motion region ([x, y, w, h] in 0..1000 normalized coordinates) automatically issues Baichuan cmd_id = 182445 (Set3DPos set_ptz_3d_zoom) to zoom the 5X motorized lens onto the moving target, marks the timeline event with an Auto-Zoomed badge, and --frameffmpegffmpeg -nostdin -loglevel error -rtsp_transport tcp -analyzeduration 1500000 \
-flags low_delay -i rtsp://admin:@10.0.0.123:554/h264Preview_01_sub -an \
-vf "fps=10,scale=640:-2,format=yuvj420p" -strict unofficial \
-f mpjpeg -boundary_tag frame -q:v 5 -
baseline_zoom 20 snapshotsseconds POST Spotlight Control/api/cameras/{ip}/talk):
Reolink'sSupportsBaichuanboth Push-to-Talk (Browser Microphone) (recordingSetWhiteLed(cmd_id = 288) XML parser requires<status>1</status>or<status>0</status>and rejects Python boolean strings (<status>True</status>) with status code400.app.pynormalizesviastateaudio/webmin the browser) and Speak Text (TTS) (synthesizing speech vianormalize_floodlight_state(req.state)MediaRecorderespeak-ng --stdout).
transcode_to_mulaw converts the audio stream via ffmpeg -i pipe:0 -ar 8000 -ac 1 -f mulaw pipe:1 into 8 kHz G.711 mu-law (PCMU/8000), and stream_rtsp_backchannel_mulaw negotiates an RTSP Digest session on 554/tcp with Require: www.onvif.org/ver20/backchannel, sets up track3 (Transport: RTP/AVP/TCP;unicast;interleaved=0-1), and transmits 160-byte (20 ms) RTP packets directly to 1camera's 0Static IPs vs. DHCP Reservations on danknasty & IPv6 Support
1. Should the Cameras Be Configured for Static IPs?DHCP Reservations (/etc/dhcpd.conf & ~/git/router_config/dhcpd.conf)
YesBoth —cameras pinninghave the cameras' IPv4 addresses viapermanent static DHCP reservationsleases on danknasty is recommended.
Currently, both cameras use DHCP (<Dhcp><enable>1</enable></Dhcp>) and received 10.0.0.122 and 10.0.0.123 from the dynamic pool (range 10.0.0.114 10.0.0.250;) on danknasty. There are two ways to assign permanent IPs:
/etc/dhcpd.conf danknastyec:71:db:f1:25:5aec:71:db:6d:84:ce~/git/router_config/dhcpd.conf) on danknastypikvmnodegridkikuofireboardctl:
host cam1 {
# RLC-811A (141484731968753)
hardware ethernet ec:71:db:f1:25:5a;
fixed-address 10.0.0.122;
}
host cam2 {
# RLC-811A (141484731989233)
hardware ethernet ec:71:db:6d:84:ce;
fixed-address 10.0.0.123;
}
cmd_id = 75SetLocalLink<LocalLink>cmd_id = 76cmd_id = 75<LocalLink version="1.1">
<Dynamic>
<Dhcp><enable>0</enable></Dhcp>
<Ip>
<ip>10.0.0.122</ip>
<mask>255.255.255.0</mask>
<gateway>10.0.0.1</gateway>
</Ip>
<Dns>
<auto>0</auto>
<dns1>10.0.0.1</dns1>
<dns2>0.0.0.0</dns2>
</Dns>
</Dynamic>
</LocalLink>
cam.drheck.devec:71:db:*/proc/net/arp2. Do the CamerasIPv6 Support IPv6?
- Camera Hardware (
RLC-811AFirmwarev3.1.0.4695_2504301440): No native IPv6support.stack Inspectiontheofcameraip -6 neigh show dev eth77confirms that neitherec:71:db:f1:25:5anorec:71:db:6d:84:ceconfigures an IPv6 link-localSoC (fe80::/1010.0.0.0/24), SLAAC, or DHCPv6 address, and the BaichuanLocalLink(cmd_id = 76) schema only supports 32-bitIPv4fields.
cam.drheck.dev): Fullcamulfd77:7777:5010:0:1337:f1ac:d00d:ca3080002603:3001:626:9de0:[fd77:7777:5010:0:1337:f1ac:d00d:aaaaul10.0.0.0/24ca30]:8000.AvailableComplete Camera SettingsControls & HowSettings to Adjust ThemMatrix
All camera settings canare be adjustedavailable interactively in the DrHeck Camera Hub web UI (https://cam.drheck.dev/ — expand Camera Hardware Encoder, Bandwidth, Image & Protocol Settings on any camera card) or programmatically via POST /api/cameras/{ip}/control.:
| Category | Setting | Supported Range / Values | ul |
Baichuan cmd_id |
Web UI / API Action |
|---|---|---|---|---|---|
| Events & AI |
true / false
true (Enabled)
Local + 182
Auto Event Capture (action: "auto_zoom_config")
Events & AI
Manual Event Capture & Classify
Captures JPEG + YOLOv8n text metadata
On-demand
182 + ONNX
Capture Event (POST /api/cameras/{ip}/capture_event)
Events & AI
Person / Vehicle / Pet AI Sensitivity
0 .. 100 (stayTime 0..8s)
60
342 / 343 (SetAiAlarm)
Person / Vehicle / Pet AI Sensitivity (action: "ai_sensitivity")
Events & AI
Motion Detection Sensitivity
1 .. 50
10
46 / 47 (SetMdAlarm)
Motion Sensitivity (action: "ai_sensitivity")
Optics & PTZ
Optical Zoom (ZoomPos)
0 .. 28 (1X .. 5X optical)
0
295 (StartZoomFocus)
Zoom slider (action: "zoom")
Optics & PTZ
Optical Focus (FocusPos)
0 .. 238295 (StartZoomFocus)
Focus slider (action: "focus")
Set3DPos)
0posX, posY, posWidth, posHeight (0..1000)
Interactive
445 (set_ptz_3d_zoom)
3D Click-Zoom button (action: "zoom_3d")
Optics & PTZ
Auto-Zoom on Moving Objects
false (Off) or 1true (On) + baseline_zoom
0false (Off)
288445 SetWhiteLed295Spotlight:Auto-Zoom ON/OFFon Moving Objects (action: "spotlight"auto_zoom_config")
Optics & PTZ
Autofocus Lock
false (Auto) or true (Locked)
false (Auto)
224 / 225 (SetAutoFocus)
Autofocus Lock (action: "autofocus")
Lighting
1, brightness: 1..%85Off, 85%
288 (SetWhiteLed)
Lighting
Floodlight Auto Behavior (FloodlightTask)
Mode 0 (Manual), 1 (Smart Night AI), 3 (Schedule); Duration 60..600s; Triggers people,vehicle,dog_cat
Mode 1, 180s
Light %289 290 (FloodlightTask)
Spotlight Automatic Mode / Triggers / Duration (action: "spotlight"floodlight_config")
auto (Auto Night IR) or close (Off)
auto
208 / 209 (LedState)
IR Night Vision LEDs (action: "leds")
Lighting
Front Status Power LED
open (On) or close (Off / Stealth)
open
208 / 209 (LedState)
Front Status Power LED (action: "leds")
Lighting
Day / Night Sensor Mode
auto, color (24/7 Color), black&white
auto
26 / 25 (SetImage)
Day / Night Sensor Mode (action: "image")
Deterrents & Audio
Auto-Siren on Detection
false (Off) or true (On)
false (Off)
232 / 231 (SetAudioAlarm)
Auto-Siren on Detection (action: "audio_alarm")
Deterrents & Audio
Manual Security Siren
Trigger 1x276263 (AudioAlarmPlay)
Siren (1x) action: "siren")
Deterrents & Audio16 kHz AAC -> 64 kbps MP3
Enabled<audio>1</audio>57SetEncAudio: Muted / LIVEGET /api/cameras/{ip}/audio.mp3)
Deterrents & Audio
Two-Way Audio Talk (Mic & TTS)
Browser MediaRecorder or espeak-ng -> 8 kHz G.711 PCMU
On-demand
RTSP track3 (554)
Push-to-Talk (Mic) & Speak Text (POST /api/cameras/{ip}/talk)
Deterrents & Audio
Mic 3D Noise Reduction
Level 0 (Off), 1 (Low), 2 (Med), 3 (High)
3 (High)
439 / 440 (SetAudioNoise)
Mic 3D Noise Reduction (action: "audio_noise")
Deterrents & Audio
Speaker Volume
0 .. 100 (%)
92
265 (SetAudioCfg)
Speaker Volume action: "volume")
0false (1true (0false (574 / cam575 (set_privacy_mode)
45Privacy Sleep SetOsdReolink Logo Watermarkbutton (action: "osd", watermark: falseprivacy_mode")
Shelter)
0false (Off) or 1true (On)
1false (4552 / 53 (SetOsdSetMask)
OSDHardware CameraPrivacy Name / TimestampMask (action: "osd"640x36064, 128, 160, 192, 256, 384, 51225657SetEncSub-Stream Bitrateaction: "encoding"4, 7, 10, 151057SetEncSub-Stream Frame Rateaction: "encoding"3840x21601024, 1536, 2048, 3072, 4096, 5120, 6144, 7168, 8192614457SetEncMain-Stream Bitrateaction: "encoding"2, 4, 6, 8, 10, 12, 15, 16, 18, 20, 22, 252557SetEncMain-Stream Frame Rateaction: "encoding"privacy_mask")
Image mirror, flip)
Normal, 180° Upside-Down, Flip, Mirror
0 / 025SetImageSetIspFlip 180°Mounting / Orientationaction: "image", flip: true, mirror: truebright0 .. 255128Normal
25 (SetImage)
BrightnessFlip 180° action: "image")
Image false (Hidden) or true (Visible)
false (Hidden)
45 (contrastSetOsd)
0Reolink ..Logo 255Watermark12825SetImageContrastaction: "image"osd")
time.google.com:123 (saturationEDT/EST)
0 .. 255time.google.com
12838 / 39 (SetNtp) & 105
25Set time.google.com SetImageSaturationEDT Clock (action: "image"ntp", action: "sync_time")
23 (sharpenreboot)
0Reboot .. 255Camera12825SetImageSharpnessaction: "image"rtsp554onvif8000rtmp1935http80https443900055436SetNetPortaction: "port"reboot")
REST API Examples for Adjusting Camera Settings
# Toggle Spotlight ON at 75% brightness on 10.0.0.122
curl -X POST http://[fd77:7777:5010:0:1337:f1ac:d00d:ca30]:8000/api/cameras/10.0.0.122/control \
-H "Content-Type: application/json" \
-d '{"action": "spotlight", "state": true, "brightness": 75}'
# Set Optical Zoom to 14 (2.5X)
curl -X POST http://[fd77:7777:5010:0:1337:f1ac:d00d:ca30]:8000/api/cameras/10.0.0.122/control \
-H "Content-Type: application/json" \
-d '{"action": "zoom", "value": 14}'
# Reduce on-camera H.264 sub-stream encoder to 128 kbps @ 7 fps
curl -X POST http://[fd77:7777:5010:0:1337:f1ac:d00d:ca30]:8000/api/cameras/10.0.0.122/control \
-H "Content-Type: application/json" \
-d '{"action": "encoding", "sub_bitrate": 128, "sub_fps": 7}'
# Adjust ISP Image Brightness and Sharpness
curl -X POST http://[fd77:7777:5010:0:1337:f1ac:d00d:ca30]:8000/api/cameras/10.0.0.122/control \
-H "Content-Type: application/json" \
-d '{"action": "image", "bright": 135, "sharpen": 140}'
Authentik Access Control (camera_access Group)
Access to https://cam.drheck.dev is restricted exclusively to members of the camera_access group in Authentik:
lukeikuraharukaCamerasslug = "cam"PolicyBindingcamera_accesshttps://cam.drheck.devauth_request /outpost.goauthentik.io/auth/nginxhttps://auth.drheck.devcamera_accessX-authentik-usernameX-authentik-groupscamcheck_camera_access_headers()/data/docker/cam/app.pyX-authentik-groups|camera_access//tv/cam-googletv.apk/api/*HTTP 403 ForbiddenManaging camera_access Group Membership via CLI
ssh ul 'docker exec -i authentik-server ak shell << "PY"
from authentik.core.models import Group, User
grp = Group.objects.get(name="camera_access")
print("Current members:", [u.username for u in grp.users.all()])
# To add or set members:
grp.users.set(User.objects.filter(username__in=["luke", "ikura", "haruka"]))
grp.save()
PY'
Bandwidth Adjustments for Unreliable or Slow Internet
When viewing two cameras simultaneously over a slow, high-latency, or lossy internet connection (cellular tethering, hotel Wi-Fi, or rural WAN),connection, total downstream bandwidth for $N$ cameras is governed by:
$$B_{\text{total}} = N \times f_{\text{fps}} \times S_{\text{frame}}(W, H, q) \times 8 \quad \text{bits/sec}$$
where $f_{\text{fps}}$ is the frame rate, $W \times H$ is the scaled resolution, and $q \in [2, 24]$ is the FFmpeg MJPEG quantization factor (-q:v).
cam.drheck.dev provides two independent bandwidth controls:
1. Per-Viewer Stream Presets (Top Toolbar on cam.drheck.dev & /tv)
Changing the Bandwidth / Mode dropdown in the top bar adjusts server-side scaling, frame rate decimation, and JPEG compression for your browser session without affecting other viewers:
| Preset Mode | Resolution | Frame Rate | JPEG q |
Avg Frame Size | Per-Camera Bitrate | 2-Camera Total WAN Bitrate | Best For |
|---|---|---|---|---|---|---|---|
| HD Main Stream | 1280x720 |
10 fps |
5 |
~25 KB |
~2.0 Mbps |
~4.0 Mbps |
Fast fiber / LAN full-screen inspection |
| Standard Live (Default) | 640x360 |
10 fps |
5 |
~6.2 KB |
~500 kbps |
~1.0 Mbps |
Normal broadband / Wi-Fi |
| Low Bandwidth | 480x270 |
5 fps |
10 |
~4.0 KB |
~160 kbps |
~320 kbps |
Congested Wi-Fi / mobile hotspot |
| Ultra-Low WAN | 320x180 |
2 fps |
15 |
~3.1 KB |
~50 kbps |
~100 kbps |
Throttled cellular / international roaming |
| Unreliable WAN Snapshot (2s) | 640x360 |
0.5 fps (1 / 2s) |
Native | ~9.0 KB |
~36 kbps |
~72 kbps |
High packet loss / TCP reset prone links |
| Minimal WAN Snapshot (5s) | 640x360 |
0.2 fps (1 / 5s) |
Native | ~9.0 KB |
~14 kbps |
~28 kbps |
Extreme low-speed satellite / 2G fallback |
Tip
for
Authentik HighAccess Packet Loss Links:
camera_access 2. On-Camera Hardware H.264 Sub-Stream Bitrate Tuning
Inside each camera card's Camera Hardware Encoder, Bandwidth, ImageGroup) & Protocol Settings drawer, you can also lower the camera's internal H.264 hardware encoder (SetEnc cmd_id = 57) from 256 kbps @ 10 fps down to 64 kbps @ 4 fps (64, 128, 160, 192, 256, 384, 512 kbps).
Google TV /App
camera_access): luke, ikura, haruka. Enforced at both the Nginx ForwardAuth edge (PolicyBinding on cam) and inside check_camera_access_headers() in app.py.
Google TV Sideloadable App (cam-googletv.apkA signed, sideloadable Android TV / Google TV application (DrHeck Cameras, package dev.drheck.cam) is built and hosted directly on cam.drheck.dev at:
- Built APK
Locationonul(Not Served over HTTPS):/data/docker/cam/googletv_src/cam-googletv.apk - 10-Foot TV
Web Interface:Interface:https://cam.drheck.dev/tv
ul/data/docker/cam/googletv_src/ (AndroidManifest.xmlMainActivity.smalires/drawable/tv_banner.pngres/drawable/ic_launcher.pngFeatures of the Google TV App
LEANBACK_LAUNCHERandroid.intent.category.LEANBACK_LAUNCHER320x180android:bannerFLAG_KEEP_SCREEN_ONWindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON0x80v2.0TV_AUTH_TOKEN)CookieManagercam_tv_tokenUser-AgentCamTVToken/...X-Cam-Tv-Tokenhmac.compare_digest10.0.0.12210.0.0.1232-Up GridModeStandard 10fpsLow-BW 5fpsUltra-Low 2fpsHD 720p 10fpsSpotlight ToggleDPAD_CENTEREnter2-Up GridFull-Screen5X+2-22-Up Grid.
How to Sideload onto Google TV
Option A: Via ADB over Wi-Fi / Ethernet (Fastest from a Laptop/Desktop)
<googletv-ip>scp ul:/data/docker/cam/googletv_src/cam-googletv.apk /tmp/cam-googletv.apk
adb connect <googletv-ip>:5555
adb install -r /tmp/cam-googletv.apk