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>
488 lines
15 KiB
Markdown
488 lines
15 KiB
Markdown
# Action Mapping Implementation Status & Plan
|
|
|
|
**Last Updated**: 2025-12-11
|
|
**Feature**: GeViSoft Action Mapping Configuration API
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
This document tracks the implementation of action mapping configuration endpoints for the Geutebruck API. Action mappings allow GeViServer to trigger output actions automatically when input actions occur (e.g., motion detection triggers camera routing and alarm notifications).
|
|
|
|
---
|
|
|
|
## SDK Documentation References
|
|
|
|
### Primary Documentation (Extracted & Searchable)
|
|
|
|
**Location**: `C:\Gevisoft\Documentation\extracted_html\`
|
|
|
|
**Comprehensive Guide**:
|
|
- `C:\DEV\COPILOT\gevisoft-sdk-reference.md` - Complete SDK reference with action mapping examples
|
|
|
|
**Key Documentation Files**:
|
|
- `GeViSoft_SDK_Documentation\313Action Mapping.htm` - Action mapping concepts and usage
|
|
- `GeViSoft_SDK_Documentation\414StateQueries.htm` - State query patterns (including action mapping queries)
|
|
- `GeViSoft_API_Documentation\class_ge_vi_a_p_i_client.html` - GeViAPIClient class reference
|
|
|
|
### Critical SDK Methods for Action Mapping
|
|
|
|
```cpp
|
|
// Reading Action Mapping Configuration
|
|
CStateQuery* query = new CSQGetActionMappingTable();
|
|
CStateAnswer* answer = m_APIClient->SendStateQuery(query, INFINITE);
|
|
query->DeleteObject();
|
|
|
|
if (answer && answer->m_AnswerKind == sak_ActionMappingTable)
|
|
{
|
|
CSAActionMappingTable* mappings =
|
|
reinterpret_cast<CSAActionMappingTable*>(answer);
|
|
|
|
// Process action mappings...
|
|
|
|
answer->DeleteObject();
|
|
}
|
|
|
|
// Writing Action Mapping Configuration
|
|
CSAActionMappingTable* modifiedMappings = /* your modified mappings */;
|
|
CStateQuery* setQuery = new CSQSetActionMappingTable(modifiedMappings);
|
|
CStateAnswer* answer = m_APIClient->SendStateQuery(setQuery, INFINITE);
|
|
|
|
if (answer && answer->m_AnswerKind == sak_OK)
|
|
{
|
|
// Success!
|
|
}
|
|
setQuery->DeleteObject();
|
|
answer->DeleteObject();
|
|
```
|
|
|
|
---
|
|
|
|
## Current Implementation Status
|
|
|
|
### ✅ Completed (Phase 1 - MVP Workaround)
|
|
|
|
**Files Implemented**:
|
|
1. `src\sdk-bridge\GeViScopeBridge\SDK\ActionMappingHandler.cs`
|
|
- Basic action mapping handler
|
|
- **Current approach**: In-memory storage + alarm queries
|
|
- CRUD operations: Create, Read, Update, Delete
|
|
- Execution tracking (count, last executed)
|
|
|
|
2. `src\sdk-bridge\GeViScopeBridge\Services\ActionMappingServiceImplementation.cs`
|
|
- gRPC service wrapper for ActionMappingHandler
|
|
- Exposes `GetActionMappings()` and `GetActionMapping()` RPCs
|
|
|
|
3. `src\sdk-bridge\GeViScopeBridge\SDK\AlarmQueryService.cs`
|
|
- Queries alarm data from GeViServer
|
|
- Used as workaround to read action mappings
|
|
|
|
4. `src\sdk-bridge\DiagnoseActionMapping\Program.cs`
|
|
- Diagnostic tool for testing action mapping functionality
|
|
- Validates SDK connection and action sending
|
|
|
|
**What Works**:
|
|
- ✅ In-memory action mapping storage
|
|
- ✅ Basic CRUD operations
|
|
- ✅ Execution tracking and statistics
|
|
- ✅ gRPC service exposure
|
|
- ✅ Diagnostic testing tool
|
|
|
|
### ⚠️ Known Limitations (Current Implementation)
|
|
|
|
1. **No Direct GeViServer Integration**:
|
|
- Action mappings stored in application memory only
|
|
- Does NOT read from GeViServer's action mapping table
|
|
- Does NOT write back to GeViServer configuration
|
|
- Lost on restart
|
|
|
|
2. **Alarm Query Workaround**:
|
|
- Uses `AlarmQueryService` to query alarms as a proxy for action mappings
|
|
- Not the correct SDK method for action mapping configuration
|
|
|
|
3. **Missing SDK State Queries**:
|
|
- `CSQGetActionMappingTable()` - NOT implemented
|
|
- `CSQSetActionMappingTable()` - NOT implemented
|
|
|
|
---
|
|
|
|
## Phase 2 - Proper SDK Integration (TO DO)
|
|
|
|
### Required Changes
|
|
|
|
#### 1. Implement State Query Support for Action Mappings
|
|
|
|
**File**: `src\sdk-bridge\GeViScopeBridge\SDK\StateQueryHandler.cs`
|
|
|
|
Add methods:
|
|
```csharp
|
|
/// <summary>
|
|
/// Read action mapping table from GeViServer
|
|
/// </summary>
|
|
public async Task<CSAActionMappingTable> GetActionMappingTableAsync()
|
|
{
|
|
var query = new CSQGetActionMappingTable();
|
|
var answer = await _geviWrapper.SendStateQueryAsync(query);
|
|
|
|
if (answer?.m_AnswerKind == sak_ActionMappingTable)
|
|
{
|
|
return (CSAActionMappingTable)answer;
|
|
}
|
|
|
|
throw new Exception("Failed to retrieve action mapping table");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write action mapping table to GeViServer
|
|
/// </summary>
|
|
public async Task<bool> SetActionMappingTableAsync(CSAActionMappingTable mappingTable)
|
|
{
|
|
var query = new CSQSetActionMappingTable(mappingTable);
|
|
var answer = await _geviWrapper.SendStateQueryAsync(query);
|
|
|
|
return answer?.m_AnswerKind == sak_OK;
|
|
}
|
|
```
|
|
|
|
#### 2. Update ActionMappingHandler.cs
|
|
|
|
**Changes Required**:
|
|
```csharp
|
|
public class ActionMappingHandler
|
|
{
|
|
private readonly StateQueryHandler _stateQueryHandler; // ADD THIS
|
|
|
|
/// <summary>
|
|
/// Enumerate action mappings from LIVE GeViServer database
|
|
/// </summary>
|
|
public async Task<List<ActionMappingConfig>> EnumerateActionMappingsAsync(bool enabledOnly = false)
|
|
{
|
|
// REPLACE alarm query workaround with:
|
|
var mappingTable = await _stateQueryHandler.GetActionMappingTableAsync();
|
|
|
|
// Convert CSAActionMappingTable to List<ActionMappingConfig>
|
|
return ConvertToActionMappingConfigs(mappingTable, enabledOnly);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save action mappings back to GeViServer
|
|
/// </summary>
|
|
public async Task<bool> SaveActionMappingsAsync(List<ActionMappingConfig> mappings)
|
|
{
|
|
// Convert List<ActionMappingConfig> to CSAActionMappingTable
|
|
var mappingTable = ConvertToActionMappingTable(mappings);
|
|
|
|
// Send to GeViServer
|
|
return await _stateQueryHandler.SetActionMappingTableAsync(mappingTable);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3. Add Data Conversion Methods
|
|
|
|
**File**: `src\sdk-bridge\GeViScopeBridge\SDK\ActionMappingHandler.cs`
|
|
|
|
Add conversion methods:
|
|
```csharp
|
|
/// <summary>
|
|
/// Convert SDK action mapping table to internal format
|
|
/// </summary>
|
|
private List<ActionMappingConfig> ConvertToActionMappingConfigs(
|
|
CSAActionMappingTable sdkTable,
|
|
bool enabledOnly)
|
|
{
|
|
var result = new List<ActionMappingConfig>();
|
|
|
|
// Iterate through SDK mapping table entries
|
|
// Each entry has:
|
|
// - Input action definition
|
|
// - List of output actions
|
|
// - Caption/description
|
|
// - Enable/disable state
|
|
|
|
foreach (var entry in sdkTable.Entries)
|
|
{
|
|
var config = new ActionMappingConfig
|
|
{
|
|
Id = entry.Id.ToString(),
|
|
Name = entry.Caption,
|
|
Description = entry.Description ?? "",
|
|
InputAction = entry.InputAction.ToString(),
|
|
OutputActions = entry.OutputActions.Select(a => a.ToString()).ToList(),
|
|
Enabled = entry.Enabled,
|
|
// ... other fields
|
|
};
|
|
|
|
if (!enabledOnly || config.Enabled)
|
|
{
|
|
result.Add(config);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert internal format to SDK action mapping table
|
|
/// </summary>
|
|
private CSAActionMappingTable ConvertToActionMappingTable(List<ActionMappingConfig> configs)
|
|
{
|
|
var sdkTable = new CSAActionMappingTable();
|
|
|
|
foreach (var config in configs)
|
|
{
|
|
var entry = new ActionMappingEntry
|
|
{
|
|
Caption = config.Name,
|
|
Description = config.Description,
|
|
InputAction = ParseAction(config.InputAction),
|
|
OutputActions = config.OutputActions.Select(ParseAction).ToList(),
|
|
Enabled = config.Enabled
|
|
};
|
|
|
|
sdkTable.Entries.Add(entry);
|
|
}
|
|
|
|
return sdkTable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse action string to SDK CAction object
|
|
/// </summary>
|
|
private CAction ParseAction(string actionString)
|
|
{
|
|
// Use CGeViMessage.ReadASCIIMessage to parse action string
|
|
int bytesRead = 0;
|
|
var message = CGeViMessage.ReadASCIIMessage(
|
|
actionString,
|
|
actionString.Length,
|
|
out bytesRead
|
|
);
|
|
|
|
return (CAction)message;
|
|
}
|
|
```
|
|
|
|
#### 4. Update gRPC Service Implementation
|
|
|
|
**File**: `src\sdk-bridge\GeViScopeBridge\Services\ActionMappingServiceImplementation.cs`
|
|
|
|
Add RPC methods:
|
|
```csharp
|
|
/// <summary>
|
|
/// Update action mappings in GeViServer
|
|
/// </summary>
|
|
public override async Task<UpdateActionMappingsResponse> UpdateActionMappings(
|
|
UpdateActionMappingsRequest request,
|
|
ServerCallContext context)
|
|
{
|
|
try
|
|
{
|
|
var configs = request.Mappings.Select(ConvertFromProto).ToList();
|
|
|
|
bool success = await _actionMappingHandler.SaveActionMappingsAsync(configs);
|
|
|
|
return new UpdateActionMappingsResponse
|
|
{
|
|
Success = success,
|
|
Message = success ? "Action mappings updated successfully" : "Failed to update action mappings"
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, "UpdateActionMappings failed");
|
|
throw new RpcException(new Status(StatusCode.Internal, $"Failed to update: {ex.Message}"));
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 5. Update Protobuf Definitions
|
|
|
|
**File**: `src\sdk-bridge\GeViScopeBridge\Protos\actionmapping.proto`
|
|
|
|
Add messages:
|
|
```protobuf
|
|
message UpdateActionMappingsRequest {
|
|
repeated ActionMapping mappings = 1;
|
|
}
|
|
|
|
message UpdateActionMappingsResponse {
|
|
bool success = 1;
|
|
string message = 2;
|
|
int32 updated_count = 3;
|
|
}
|
|
|
|
service ActionMappingService {
|
|
rpc GetActionMappings(GetActionMappingsRequest) returns (GetActionMappingsResponse);
|
|
rpc GetActionMapping(GetActionMappingRequest) returns (ActionMappingResponse);
|
|
rpc UpdateActionMappings(UpdateActionMappingsRequest) returns (UpdateActionMappingsResponse); // NEW
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Task Breakdown
|
|
|
|
### Phase 2 Tasks
|
|
|
|
- [ ] **T001**: Add `CSQGetActionMappingTable` support to StateQueryHandler.cs
|
|
- [ ] **T002**: Add `CSQSetActionMappingTable` support to StateQueryHandler.cs
|
|
- [ ] **T003**: Implement `ConvertToActionMappingConfigs()` conversion method
|
|
- [ ] **T004**: Implement `ConvertToActionMappingTable()` conversion method
|
|
- [ ] **T005**: Implement `ParseAction()` helper for action string parsing
|
|
- [ ] **T006**: Update `EnumerateActionMappingsAsync()` to use state queries
|
|
- [ ] **T007**: Add `SaveActionMappingsAsync()` method to ActionMappingHandler
|
|
- [ ] **T008**: Update protobuf definitions for UpdateActionMappings RPC
|
|
- [ ] **T009**: Implement `UpdateActionMappings` gRPC service method
|
|
- [ ] **T010**: Update DiagnoseActionMapping tool to test new functionality
|
|
- [ ] **T011**: Write unit tests for conversion methods
|
|
- [ ] **T012**: Write integration tests with live GeViServer
|
|
- [ ] **T013**: Update API documentation with new endpoints
|
|
- [ ] **T014**: Remove in-memory storage workaround
|
|
- [ ] **T015**: Remove AlarmQueryService dependency (if no longer needed)
|
|
|
|
### Phase 3 Tasks (Python API Layer)
|
|
|
|
- [ ] **T016**: Create Python gRPC client for action mapping service
|
|
- [ ] **T017**: Create FastAPI endpoint `GET /api/v1/gevisoft/action-mappings`
|
|
- [ ] **T018**: Create FastAPI endpoint `GET /api/v1/gevisoft/action-mappings/{id}`
|
|
- [ ] **T019**: Create FastAPI endpoint `PUT /api/v1/gevisoft/action-mappings`
|
|
- [ ] **T020**: Create FastAPI endpoint `POST /api/v1/gevisoft/action-mappings`
|
|
- [ ] **T021**: Create FastAPI endpoint `DELETE /api/v1/gevisoft/action-mappings/{id}`
|
|
- [ ] **T022**: Add validation for action mapping schema
|
|
- [ ] **T023**: Add audit logging for configuration changes
|
|
- [ ] **T024**: Add caching for action mapping configuration
|
|
- [ ] **T025**: Write API contract tests
|
|
- [ ] **T026**: Update OpenAPI specification
|
|
|
|
---
|
|
|
|
## API Endpoints (Target)
|
|
|
|
### GET /api/v1/gevisoft/action-mappings
|
|
**Description**: List all action mappings from GeViServer
|
|
**Response**:
|
|
```json
|
|
{
|
|
"total_count": 15,
|
|
"enabled_count": 12,
|
|
"disabled_count": 3,
|
|
"mappings": [
|
|
{
|
|
"id": "mapping_1",
|
|
"name": "Motion Detection → Camera Routing",
|
|
"description": "Route camera to monitor 1 when motion detected",
|
|
"input_action": "VMD_Start(101038)",
|
|
"output_actions": [
|
|
"CrossSwitch(101038, 1, 0)"
|
|
],
|
|
"enabled": true,
|
|
"execution_count": 42,
|
|
"last_executed": "2025-12-11T10:30:00Z",
|
|
"created_at": "2025-12-01T08:00:00Z",
|
|
"updated_at": "2025-12-11T10:30:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### PUT /api/v1/gevisoft/action-mappings
|
|
**Description**: Update action mapping configuration on GeViServer
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"mappings": [
|
|
{
|
|
"id": "mapping_1",
|
|
"name": "Motion Detection → Camera Routing",
|
|
"input_action": "VMD_Start(101038)",
|
|
"output_actions": ["CrossSwitch(101038, 1, 0)"],
|
|
"enabled": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Action mappings updated successfully",
|
|
"updated_count": 1
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
- ✅ ActionMappingConfig model validation
|
|
- ✅ Conversion methods (SDK ↔ internal format)
|
|
- ✅ gRPC service method logic
|
|
|
|
### Integration Tests
|
|
- [ ] Connect to GeViServer
|
|
- [ ] Read action mapping table
|
|
- [ ] Modify action mapping table
|
|
- [ ] Write action mapping table back
|
|
- [ ] Verify changes persisted
|
|
|
|
### End-to-End Tests
|
|
- [ ] Full API workflow: GET → PUT → GET (verify changes)
|
|
- [ ] Action mapping execution validation
|
|
- [ ] Error handling and rollback scenarios
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
### SDK Classes (C++/CLI Interop)
|
|
- `CSQGetActionMappingTable` - State query to read action mappings
|
|
- `CSQSetActionMappingTable` - State query to write action mappings
|
|
- `CSAActionMappingTable` - State answer containing action mapping table
|
|
- `CAction` - Base class for action objects
|
|
- `CGeViMessage` - Base class for all messages, provides `ReadASCIIMessage()`
|
|
|
|
### NuGet Packages
|
|
- `GEUTEBRUECK.GeViSoftSDKNET` (GeViSoft SDK wrapper)
|
|
- `Grpc.AspNetCore` (gRPC server)
|
|
- `Serilog` (logging)
|
|
|
|
---
|
|
|
|
## Known Issues & Risks
|
|
|
|
### Issues
|
|
1. **SDK documentation incomplete**: May need to inspect DLL interfaces directly
|
|
2. **Action string parsing**: Complex actions may require custom parsing logic
|
|
3. **Concurrency**: GeViServer may have locking on configuration changes
|
|
|
|
### Risks
|
|
1. **Configuration corruption**: Improper data conversion could corrupt GeViServer config
|
|
- **Mitigation**: Thorough testing, backup/restore functionality
|
|
2. **Performance**: Reading large action mapping tables may be slow
|
|
- **Mitigation**: Caching, incremental updates
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
### SDK Documentation
|
|
- **Location**: `C:\Gevisoft\Documentation\extracted_html\`
|
|
- **Comprehensive Guide**: `C:\DEV\COPILOT\gevisoft-sdk-reference.md`
|
|
- **Action Mapping Guide**: `GeViSoft_SDK_Documentation\313Action Mapping.htm`
|
|
- **State Queries**: `GeViSoft_SDK_Documentation\414StateQueries.htm`
|
|
- **GeViAPIClient**: `GeViSoft_API_Documentation\class_ge_vi_a_p_i_client.html`
|
|
|
|
### Code Files
|
|
- `src\sdk-bridge\GeViScopeBridge\SDK\ActionMappingHandler.cs`
|
|
- `src\sdk-bridge\GeViScopeBridge\SDK\StateQueryHandler.cs`
|
|
- `src\sdk-bridge\GeViScopeBridge\Services\ActionMappingServiceImplementation.cs`
|
|
- `src\sdk-bridge\DiagnoseActionMapping\Program.cs`
|
|
|
|
---
|
|
|
|
**Status**: Phase 1 Complete (MVP workaround) | Phase 2 Pending (proper SDK integration)
|
|
**Next Step**: Implement state query support (T001-T002)
|