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>
270 lines
7.3 KiB
Markdown
270 lines
7.3 KiB
Markdown
# Action Mapping CRUD Operations - Implementation Summary
|
|
|
|
## Overview
|
|
|
|
Successfully implemented **CREATE, READ, UPDATE, and DELETE** operations for GeViSoft action mappings via gRPC API. Mappings created through the API are fully visible and editable in GeViSet.
|
|
|
|
## Critical Discovery: The Secondary Flag
|
|
|
|
**The breakthrough finding:** GeViSet requires the secondary flag (`@@`) to be set to **100** for mappings to be visible in the UI.
|
|
|
|
Without `@@ = 100`, mappings exist in the configuration but are filtered out by GeViSet's display logic.
|
|
|
|
## Complete Mapping Structure (for VideoInput mappings)
|
|
|
|
```
|
|
MappingRules/
|
|
{rule_id}/
|
|
# FILTERS (control which fields are active)
|
|
.SwitchMode = false (bool)
|
|
.VideoInput = true (bool)
|
|
.VideoOutput = false (bool)
|
|
|
|
# CAPTION AND FLAGS
|
|
@ = "Mapping Name" (string)
|
|
@! = 0 (int32) # Primary flag
|
|
@@ = 100 (int32) # Secondary flag - CRITICAL FOR VISIBILITY!
|
|
|
|
# OUTPUT ACTIONS
|
|
Rules/
|
|
0/
|
|
@ = "Action Name"
|
|
@! = 0
|
|
@@ = 0
|
|
GCoreAction = "ActionType" (or GscAction)
|
|
GCoreServer = "" (or GscServer)
|
|
1/
|
|
...
|
|
|
|
# FIELD VALUES (after Rules)
|
|
SwitchMode = 0 (int32)
|
|
VideoInput = 101027 (int32)
|
|
VideoOutput = 0 (int32)
|
|
```
|
|
|
|
## API Operations
|
|
|
|
### 1. CREATE - Create New Action Mapping
|
|
|
|
```python
|
|
import grpc
|
|
from protos import configuration_pb2, configuration_pb2_grpc
|
|
|
|
channel = grpc.insecure_channel('localhost:50051')
|
|
stub = configuration_pb2_grpc.ConfigurationServiceStub(channel)
|
|
|
|
# Define output actions
|
|
output1 = configuration_pb2.ActionDefinition(action="GCoreDataBase")
|
|
output2 = configuration_pb2.ActionDefinition(action="GscMail")
|
|
|
|
# Create mapping
|
|
mapping = configuration_pb2.ActionMappingInput(
|
|
name="My New Mapping",
|
|
video_input=101027, # Camera ID
|
|
output_actions=[output1, output2]
|
|
)
|
|
|
|
request = configuration_pb2.CreateActionMappingRequest(mapping=mapping)
|
|
response = stub.CreateActionMapping(request)
|
|
|
|
print(f"Success: {response.success}")
|
|
print(f"Message: {response.message}")
|
|
```
|
|
|
|
### 2. READ - List All Action Mappings
|
|
|
|
```python
|
|
request = configuration_pb2.ReadActionMappingsRequest()
|
|
response = stub.ReadActionMappings(request)
|
|
|
|
print(f"Total mappings: {response.total_count}")
|
|
for mapping in response.mappings:
|
|
print(f" - {mapping.name}")
|
|
print(f" Input actions: {len(mapping.input_actions)}")
|
|
print(f" Output actions: {len(mapping.output_actions)}")
|
|
```
|
|
|
|
### 3. UPDATE - Modify Existing Mapping
|
|
|
|
```python
|
|
# Update mapping ID 66 (1-based index)
|
|
updated_output = configuration_pb2.ActionDefinition(action="UpdatedAction")
|
|
|
|
update_mapping = configuration_pb2.ActionMappingInput(
|
|
name="Updated Name",
|
|
video_input=101028, # Changed camera
|
|
output_actions=[updated_output]
|
|
)
|
|
|
|
request = configuration_pb2.UpdateActionMappingRequest(
|
|
mapping_id=66,
|
|
mapping=update_mapping
|
|
)
|
|
|
|
response = stub.UpdateActionMapping(request)
|
|
print(f"Success: {response.success}")
|
|
```
|
|
|
|
### 4. DELETE - Remove Action Mapping
|
|
|
|
```python
|
|
request = configuration_pb2.DeleteActionMappingRequest(mapping_id=66)
|
|
response = stub.DeleteActionMapping(request)
|
|
|
|
print(f"Success: {response.success}")
|
|
print(f"Message: {response.message}")
|
|
```
|
|
|
|
## Key Implementation Details
|
|
|
|
### Files Modified
|
|
|
|
1. **ActionMappingManager.cs** (`C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\Services\`)
|
|
- Added complete filter/field structure
|
|
- Set secondary flag to 100
|
|
- Made `CreateOutputFolder` public for reuse in UPDATE
|
|
|
|
2. **ConfigurationServiceImplementation.cs**
|
|
- Implemented CREATE using FolderTreeParser/Writer
|
|
- Implemented UPDATE to modify existing mappings in folder tree
|
|
- Implemented DELETE to remove mappings from folder tree
|
|
|
|
3. **configuration.proto**
|
|
- Added `video_input` field to ActionMappingInput
|
|
|
|
### Folder Tree Approach
|
|
|
|
All operations use the **FolderTreeParser** and **FolderTreeWriter** classes to:
|
|
1. Parse binary .set file into hierarchical folder structure
|
|
2. Navigate to MappingRules folder
|
|
3. Modify the folder tree (add/update/delete)
|
|
4. Serialize back to binary
|
|
5. Write to GeViServer
|
|
|
|
This approach maintains the complete configuration structure and ensures proper binary serialization.
|
|
|
|
## Testing
|
|
|
|
### Run Comprehensive CRUD Test
|
|
|
|
```bash
|
|
# 1. Disconnect from GeViSet
|
|
# 2. Start SDK bridge:
|
|
cd geutebruck-api/src/sdk-bridge/GeViScopeBridge
|
|
dotnet run
|
|
|
|
# 3. In another terminal:
|
|
python test_crud_operations.py
|
|
```
|
|
|
|
The test will:
|
|
- CREATE a new mapping
|
|
- READ and verify it exists
|
|
- UPDATE the mapping (change name and VideoInput)
|
|
- READ and verify the update
|
|
- DELETE the mapping
|
|
- READ and verify deletion
|
|
|
|
### Verify in GeViSet
|
|
|
|
After CREATE/UPDATE operations:
|
|
1. Reconnect to GeViSet
|
|
2. Navigate to action mappings
|
|
3. Verify the mapping is visible and editable
|
|
|
|
## Connection Management
|
|
|
|
**IMPORTANT:** GeViSoft only allows ONE connection at a time.
|
|
|
|
- GeViSet connected = SDK bridge cannot connect
|
|
- SDK bridge connected = GeViSet cannot connect
|
|
|
|
Always disconnect from GeViSet before running SDK bridge operations.
|
|
|
|
## GeViSet Display Requirements
|
|
|
|
For a mapping to be visible in GeViSet:
|
|
|
|
✅ **Required:**
|
|
- Secondary flag (`@@`) = 100
|
|
- Caption (`@`) with non-empty name
|
|
- At least one filter enabled (`.VideoInput = true`)
|
|
- Corresponding field value (`VideoInput` with camera ID)
|
|
|
|
❌ **Without these:**
|
|
- Mapping exists in configuration
|
|
- API can read it
|
|
- But GeViSet filters it out (invisible in UI)
|
|
|
|
## Performance Notes
|
|
|
|
- CREATE: Adds ~200-300 bytes to configuration
|
|
- UPDATE: Size change depends on what's modified
|
|
- DELETE: Reduces configuration size
|
|
- All operations write full configuration (~280KB)
|
|
|
|
## Bulk Operations
|
|
|
|
For bulk creation (thousands of mappings):
|
|
|
|
```python
|
|
# Read configuration once
|
|
response = stub.ReadActionMappings(configuration_pb2.ReadActionMappingsRequest())
|
|
initial_count = len(response.mappings)
|
|
|
|
# Create multiple mappings
|
|
for i in range(1000):
|
|
mapping = configuration_pb2.ActionMappingInput(
|
|
name=f"Bulk Mapping {i}",
|
|
video_input=101000 + i,
|
|
output_actions=[output1, output2]
|
|
)
|
|
|
|
request = configuration_pb2.CreateActionMappingRequest(mapping=mapping)
|
|
response = stub.CreateActionMapping(request)
|
|
|
|
if i % 100 == 0:
|
|
print(f"Created {i} mappings...")
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Mapping not visible in GeViSet
|
|
|
|
Check:
|
|
1. Secondary flag is 100
|
|
2. `.VideoInput` filter is set to true
|
|
3. `VideoInput` field has valid camera ID
|
|
4. Caption (`@`) is non-empty
|
|
|
|
### Connection refused
|
|
|
|
- Ensure GeViSet is disconnected
|
|
- Check GeViServer is running
|
|
- Verify port 50051 is available
|
|
|
|
### Write operation succeeds but changes not persisted
|
|
|
|
- This is normal - GeViSoft may cache configuration
|
|
- Restart GeViSet to force reload
|
|
- Or use GeViSet's refresh functionality
|
|
|
|
## Next Steps
|
|
|
|
Potential enhancements:
|
|
- Add input action support (for trigger conditions)
|
|
- Support for other filter/field types (beyond VideoInput)
|
|
- Batch operations endpoint
|
|
- Transaction support (create multiple mappings atomically)
|
|
- Validation of camera IDs and action names
|
|
|
|
## Summary
|
|
|
|
All CRUD operations are now fully functional:
|
|
- ✅ **CREATE** - Add new mappings visible in GeViSet
|
|
- ✅ **READ** - List all mappings with full details
|
|
- ✅ **UPDATE** - Modify existing mappings
|
|
- ✅ **DELETE** - Remove mappings
|
|
|
|
The key breakthrough was discovering that `@@ = 100` (secondary flag) is required for GeViSet visibility.
|