This MVP release provides a complete full-stack solution for managing action mappings in Geutebruck's GeViScope and GeViSoft video surveillance systems. ## Features ### Flutter Web Application (Port 8081) - Modern, responsive UI for managing action mappings - Action picker dialog with full parameter configuration - Support for both GSC (GeViScope) and G-Core server actions - Consistent UI for input and output actions with edit/delete capabilities - Real-time action mapping creation, editing, and deletion - Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers) ### FastAPI REST Backend (Port 8000) - RESTful API for action mapping CRUD operations - Action template service with comprehensive action catalog (247 actions) - Server management (G-Core and GeViScope servers) - Configuration tree reading and writing - JWT authentication with role-based access control - PostgreSQL database integration ### C# SDK Bridge (gRPC, Port 50051) - Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll) - Action mapping creation with correct binary format - Support for GSC and G-Core action types - Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug) - Action ID lookup table with server-specific action IDs - Configuration reading/writing via SetupClient ## Bug Fixes - **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet - Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)` - Proper filter flags and VideoInput=0 for action mappings - Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft) ## Technical Stack - **Frontend**: Flutter Web, Dart, Dio HTTP client - **Backend**: Python FastAPI, PostgreSQL, Redis - **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK - **Authentication**: JWT tokens - **Configuration**: GeViSoft .set files (binary format) ## Credentials - GeViSoft/GeViScope: username=sysadmin, password=masterkey - Default admin: username=admin, password=admin123 ## Deployment All services run on localhost: - Flutter Web: http://localhost:8081 - FastAPI: http://localhost:8000 - SDK Bridge gRPC: localhost:50051 - GeViServer: localhost (default port) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
11 KiB
REST API Endpoints - Data Sources Explained
Overview
This document explains where each REST API endpoint gets its data and how the flow works.
🎥 Camera Endpoints
GET /api/v1/cameras
Data Source: GeViServer Camera Manager (real-time, in-memory)
Flow:
Client → FastAPI → gRPC (CameraService) → StateQueryHandler → SDK → GeViServer Camera Manager
Code Path:
routers/cameras.py- REST endpointservices/camera_service.py- Business logicclients/sdk_bridge_client.py- gRPC clientServices/CameraService.cs(C#) - gRPC serviceSDK/StateQueryHandler.cs(C#) - SDK wrapperCSQGetFirstVideoInput()+CSQGetNextVideoInput()- SDK enumeration
What You Get:
[
{
"channel": 1,
"name": "Front Door Camera",
"description": "Main entrance",
"has_ptz": true,
"has_video_sensor": true,
"status": "online"
}
]
Data Characteristics:
- ✅ Real-time camera list
- ✅ Current connection status
- ✅ Live from GeViServer memory
- ❌ NOT stored in TestMKS.set
- 🔄 Changes when cameras connect/disconnect
📺 Monitor Endpoints
GET /api/v1/monitors
Data Source: GeViServer Monitor Manager (real-time, in-memory)
Flow:
Client → FastAPI → gRPC (MonitorService) → StateQueryHandler → SDK → GeViServer Monitor Manager
Code Path:
routers/monitors.pyservices/monitor_service.pyclients/sdk_bridge_client.pyServices/MonitorService.cs(C#)SDK/StateQueryHandler.cs(C#)CSQGetFirstVideoOutput()+CSQGetNextVideoOutput()
What You Get:
[
{
"channel": 1,
"name": "Main Monitor",
"is_active": true,
"current_camera_id": 7
}
]
Data Characteristics:
- ✅ Real-time monitor/viewer list
- ✅ Current routing state (which camera is shown)
- ✅ GSCView client status
- ❌ NOT in TestMKS.set
- 🔄 Changes when monitors connect/disconnect
🔀 CrossSwitch Endpoints
POST /api/v1/crossswitch
Action: Routes camera to monitor (sends command to GeViServer)
Flow:
Client → FastAPI → gRPC (CrossSwitchService) → ActionDispatcher → SDK → GeViServer Action Engine
Request:
{
"camera_id": 7,
"monitor_id": 3,
"mode": 0
}
Code Path:
routers/crossswitch.pyservices/crossswitch_service.pyServices/CrossSwitchService.cs(C#)SDK/ActionDispatcher.cs(C#)SendAction("CrossSwitch", ...)- SDK action
What Happens:
- GeViServer routes video from Camera 7 to Monitor 3
- Monitor immediately shows the camera feed
- Routing state updated in GeViServer memory
DELETE /api/v1/monitors/{id}
Action: Clears monitor (stops video display)
Code Path: Similar to CrossSwitch but calls ClearVideoOutput action
⚙️ Configuration Endpoints (✅ IMPLEMENTED)
GET /api/v1/configuration/servers
Data Source: TestMKS.set file (persistent binary configuration)
Flow:
Client → FastAPI → gRPC (ConfigurationService) → SetupClient.Download() →
Parse .set file → Extract GeViGCoreServer folder → Return servers
Code Path:
routers/configuration.pyservices/configuration_service.pyclients/sdk_bridge_client.pyServices/ConfigurationService.cs(C#) - gRPC serviceSDK/GeViSetupClientWrapper.cs(C#) - Download configServices/FolderTreeParser.cs(C#) - Parse binary .set- Navigate to "GeViGCoreServer" folder
- Extract all server nodes
What You Get:
[
{
"id": "1",
"alias": "Remote Server 1",
"host": "192.168.1.100",
"user": "admin",
"enabled": true,
"deactivate_echo": false,
"deactivate_live_check": false
},
{
"id": "2",
"alias": "Remote Server 2",
...
}
]
Data Characteristics:
- ✅ Persistent in TestMKS.set file
- ✅ Survives GeViServer restart
- ✅ Visible in GeViSet UI
- 💾 Binary format, parsed on-demand
- 🔒 Requires SetupClient download
POST /api/v1/configuration/servers
Action: Creates new G-Core server in configuration
Flow:
Client → FastAPI → gRPC → SetupClient.Download() → Parse .set →
Auto-increment ID → Create server node → Write tree → SetupClient.Upload()
Request:
{
"alias": "New Remote Server",
"host": "192.168.1.200",
"user": "admin",
"password": "secret",
"enabled": true
}
What Happens:
- Downloads current TestMKS.set file
- Parses binary format into folder tree
- Finds GeViGCoreServer folder
- Calculates new ID (max existing ID + 1)
- Creates new server node with all fields
- Writes modified tree back to binary
- Uploads to GeViServer
- GeViServer saves and reloads config
Response:
{
"id": "14",
"alias": "New Remote Server",
"host": "192.168.1.200",
...
}
PUT /api/v1/configuration/servers/{server_id}
Status: ⚠️ KNOWN BUG - "Server ID is required"
Intended Flow: Download → Parse → Find server → Update fields → Upload
Workaround: Use DELETE + POST to replace server
DELETE /api/v1/configuration/servers/{server_id}
Action: Removes server from configuration
Flow:
Client → FastAPI → gRPC → Download .set → Parse →
Find server node by ID → Remove node → Upload
Critical Note: When deleting multiple servers, always delete in REVERSE ORDER (highest ID first) to prevent ID shifting!
GET /api/v1/configuration/action-mappings
Data Source: TestMKS.set file → ActionMapping folder
Flow: Same as servers, but navigates to "ActionMapping" folder
What You Get:
[
{
"id": 1,
"name": "Door Contact Mapping",
"input_action": "GeVi DoorContact_101001",
"output_action": "GeVi PanLeft_101027",
"enabled": true
}
]
Data Characteristics:
- ID is 1-based index in MappingRules list
- Each mapping links input action → output action
- Used for automation (e.g., door opens → camera pans)
POST /api/v1/configuration/action-mappings
Action: Creates new action mapping
Flow: Download → Parse → Add to MappingRules list → Upload
Request:
{
"name": "VMD Trigger",
"input_action": "GeVi VideoMotionDetection_7",
"output_action": "GeVi StartRecording_7",
"enabled": true
}
PUT /api/v1/configuration/action-mappings/{mapping_id}
Action: Updates existing action mapping
Flow: Download → Parse → Find by ID → Update fields → Upload
Status: ✅ WORKING (all CRUD operations functional)
DELETE /api/v1/configuration/action-mappings/{mapping_id}
Action: Removes action mapping
Flow: Download → Parse → Remove from list → Upload
⚠️ CRITICAL: When deleting multiple mappings, always delete in REVERSE ORDER!
Why? Mappings use 1-based indices. Deleting mapping #5 shifts all subsequent mappings down by 1 index.
Example Bug:
Original: [#1, #2, #3, #4, #5, #6]
Delete #4 → [#1, #2, #3, #5→4, #6→5]
Delete #5 (which is now actually #6!) → WRONG MAPPING DELETED!
Solution:
# Sort by ID descending
mappings_sorted = sorted(mappings, key=lambda x: x['id'], reverse=True)
for mapping in mappings_sorted:
delete_action_mapping(mapping['id']) # Delete from highest to lowest
🔐 Authentication Endpoints
POST /api/v1/auth/login
Data Source: PostgreSQL database (user credentials)
Flow: FastAPI → AuthService → Database query → JWT generation
Not fully implemented yet - authentication is stubbed out
❤️ Health Endpoint
GET /api/v1/health
Data Source: Real-time component checks
Checks:
- Database: PostgreSQL connection test
- Redis: Cache connectivity
- SDK Bridge: gRPC connection test (calls ping)
Response:
{
"status": "healthy",
"version": "1.0.0",
"components": {
"database": "healthy",
"redis": "healthy",
"sdk_bridge": "healthy"
},
"timestamp": "2025-12-16T21:15:00Z"
}
🔍 Data Source Summary
| Endpoint Pattern | Data Source | Access Method | Persistent? |
|---|---|---|---|
/cameras |
GeViServer memory | SDK State Query | ❌ Real-time |
/monitors |
GeViServer memory | SDK State Query | ❌ Real-time |
/crossswitch |
GeViServer actions | SDK Action Dispatch | ❌ Command |
/configuration/servers |
TestMKS.set | SetupClient + Parser | ✅ Persistent |
/configuration/action-mappings |
TestMKS.set | SetupClient + Parser | ✅ Persistent |
/auth/* |
PostgreSQL | Database query | ✅ Persistent |
/health |
Component checks | Direct probe | ❌ Real-time |
🎯 Testing the API
Using Swagger UI
- Open http://localhost:8000/docs
- All endpoints are documented with schemas
- Click "Try it out" to test
Using curl
# List cameras
curl http://localhost:8000/api/v1/cameras
# List servers
curl http://localhost:8000/api/v1/configuration/servers
# Get specific server
curl http://localhost:8000/api/v1/configuration/servers/1
# Create server
curl -X POST http://localhost:8000/api/v1/configuration/servers \
-H "Content-Type: application/json" \
-d '{
"alias": "Test Server",
"host": "192.168.1.50",
"user": "admin",
"password": "test123",
"enabled": true
}'
# Delete server
curl -X DELETE http://localhost:8000/api/v1/configuration/servers/14
Using Python
import requests
# List cameras
response = requests.get("http://localhost:8000/api/v1/cameras")
cameras = response.json()
print(f"Found {len(cameras)} cameras")
# Get all servers
response = requests.get("http://localhost:8000/api/v1/configuration/servers")
servers = response.json()
print(f"Found {len(servers)} servers")
# Create server
new_server = {
"alias": "Python Test Server",
"host": "192.168.1.99",
"user": "admin",
"password": "secret",
"enabled": True
}
response = requests.post(
"http://localhost:8000/api/v1/configuration/servers",
json=new_server
)
created = response.json()
print(f"Created server with ID: {created['id']}")
🐛 Common Issues
1. Empty Camera List
Cause: No cameras configured in GeViServer
Solution: Add IP cameras in GeViSet or camera configuration
2. Configuration Endpoints Return Error
Cause: SetupClient cannot connect to GeViServer
Possible reasons:
- GeViSet is connected (blocks SetupClient port)
- GeViServer not running
- Port 7702 not available
Solution:
- Close GeViSet
- Ensure GeViServer is running
- Check
status-services.ps1
3. CrossSwitch Fails
Cause: Invalid camera or monitor ID
Solution: First call /cameras and /monitors to get valid IDs
📚 Next Steps
- Test each endpoint with Swagger UI
- Verify data sources match expectations
- Check logs for any errors
- Use test scripts in repository root:
comprehensive_crud_test.py- Full CRUD testverify_config_via_grpc.py- Config verification
Last Updated: 2025-12-16 Version: 1.0