Cameras on the TV camwall (telep-mainframe) looked “stuck for a long time” — a quadrant sat frozen on a static image with a stopped OSD clock while Frigate ingest stayed healthy (camera_fps ~5). Three root causes found and fixed: (1) the camwall stall-watchdog only watched one of the four mpv panes, so a stalled cam1/cam3/cam4 pane was never detected or re-rolled; (2) the pytapo camera-reboot tooling had silently died on Tapo KLAP auth breakage; (3) a reboot wipes the RTC-less Tapo clocks, leaving ~40 min of wrong OSD time until the hourly ONVIF push self-heals. All three applied and verified end-to-end. Closes the open “watchdog covers only the IPC-socket-owning pane” follow-up flagged in 2026-07-28-camwall-4-substream-composite.
For Agents — Quick Reference
Camwall:
/usr/local/bin/camwall-mpv.sh(camwall.service) — 4 tiled single-input mpv panes, each a go2rtc substream atrtsp://127.0.0.1:8554/:cam1_sub(DÉL-Fix, TL),cam2_sub(DÉL-PTZ, BL),cam3_sub(ÉSZAK-Fix, TR),cam4_sub(ÉSZAK-PTZ, BR). Per-pane IPC sockets (NEW):/run/camwall-cam1.sock…/run/camwall-cam4.sock(was: only/run/camwall.sockon the cam2 pane). Stall watchdog:/usr/local/bin/camwall-watchdog.py(camwall-watchdog.service) — now pollstime-poson ALL FOUR sockets, per-socket stall counters, re-rolls the whole wall (systemctl restart camwall) if ANY pane hitsSTALL_LIMIT. HDMI-reconnect logic preserved. Frigate re-roll watch:camwall-frigate-watch.service— re-rolls camwall when Frigate restarts (unchanged). Camera reboot (WORKING):~/tapo-ctl/reboot-cams-onvif.py— ONVIFSystemReboot()on port 2020 using Frigate RTSP creds, waits for ping-back, then re-syncs OSD clock viaset-cam-time.py. Default reboots both cams (192.168.30.119,192.168.30.139). Clock re-sync:~/tapo-ctl/set-cam-time.py(creds from Frigate container config + docker env) + hourlycam-timesync.timer(see 2026-08-08-camera-osd-clock-drift-onvif-timesync). DEAD:~/tapo-ctl/reboot-cam.py/reboot-onvif.py(pytapo, hardcodednvr42vhy1creds —Invalid authentication dataon both cams). Left in place but non-functional. Backups:camwall-mpv.sh.bak-1786433100,camwall-watchdog.py.bak-1786433100.
Symptom vs. why the existing watchdogs missed it
The failure looked like “stuck cams” but every automatic guard reported healthy:
- A single quadrant showed a static image with a frozen OSD clock (stalled stream — no new frames arriving), for a long time.
- Frigate ingest was fine:
camera_fps ~5, so the Frigate per-camera FPS watchdog saw nothing wrong (it watches Frigate’s/api/stats, not the display panes). - The camwall stall-watchdog existed but was blind to three of the four panes (see Root cause 1).
This is a display-side stall: the go2rtc substream to that one mpv pane stopped delivering frames and mpv held the last frame, while Frigate’s own ingest of the same camera kept running. Nothing tied the two together, so the quadrant stayed frozen.
Root cause 1 — camwall panes had no per-pane freeze detection (the real “stuck” cause)
The camwall runs four independent mpv processes (one per quadrant, from the tiled low-latency rearchitecture in Latency fix (2026-07-29) — 4 tiled single-input mpv instances). Previously only the cam2 pane exposed --input-ipc-server=/run/camwall.sock. camwall-watchdog.py checked mpv time-pos on that one socket.
A stalled cam1/cam3/cam4 pane was undetectable
If the cam1, cam3, or cam4 pane stalled (stream stops → static image, frozen OSD clock), nothing detected it and nothing re-rolled — that quadrant sat frozen indefinitely while Frigate ingest stayed healthy. Only a stall of the single socket-owning cam2 pane would ever trip a re-roll. This is exactly the “watchdog freeze-detection now only covers the one IPC-socket-owning pane, not all 4 — security-relevant” regression that was left open in 2026-07-28-camwall-4-substream-composite.
Fix — per-pane IPC sockets + all-four-pane polling
- All four panes now get their own IPC socket:
/run/camwall-cam{1,2,3,4}.sock(in/usr/local/bin/camwall-mpv.sh). camwall-watchdog.pynow pollstime-poson all four sockets, keeps a per-socket stall counter, and re-rolls the whole wall (systemctl restart camwall) if any pane reachesSTALL_LIMIT.- HDMI-reconnect logic preserved unchanged.
- Backups:
camwall-mpv.sh.bak-1786433100,camwall-watchdog.py.bak-1786433100.
Verified end-to-end via stall simulation
Pausing the cam3 pane produced, ~33 s later:
camwall-watchdog.py: rerolling camwall: pane /run/camwall-cam3.sock stalled
…and the wall re-rolled (cam3 pane uptime reset to fresh). All four sockets respond to time-pos.
Scope: this catches STALLED-STREAM freezes, not repeated-frame freezes
The watchdog trips when
time-posstops advancing (no new frames). It does not catch a camera that keeps pushing a repeated frozen frame at full fps (theretime-poskeeps advancing). The user confirmed the freezes on this wall are the static/stalled kind, so content-hash / framebuffer-staleness detection was not needed. If a repeated-frozen-frame failure ever shows up, that’s the direction to add.
Root cause 2 — camera reboot tooling was silently broken
The recovery for a wedged camera is an ONVIF reboot (established in 2026-08-03-cam-stall-recovery-and-casino-alert). The pytapo-based tool no longer works:
pytapo reboot path is dead —
Invalid authentication data
~/tapo-ctl/reboot-cam.py(pytapo, hardcoded accountnvr42vhy1+ password lifted fromdisable_alarm.py) now fails withInvalid authentication dataon BOTH cameras (192.168.30.119,192.168.30.139) — the classic Tapo firmware/KLAP auth breakage. pytapo is not a viable path here anymore.
Fix — ONVIF SystemReboot() with Frigate creds
The working path is ONVIF SystemReboot() on port 2020 using the Frigate RTSP creds — the same credential resolution set-cam-time.py uses (reads them from the Frigate container config + docker env), not the stale hardcoded nvr42vhy1 account.
New tool ~/tapo-ctl/reboot-cams-onvif.py:
- Reboots the given IPs (default: both cams) via ONVIF
SystemReboot(). - Waits for each camera to ping back.
- Re-syncs the OSD clock by invoking
set-cam-time.py(see Root cause 3).
Cleanup: the dead ~/tapo-ctl/reboot-cams.py (an earlier pytapo attempt) was removed. The user’s original hardcoded reboot-cam.py / reboot-onvif.py (.139 only, stale nvr42vhy1 creds) were left in place but are effectively dead.
Root cause 3 — wrong OSD time after a reboot
Tapo cams have no RTC, so a reboot wipes their clock. cam-timesync.timer re-pushes host time over ONVIF hourly (cam-timesync.service, “Push host time to Tapo cameras over ONVIF”), so it self-heals within an hour — but that leaves a ~40 min window of wrong OSD time after any reboot.
Fix: re-sync the clock immediately on reboot, don't wait for the hourly timer
reboot-cams-onvif.pycallsset-cam-time.pyas soon as the cameras come back up, closing the post-reboot gap. Both cams verified showing correct time after. Full background on the ONVIF time-push (pre-compensated for the Tapo TZ bug, DST-safe) is in 2026-08-08-camera-osd-clock-drift-onvif-timesync.
This session’s manual actions
- Both cameras were manually rebooted via the new ONVIF tool — both healthy after (~5 fps).
- The camwall was re-rolled.
Related pieces on the box
camwall.service//usr/local/bin/camwall-mpv.sh— the 4-pane tiled wallcamwall-watchdog.service//usr/local/bin/camwall-watchdog.py— HDMI reconnect + now all-4-pane stall detectioncamwall-frigate-watch.service— re-rolls camwall when Frigate restartscam-timesync.timer/cam-timesync.service— hourly ONVIF host-time push
Related
- 2026-07-28-camwall-4-substream-composite — the 4-pane tiled wall + the open “watchdog covers only the IPC-socket-owning pane” regression this note closes
- 2026-08-03-cam-stall-recovery-and-casino-alert — the wedged-RTSP camera failure a Frigate restart does NOT fix; ONVIF reboot is the recovery (now via the new working tool)
- 2026-08-08-camera-osd-clock-drift-onvif-timesync — the hourly ONVIF time push + Tapo TZ/NTP bugs;
set-cam-time.pyinternals - 2026-08-08-frigate-fps-watchdog — the Frigate-side watchdog that stayed healthy through this display-side freeze (why it looked like “nothing wrong”)
- 2026-07-31-camwall-lag-24ghz-wifi-bufferbloat — the upstream 2.4 GHz WiFi saturation that stresses these same substreams
- telep-mainframe
- telep-mainframe-handover
- SESSION-HANDOVER