# 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.