Initial commit: COPILOT D6 Flutter keyboard controller

Flutter web app replacing legacy WPF CCTV surveillance keyboard controller.
Includes wall overview, section view with monitor grid, camera input,
PTZ control, alarm/lock/sequence BLoCs, and legacy-matching UI styling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
klas
2026-02-12 14:57:38 +01:00
commit 40143734fc
125 changed files with 65073 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
---
title: "Configuration"
description: "JSON configuration files, monitor wall topology, and function button mapping"
---
# Configuration System
## Configuration Files
All configuration is stored as JSON files, managed centrally on the AppServer and synced to each keyboard.
### appsettings.json (Main)
```json
{
"UseSoftwareRendering": true,
"AppServerConfiguration": {
"Uri": "https://copilot.test.d6.colsys.cz",
"Timeout": "00:00:01.5"
},
"ReconnectionConfiguration": {
"ReconnectionPeriod": "00:00:02"
},
"ViewerStates": {
"AppServerConnectionTimeout": "00:00:05"
}
}
```
| Setting | Value | Purpose |
|---------|-------|---------|
| `UseSoftwareRendering` | `true` | Forces WPF software rendering (no GPU) for LattePanda |
| `AppServerConfiguration.Uri` | HTTPS URL | Central AppServer for coordination |
| `AppServerConfiguration.Timeout` | 1.5s | HTTP request timeout |
| `ReconnectionPeriod` | 2s | Auto-reconnect interval to camera servers |
| `AppServerConnectionTimeout` | 5s | SignalR connection timeout |
### appsettings-copilot.json (Per-Keyboard)
```json
{
"CopilotConfig": {
"WallId": 2,
"CameraLockOptions": {
"Priority": "Low",
"Timeout": "00:05:00"
},
"CameraNumberOptions": {
"MaxLength": 6,
"Prefixes": ["500", "501", "502"],
"CancelEditTimeout": "00:05"
},
"ViewerStateThrottleInterval": "00:00:00.150",
"CentralServer": {
"IpAddress": "192.168.102.186",
"UserName": "sysadmin",
"Password": "masterkey"
},
"AllowPrepositionsInterval": {
"Min": 10,
"Max": 99
},
"PlaybackOptions": {
"Allowed": true,
"Speeds": [1, 2, 5, 15, 30, 100, 250]
},
"AlarmHistoryOptions": {
"CameraIdExtractionRegex": "^\\D*(?<CameraId>\\d{6})\\D*$",
"DefaultSearchInterval": "30.00:00:00"
}
}
}
```
| Setting | Purpose |
|---------|---------|
| `WallId` | Which monitor wall this keyboard controls |
| `CameraLockOptions.Priority` | PTZ lock priority (`Low` / `High`) |
| `CameraLockOptions.Timeout` | Lock auto-expiration (5 min) |
| `CameraNumberOptions.MaxLength` | Max digits for camera number (6) |
| `CameraNumberOptions.Prefixes` | Auto-prefixes for camera numbers |
| `CancelEditTimeout` | Auto-cancel camera number entry (5 sec) |
| `ViewerStateThrottleInterval` | Debounce viewer state updates (150ms) |
| `PlaybackOptions.Speeds` | Shuttle playback speeds (1x to 250x) |
| `AllowPrepositionsInterval` | Valid preposition range (10-99) |
### appsettings-camera-servers.json
```json
{
"CameraServerConfig": {
"CameraServers": [
{
"IpAddress": "192.168.102.20",
"UserName": "sysadmin",
"Password": "masterkey",
"CameraServerType": "GCore"
},
{
"IpAddress": "192.168.102.186",
"UserName": "sysadmin",
"Password": "masterkey",
"CameraServerType": "GeviScope"
}
]
}
}
```
Supported server types: `GeViScope`, `GCore`, `GeViSoft`
### appsettings-monitor-wall.json (Topology)
Defines the physical monitor wall layout:
```mermaid
graph TD
subgraph "Wall (WallId: 1, Name: HDŘÚ TSK/DIC)"
subgraph "Segment 1 (4 rows × 8 cols)"
M1["Monitor #01<br/>2×2 span<br/>VM: 151,152,153,154"]
M2["Monitor #02<br/>2×2 span<br/>VM: 155,156,157,158"]
M3["Monitor #03"]
M4["Monitor #04"]
M5["Monitor #05<br/>...etc"]
end
end
```
Hierarchy:
```
Wall
└── Segment (grid: RowCount × ColumnCount)
└── Monitor (physical screen, positioned at Row/Col with RowSpan/ColSpan)
└── VirtualMonitor (individual video feed, positioned within monitor grid)
```
A single physical monitor can display multiple virtual monitors (e.g., 2×2 quad view). Each VirtualMonitor has a unique `VirtualMonitorId` that maps to a `ViewerId` in the camera server.
### appsettings-function-buttons.json
Maps F1-F7 and Home keys to actions per wall:
```json
{
"FunctionButtonsConfig": {
"FunctionButtons": [
{
"WallId": 1,
"Buttons": [
{
"Button": "F1",
"Actions": [
{ "ViewerId": 1001, "ActionType": "CrossSwitch", "SourceId": 501111 },
{ "ViewerId": 1002, "ActionType": "CrossSwitch", "SourceId": 502345 }
]
},
{
"Button": "F4",
"Actions": [
{ "ViewerId": 1001, "ActionType": "SequenceStart", "SourceId": 258 }
]
}
]
}
]
}
}
```
Action types: `CrossSwitch` (switch camera to viewer), `SequenceStart` (start camera cycling)
### appsettings-sequences.json
```json
{
"SequencesConfig": {
"Sequences": [
{
"Id": 1,
"CategoryId": 1,
"Name": "Test-A",
"Interval": 1,
"MediaChannels": [500100, 500101, 500102, 500103]
}
]
}
}
```
## AppServer Configuration
```json
{
"ConnectionStrings": {
"SqliteConnection": "Data Source=copilot.db"
},
"CameaApiClient": {
"Uri": "http://localhost:8081",
"Timeout": "00:00:01.5",
"TimeZone": "Central Europe Standard Time"
},
"LockExpirationConfig": {
"LockExpirationTimeout": "00:05:00",
"NotificationBeforeExpiration": "00:01:00"
},
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://*:443",
"Certificate": {
"Subject": "copilot.test.d6.colsys.cz",
"Store": "Root",
"Location": "LocalMachine"
}
}
}
}
}
```
## Network Topology
```
┌───────────────────────────────────────────────────────────┐
│ 192.168.102.0/24 Network │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ GeViScope Server │ │ G-Core Server │ │
│ │ 192.168.102.186 │ │ 192.168.102.20 │ │
│ │ sysadmin/master │ │ sysadmin/master │ │
│ └────────┬─────────┘ └────────┬────────┘ │
│ │ TCP (native SDK) │ TCP (native SDK) │
│ │ │ │
│ ┌────────┴──────────────────────┴────────┐ │
│ │ Keyboard SBC │ │
│ │ (LattePanda Sigma) │ │
│ │ Copilot.App.exe (WPF) │ │
│ └────────┬───────────────────────────────┘ │
│ │ HTTPS/WSS (SignalR) │
│ │ │
│ ┌────────┴───────────────────────────────┐ │
│ │ AppServer │ │
│ │ copilot.test.d6.colsys.cz:443 │ │
│ │ Copilot.AppServer.exe │ │
│ │ + SQLite DB + Camea API (:8081) │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ Elasticsearch (logging) │ │
│ │ localhost:9200 │ │
│ └────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
```