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:
253
Docs/legacy-architecture/configuration.md
Normal file
253
Docs/legacy-architecture/configuration.md
Normal 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 │ │
|
||||
│ └────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
```
|
||||
Reference in New Issue
Block a user