--- title: "Data Flows" description: "CrossSwitch, Alarms, Sequences, Playback, and Camera Lock workflows" --- # Data Flows ## 1. CrossSwitch (Switch Camera to Monitor) The primary operation — routing a camera feed to a physical monitor output. ```mermaid sequenceDiagram participant Op as Operator participant VM as SegmentViewModel participant CenD as CentralServerDriver participant Srv as Camera Server Op->>VM: Enter camera number (digits + Enter) VM->>VM: Validate camera exists via MediaChannelService alt Camera exists alt Playback active on this viewer VM->>VM: playbackStateService.SetPlaybackState(false) end alt Sequence active on this viewer VM->>VM: hub.Stop(viewerId) end VM->>CenD: CrossSwitch(viewerId, cameraNumber) CenD->>Srv: SDK CrossSwitch command Note over Srv: Server switches video output
and fires ViewerConnectionEvent else Camera not found VM->>VM: ShowError("MediaChannel does not exist", 2s) end ``` ### CrossSwitch Triggers 1. **Numeric entry** — Type camera number + Enter 2. **Plus/Minus keys** — Cycle to next/previous camera in sorted order 3. **Function buttons** — F1-F7 mapped to preconfigured CrossSwitch actions 4. **Home key** — When not in PTZ mode or playback, executes function button "Home" ### Camera Number Editing ``` State: Not Editing │ ├─ Press digit → BeginEdit(), append digit, start cancel timer │ ▼ State: Editing (showing entered digits) │ ├─ Press digit → append digit, restart cancel timer ├─ Press Backspace → remove last digit, restart cancel timer ├─ Press Enter → validate, CrossSwitch if valid, EndEdit() └─ Cancel timer fires → CancelEdit(), revert to original camera ``` Camera number can be up to 6 digits. Configurable prefixes (e.g., "500", "501", "502") are prepended automatically based on the selected prefix. ## 2. Camera Lock Workflow Camera locks coordinate PTZ access across multiple keyboards via the AppServer SignalR hub. ```mermaid sequenceDiagram participant K1 as Keyboard 1 (Low priority) participant Hub as AppServer Hub participant DB as SQLite DB participant K2 as Keyboard 2 (High priority) K1->>Hub: TryLockCamera(camId, "K1", Low) Hub->>DB: Check existing lock DB-->>Hub: No lock exists Hub->>DB: Create lock(camId, "K1", Low, expires=5min) Hub-->>K1: LockResult(Acquired=true) K1->>K1: IsCameraTelemetryActive = true Note over K1: Operator controls PTZ...
Each action calls ResetCameraLockExpiration() K2->>Hub: TryLockCamera(camId, "K2", High) Hub->>DB: Check existing lock → held by K1 Hub-->>K2: LockResult(Acquired=false, Owner="K1") K2->>Hub: RequestCameraLock(camId, "K2", High) Hub->>K1: CameraLockNotify(ConfirmTakeOver) K1->>K1: Show dialog "K2 requests lock" alt K1 confirms takeover K1->>Hub: CameraLockConfirmTakeOver(confirm=true) Hub->>K1: CameraLockNotify(Unlocked) Hub->>K2: CameraLockNotify(Confirmed) K2->>Hub: TryLockCamera(camId, "K2", High) Hub-->>K2: LockResult(Acquired=true) else K1 denies K1->>Hub: CameraLockConfirmTakeOver(confirm=false) Hub->>K2: CameraLockNotify(Rejected) end ``` ### Lock Priority Levels Configured per keyboard in `appsettings-copilot.json`: - `Low` — Standard operator - `High` — Supervisor (can request takeover) ### Lock Expiration - **Timeout:** 5 minutes (`LockExpirationConfig.LockExpirationTimeout`) - **Warning:** 1 minute before expiration (`NotificationBeforeExpiration`) - **Reset:** Every PTZ action or explicit reset call extends the timer ## 3. Alarm System ```mermaid sequenceDiagram participant Worker as CameraAlarmsUpdateWorker participant CAS as CameraAlarmService participant Hub as CopilotHub participant AS as AppServer participant Camea as Camea API Note over Worker: Background worker (periodic) Worker->>CAS: UpdateCameraToAlarmsMapping() CAS->>Hub: GetCamerasWithAlarms() Hub->>AS: Query AS->>Camea: GET /api/alarms Camea-->>AS: List of cameras with active alarms AS-->>Hub: HashSet cameraIds Hub-->>CAS: Store in camerasWithAlarms Note over CAS: UI can now check HasCameraAlarms(cameraId) Note over Worker: Also on SegmentViewModel... participant VM as SegmentViewModel VM->>CAS: GetAlarmForCamera(camId, from, to) CAS->>Hub: GetAlarmsForCamera(camId, from, to) Hub->>AS: Query alarm history AS-->>Hub: List Hub-->>CAS: Alarms (UTC → LocalTime) CAS-->>VM: Sorted by StartTime desc ``` ### Alarm-Related Behavior - Screens with active alarms **block** camera number editing (CrossSwitch disabled) - Alarm history page uses configurable regex to extract camera ID from alarm names: `^\D*(?\d{6})\D*$` - Default search interval: 30 days ## 4. Sequence Management Sequences automatically cycle cameras on a monitor at configurable intervals. ```mermaid sequenceDiagram participant Op as Operator participant VM as SegmentViewModel participant SeqS as SequenceService participant Hub as SignalR Hub participant AS as AppServer Op->>VM: Press Sequence key VM->>VM: Navigate to SequenceCategoriesPage Op->>VM: Select category VM->>SeqS: GetSequences(categoryId) SeqS->>Hub: GetSequences(categoryId) Hub-->>SeqS: List Op->>VM: Select sequence VM->>SeqS: Start(viewerId, sequenceId) SeqS->>Hub: Start(viewerId, sequenceId) Note over AS: AppServer runs sequence timer AS->>Hub: ViewerSequenceStateChanged Hub->>SeqS: OnChanged(viewerSequenceState) SeqS->>VM: Update UI (sequence indicator) Note over AS: Timer fires every N seconds AS->>AS: CrossSwitch next camera in list ``` ### Sequence Configuration ```json { "Id": 1, "CategoryId": 1, "Name": "Test-A", "Interval": 1, // seconds between switches "MediaChannels": [500100, 500101, 500102, 500103] } ``` Sequences are **run on the AppServer**, not on the keyboard. The keyboard only starts/stops them. ## 5. Playback Control ```mermaid sequenceDiagram participant Op as Operator participant VM as SegmentViewModel participant VC as IViewerController participant Srv as Camera Server Note over Op: Playback enters via Jog/Shuttle
or Playback button Op->>VM: Jog right (arrow key) VM->>VM: IsPlaybackActive = true VM->>VC: StepForwardAndStop() VC->>Srv: Step forward one frame Op->>VM: Shuttle right position 3 VM->>VM: TryGetShuttleSpeed(speeds, out speed, out forward) Note over VM: position 3 → speeds[2] = 5 VM->>VC: FastForward(5) VC->>Srv: Play at 5x speed Op->>VM: Shuttle center VM->>VC: Stop() Op->>VM: Press Home key VM->>VC: PlayLive() VM->>VM: IsPlaybackActive = false ``` ### Playback Controls | Input | Action | SDK Method | |-------|--------|------------| | Jog Left | Step back 1 frame | `StepBackwardAndStop()` | | Jog Right | Step forward 1 frame | `StepForwardAndStop()` | | Shuttle Left 1-7 | Rewind at speed | `FastBackward(speed)` | | Shuttle Right 1-7 | Fast forward at speed | `FastForward(speed)` | | Shuttle Center | Pause | `Stop()` | | Home | Return to live | `PlayLive()` | ## 6. Function Buttons F1-F7 and Home keys execute preconfigured action lists per wall: ```mermaid graph TD Key["F1-F7 / Home Key Press"] --> FBS["FunctionButtonsService"] FBS --> Config["Load from appsettings-function-buttons.json"] Config --> Actions["Get actions for wallId + buttonKey"] Actions --> ForEach["For each action:"] ForEach -->|CrossSwitch| CS["CentralServerDriver.CrossSwitch(viewerId, sourceId)
+ Minimize viewer"] ForEach -->|SequenceStart| SS["SequenceService.Start(viewerId, sourceId)"] ``` Example: Pressing F1 on Wall 2 executes: ```json { "ViewerId": 12322, "ActionType": "CrossSwitch", "SourceId": 500123 } ``` This switches camera 500123 to viewer 12322. ## 7. Configuration Sync Configuration files are managed centrally on the AppServer and synced to keyboards: ```mermaid sequenceDiagram participant AS as AppServer participant Hub as SignalR Hub participant CfgS as ConfigurationService participant Disk as Local JSON Files Note over CfgS: On startup CfgS->>Hub: GetConfigurationFile(filename) for each manager Hub-->>CfgS: ConfigurationFile (content + hash) CfgS->>Disk: Compare hash, write if changed Note over AS: Admin changes config via Blazor UI AS->>Hub: ConfigurationFileChanged event Hub->>CfgS: OnConfigurationFileChanged(file) CfgS->>Disk: Write updated content Note over CfgS: Also triggered when AppServer
becomes available after disconnect ``` Configuration files synced: - `appsettings-copilot.json` — Keyboard-specific settings - `appsettings-camera-servers.json` — Camera server connections - `appsettings-monitor-wall.json` — Monitor wall topology - `appsettings-function-buttons.json` — Function button actions - `appsettings-prepositions.json` — Camera prepositions - `appsettings-sequences.json` — Sequence definitions - `appsettings-sequence-categories.json` — Sequence categories