From 18084ec9d7fb5609f93ac15c7c2d8048949c857b Mon Sep 17 00:00:00 2001 From: Docker Config Backup Date: Thu, 28 May 2026 23:33:14 +0200 Subject: [PATCH] fix: clear PTZ flag on all MBeg keyboard video inputs Keyboard interfaces under Clients/GeViIO/GeViIO_01 should never have the PTZ flag set on their video inputs. Previously PTZ cameras (e.g. 101027) were exported with PTZ=True on every keyboard, unlike fixed cameras. Adds geviset.disable_keyboard_ptz() and runs it at the end of the video input pipeline in both /api/set/export and /api/batch/build. Only the keyboard interfaces are touched; virtual decoders/servers under GeViIO_Virtual keep their PTZ flags so PTZ control still works. Co-Authored-By: Claude Opus 4.8 --- backend/app/geviset.py | 28 ++++++++++++++++++++++++++++ backend/app/main.py | 2 ++ 2 files changed, 30 insertions(+) diff --git a/backend/app/geviset.py b/backend/app/geviset.py index 96d88cb..fd6222f 100644 --- a/backend/app/geviset.py +++ b/backend/app/geviset.py @@ -1092,6 +1092,34 @@ def ensure_global_video_inputs(tree, global_ids, ptz_by_id=None): ) +def disable_keyboard_ptz(tree): + """Force PTZ off for every video input on every MBeg keyboard interface. + + Keyboards live directly under Clients/GeViIO/GeViIO_01 (each is an + interface folder with its own VideoInputs). PTZ control on the keyboard + side is never wanted, so the PTZ flag of each video input is cleared. + Virtual decoders/servers under GeViIO_Virtual are left untouched. + """ + geviio = _find_folder(tree, ["Clients", "GeViIO", "GeViIO_01"]) + if not geviio: + return 0 + cleared = 0 + for interface in geviio.get("children", []): + if not isinstance(interface, dict) or interface.get("type") != "folder": + continue + video_inputs = _child_by_name(interface, "VideoInputs") + if video_inputs is None: + continue + for entry in video_inputs.get("children", []): + if entry.get("type") != "folder": + continue + ptz_node = _child_by_name(entry, "PTZ") + if ptz_node is not None and ptz_node.get("value") is not False: + ptz_node["value"] = False + cleared += 1 + return cleared + + def prune_video_inputs(tree, global_ids): target_ids = {int(x) for x in global_ids if isinstance(x, int) and x > 0} if not target_ids: diff --git a/backend/app/main.py b/backend/app/main.py index 30e4a0c..b18ac4a 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -110,6 +110,7 @@ async def export_set(payload: dict): geviset.ensure_global_video_inputs(tree, camera_ids, ptz_by_id) geviset.ensure_vx3_video_inputs(tree, camera_ids, ptz_by_id) geviset.prune_video_inputs(tree, camera_ids) + geviset.disable_keyboard_ptz(tree) print( f"EXPORT camera_ids={len(camera_ids)} contains_101027={101027 in camera_ids}", flush=True, @@ -301,6 +302,7 @@ async def build_from_excel( geviset.ensure_global_video_inputs(tree, camera_ids, ptz_by_id) geviset.ensure_vx3_video_inputs(tree, camera_ids, ptz_by_id) geviset.prune_video_inputs(tree, camera_ids) + geviset.disable_keyboard_ptz(tree) if servers and servers.filename: if not servers.filename.lower().endswith(".xlsx"):