Χ‘Χ‘Χ΄Χ“

πŸ“· CAMERA SYSTEM β€” canonical reference (don't re-discover this)

docs/CAMERA_SYSTEM.md Β· last changed (pre-VM history) Β· rendered from GitHub master

πŸ“· CAMERA SYSTEM β€” canonical reference (don't re-discover this)

Last verified: 2026-06-25 (camera/infra session). LIVING doc. Evidence discipline: βœ… = verified this session; 🟑 = per Brain/prior, spot-check recommended; ⚠️ = unverified/flag.
One-line truth (UPDATED 2026-07-01): cameras = Hikvision NVR β†’ ops-api nvrFetch() DIRECT (digest auth, PC-FREE) β†’ /camera/snapshot β†’ portal. Rewired to the NVR-direct path (deployed a405e728; all 4 cams verified HTTP 200 + JPEG straight from the NVR β€” no PC). go2rtc-on-PC is now only a FALLBACK and can be stopped. ⚠️ NVR ports 8500/8501 are internet-exposed β€” Step 2 = cloudflared tunnel to the NVR from an always-on box, then close the eero forwards (raw Hikvision ports are actively exploited). Step-2 runbook β†’ docs/CAMERA_STEP2_TUNNEL_RUNBOOK.md (host = a ~$50 always-on LAN box, NOT the PC; exact steps; written 2026-07-01).

CAMERA MAP βœ… (verified by on-screen OSD labels + cameras.html + Brain)

cam=N go2rtc RTSP channel Location Verified
cam1 102 Backyard (OSD "REAR DOOR") βœ… read the frame
cam2 202 Daughter's Room 🟑 Brain β€” intentionally HIDDEN from all portal views (privacy)
cam3 302 Front Door 🟑 frame grabbed, label per Brain
cam4 402 EMPTY connection β€” no camera (dropped); always 502 βœ… consistently dead
cam5 502 Living / Dining 🟑 Brain
cam6 602 Front Driveway 🟑 frame grabbed
cam7 702 Kitchen (OSD "KITCHEN") βœ… read the frame
cam8 802 Playroom (OSD "PLAYROOM") βœ… read the frame
NOT a mislabel (Sam asked re cam7/cam8 2026-06-25): cam7=Kitchen, cam8=Playroom is CORRECT at the source AND in cameras.html. Source of truth for labels = outputs/cameras.html:90-92 ("Labels confirmed by Sam 2026-06-02"). cam=N maps to NVR channel N02 (sub-stream).

ARCHITECTURE (A) β€” FALLBACK ONLY (as of 2026-07-01): go2rtc RTSP bridge (PC-tied)

Chain: cameras.html <img> β†’ ops-api /camera/snapshot?cam=N (referer-gated) β†’ Worker fetches https://cam.hookstreetservices.com/api/frame.jpeg?src=camN with headers CF-Access-Client-Id: <CAM_CF_ID> + CF-Access-Client-Secret: <CAM_CF_SECRET> (names only, never values) β†’ cloudflared tunnel treitel-cameras β†’ go2rtc on Sam's PC (localhost:1984) β†’ NVR RTSP rtsp://admin:<NVR_PW>@192.168.4.47:54607/Streaming/Channels/N02 β†’ JPEG (ffmpeg-transcoded). Code: ops-api/src/index.ts ~L630-668.
Why this exists: the NVR's direct HTTP/ISAPI web service stopped responding (see Architecture B / the security hardening), so we go around it via RTSP.

go2rtc setup on the PC (everything, exact)

Cloudflare side

ARCHITECTURE (B) β€” ⭐ CURRENT / LIVE (rewired 2026-07-01): NVR-direct, PC-FREE

Was: Worker nvrFetch() β†’ http://d6468120.eero.online:8500/ISAPI/Streaming/channels/<ch>/picture (eero DDNS + eero port-forward β†’ NVR, MD5 digest auth, NVR_HOST/NVR_USER/NVR_PASS). Verified working June 2 (commit 88c1454, "cam1 returns 34KB JPEG"). PC-FREE β€” the NVR served snapshots itself; nothing ran on the PC.
⚠️ CORRECTED 2026-07-01 (verified live from Sam's eero app β€” supersedes the old "closed June 1" claim below): the eero port-forwards are STILL OPEN + ENABLED β€” the NVR 192.168.4.47 has 8500 AND 8501 forwarded to the internet (Reservations & port forwards β†’ "Hangzhou Hikvision Digital"). DDNS d6468120.eero.online β†’ 74.101.240.91 is live (Dynamic DNS ON). So the NVR is currently internet-reachable β€” nvrFetch() (Architecture B, PC-FREE) works RIGHT NOW; a live GET to :8500 returned 200. The NVR is the ONLY forwarded device (iPod/laptop/iPads are LAN-only reservations). This is a real security exposure (internet-facing Hikvision = actively exploited) β†’ the plan is: (1) rewire ops-api to nvrFetch() for PC-free cameras now, (2) stand up a cloudflared tunnel to the NVR from an always-on HOME box, (3) Sam disables the 8500/8501 eero forwards to close the hole. NEVER leave raw ports open long-term.

~~OLD (WRONG) note, kept for history:~~ "Why it broke: Sam's 2026-06-01 hardening moved the NVR port off 8500 + closed the eero 8500 forward β†’ 8500 empty / 443 refused." β€” the eero shows the forward was never actually removed; 8500 is open. (The FABRICATED "firmware update killed it" citation in ops-api/src/index.ts ~L642 is also false β€” flag for correction.)
Restore (a SECURITY decision, Sam + camera/infra own it): the nvrFetch() helper is STILL in ops-api/src/index.ts (only the call site was rewired). To go PC-free: revert /camera/snapshot to nvrFetch() + make the NVR HTTP reachable again. Secure form = a cloudflared tunnel β†’ the NVR's HTTPS on an always-on box (NOT reopening raw 8500 to the internet). Reopening 8500 = the exposure the audit flagged. Deploy alone does NOT light cameras β€” the secret/route half ships, but the architecture choice is the actual restore.

SECRET / VERSION ARCHITECTURE + SAFE-RESTORE RULES (πŸ”΄ critical)

DIAGNOSTIC DECISION TREE (502 / "no signal")

  1. ALL cams 502 + a secret-backed endpoint also fails β†’ secrets stranded (clobber/bad deploy). Fix: Brain rolls ops-api to the max-secret version.
  2. ALL cams 502 + other endpoints WORK β†’ wrong/regressed ops-api version (route missing). Fix: roll forward to the full version (ad740523).
  3. SOME cams work, one is 502 / "no signal" β†’ THAT camera's source feed (go2rtc/RTSP/physical), NOT ops-api. Check: curl localhost:1984/api/frame.jpeg?src=camN. If local works but portal 502s = tunnel/ops-api; if local also fails = the physical camera/NVR channel (power-cycle/reseat when home). cam4 is permanently dead (empty connection).
  4. Brief "no signal" that self-recovers β†’ transient RTSP drop; go2rtc auto-reconnects. Refresh. Only worry if a camera flaps persistently (then physical).

5-POINT ACCEPTANCE TEST (not "done" until all pass)

  1. PC awake. 2. go2rtc + cloudflared running (tasklist). 3. ops-api has CAM_CF (live /camera/snapshot test, NOT secret list). 4. Worker β†’ tunnel returns JPEGs (7/8; cam4 dead). 5. Feed loads on Sam's phone off Wi-Fi (cellular).

DURABILITY ROADMAP

CURRENT STATE (2026-06-25)

Cameras LIVE via go2rtc (7/8; cam4 dead). ops-api live ad740523 (CAM_CF present). go2rtc + cloudflared running + auto-start installed. cam1/Backyard occasionally shows a transient "no signal" that self-recovers (6/6 good on last test). Portal labels correct. Off-Wi-Fi confirmed by Sam.

Source trail Β· docs/CAMERA_SYSTEM.md @ master Β· rendered 2026-07-02 7:23 PM EDT by scripts/build-docs.py Β· the .md in the repo is the truth; this page is the phone-readable view