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>
494 lines
11 KiB
Markdown
494 lines
11 KiB
Markdown
# 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**:
|
|
1. `routers/cameras.py` - REST endpoint
|
|
2. `services/camera_service.py` - Business logic
|
|
3. `clients/sdk_bridge_client.py` - gRPC client
|
|
4. `Services/CameraService.cs` (C#) - gRPC service
|
|
5. `SDK/StateQueryHandler.cs` (C#) - SDK wrapper
|
|
6. `CSQGetFirstVideoInput()` + `CSQGetNextVideoInput()` - SDK enumeration
|
|
|
|
**What You Get**:
|
|
```json
|
|
[
|
|
{
|
|
"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**:
|
|
1. `routers/monitors.py`
|
|
2. `services/monitor_service.py`
|
|
3. `clients/sdk_bridge_client.py`
|
|
4. `Services/MonitorService.cs` (C#)
|
|
5. `SDK/StateQueryHandler.cs` (C#)
|
|
6. `CSQGetFirstVideoOutput()` + `CSQGetNextVideoOutput()`
|
|
|
|
**What You Get**:
|
|
```json
|
|
[
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"camera_id": 7,
|
|
"monitor_id": 3,
|
|
"mode": 0
|
|
}
|
|
```
|
|
|
|
**Code Path**:
|
|
1. `routers/crossswitch.py`
|
|
2. `services/crossswitch_service.py`
|
|
3. `Services/CrossSwitchService.cs` (C#)
|
|
4. `SDK/ActionDispatcher.cs` (C#)
|
|
5. `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**:
|
|
1. `routers/configuration.py`
|
|
2. `services/configuration_service.py`
|
|
3. `clients/sdk_bridge_client.py`
|
|
4. `Services/ConfigurationService.cs` (C#) - gRPC service
|
|
5. `SDK/GeViSetupClientWrapper.cs` (C#) - Download config
|
|
6. `Services/FolderTreeParser.cs` (C#) - Parse binary .set
|
|
7. Navigate to "GeViGCoreServer" folder
|
|
8. Extract all server nodes
|
|
|
|
**What You Get**:
|
|
```json
|
|
[
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"alias": "New Remote Server",
|
|
"host": "192.168.1.200",
|
|
"user": "admin",
|
|
"password": "secret",
|
|
"enabled": true
|
|
}
|
|
```
|
|
|
|
**What Happens**:
|
|
1. Downloads current TestMKS.set file
|
|
2. Parses binary format into folder tree
|
|
3. Finds GeViGCoreServer folder
|
|
4. Calculates new ID (max existing ID + 1)
|
|
5. Creates new server node with all fields
|
|
6. Writes modified tree back to binary
|
|
7. Uploads to GeViServer
|
|
8. GeViServer saves and reloads config
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
[
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```python
|
|
# 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**:
|
|
1. **Database**: PostgreSQL connection test
|
|
2. **Redis**: Cache connectivity
|
|
3. **SDK Bridge**: gRPC connection test (calls ping)
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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
|
|
|
|
1. Open http://localhost:8000/docs
|
|
2. All endpoints are documented with schemas
|
|
3. Click "Try it out" to test
|
|
|
|
### Using curl
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```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
|
|
|
|
1. **Test each endpoint** with Swagger UI
|
|
2. **Verify data sources** match expectations
|
|
3. **Check logs** for any errors
|
|
4. **Use test scripts** in repository root:
|
|
- `comprehensive_crud_test.py` - Full CRUD test
|
|
- `verify_config_via_grpc.py` - Config verification
|
|
|
|
---
|
|
|
|
**Last Updated**: 2025-12-16
|
|
**Version**: 1.0
|