Add component-level documentation for all 14 server subsystems
Provides technical documentation covering OPC UA server, address space, Galaxy repository, MXAccess bridge, data types, read/write, subscriptions, alarms, historian, incremental sync, configuration, dashboard, service hosting, and CLI tool. Updates README with component documentation table. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
88
docs/GalaxyRepository.md
Normal file
88
docs/GalaxyRepository.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Galaxy Repository
|
||||
|
||||
`GalaxyRepositoryService` reads the Galaxy object hierarchy and attribute metadata from the System Platform Galaxy Repository SQL Server database. This data drives the construction of the OPC UA address space.
|
||||
|
||||
## Connection Configuration
|
||||
|
||||
`GalaxyRepositoryConfiguration` controls database access:
|
||||
|
||||
| Property | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `ConnectionString` | `Server=localhost;Database=ZB;Integrated Security=true;` | SQL Server connection using Windows Authentication |
|
||||
| `ChangeDetectionIntervalSeconds` | `30` | Polling frequency for deploy change detection |
|
||||
| `CommandTimeoutSeconds` | `30` | SQL command timeout for all queries |
|
||||
| `ExtendedAttributes` | `false` | When true, loads primitive-level attributes in addition to dynamic attributes |
|
||||
|
||||
The connection uses Windows Authentication because the Galaxy Repository database is local to the System Platform node and secured through domain credentials.
|
||||
|
||||
## SQL Queries
|
||||
|
||||
All queries are embedded as `const string` fields in `GalaxyRepositoryService`. No dynamic SQL is used.
|
||||
|
||||
### Hierarchy query
|
||||
|
||||
Returns deployed Galaxy objects with their parent relationships and browse names:
|
||||
|
||||
- Joins `gobject` to `template_definition` to filter by relevant `category_id` values (1, 3, 4, 10, 11, 13, 17, 24, 26)
|
||||
- Uses `contained_name` as the browse name, falling back to `tag_name` when `contained_name` is null or empty
|
||||
- Resolves the parent using `contained_by_gobject_id` when non-zero, otherwise falls back to `area_gobject_id`
|
||||
- Marks objects with `category_id = 13` as areas
|
||||
- Filters to `is_template = 0` (instances only, not templates)
|
||||
- Filters to `deployed_package_id <> 0` (deployed objects only)
|
||||
|
||||
### Attributes query (standard)
|
||||
|
||||
Returns user-defined dynamic attributes for deployed objects:
|
||||
|
||||
- Uses a recursive CTE (`deployed_package_chain`) to walk the package inheritance chain from `deployed_package_id` through `derived_from_package_id`, limited to 10 levels
|
||||
- Joins `dynamic_attribute` on each package in the chain to collect inherited attributes
|
||||
- Uses `ROW_NUMBER() OVER (PARTITION BY gobject_id, attribute_name ORDER BY depth)` to pick the most-derived definition when an attribute is overridden at multiple levels
|
||||
- Builds `full_tag_reference` as `tag_name.attribute_name` with `[]` appended for arrays
|
||||
- Extracts `array_dimension` from the binary `mx_value` column (bytes 13-16, little-endian int32)
|
||||
- Detects historized attributes by checking for a `HistoryExtension` primitive instance
|
||||
- Detects alarm attributes by checking for an `AlarmExtension` primitive instance
|
||||
- Excludes internal attributes (names starting with `_`) and `.Description` suffixes
|
||||
- Filters by `mx_attribute_category` to include only user-relevant categories
|
||||
|
||||
### Attributes query (extended)
|
||||
|
||||
When `ExtendedAttributes = true`, a more comprehensive query runs that unions two sources:
|
||||
|
||||
1. **Primitive attributes** -- Joins through `primitive_instance` and `attribute_definition` to include system-level attributes from primitive components. Each attribute carries its `primitive_name` so the address space can group them under their parent variable.
|
||||
2. **Dynamic attributes** -- The same CTE-based query as the standard path, with an empty `primitive_name`.
|
||||
|
||||
The `full_tag_reference` for primitive attributes follows the pattern `tag_name.primitive_name.attribute_name` (e.g., `TestMachine_001.AlarmAttr.InAlarm`).
|
||||
|
||||
### Change detection query
|
||||
|
||||
A single-column query: `SELECT time_of_last_deploy FROM galaxy`. The `galaxy` table contains one row with the timestamp of the most recent deployment.
|
||||
|
||||
## Why deployed_package_id Instead of checked_in_package_id
|
||||
|
||||
The Galaxy maintains two package references for each object:
|
||||
|
||||
- `checked_in_package_id` -- The latest saved version, which may include undeployed configuration changes
|
||||
- `deployed_package_id` -- The version currently running on the target platform
|
||||
|
||||
The queries filter on `deployed_package_id <> 0` because the OPC UA server must mirror what is actually running in the Galaxy runtime. Using `checked_in_package_id` would expose attributes and objects that exist in the IDE but have not been deployed, causing mismatches between the OPC UA address space and the MXAccess runtime.
|
||||
|
||||
## Change Detection Polling
|
||||
|
||||
`ChangeDetectionService` runs a background polling loop that calls `GetLastDeployTimeAsync` at the configured interval. It compares the returned timestamp against the last known value:
|
||||
|
||||
- On the first poll (no previous state), the timestamp is recorded and `OnGalaxyChanged` fires unconditionally
|
||||
- On subsequent polls, `OnGalaxyChanged` fires only when `time_of_last_deploy` differs from the cached value
|
||||
|
||||
When the event fires, the host service queries fresh hierarchy and attribute data from the repository and calls `LmxNodeManager.RebuildAddressSpace` (which delegates to incremental `SyncAddressSpace`).
|
||||
|
||||
The polling approach is used because the Galaxy Repository database does not provide change notifications. The `galaxy.time_of_last_deploy` column updates only on completed deployments, so the polling interval controls how quickly the OPC UA address space reflects Galaxy changes.
|
||||
|
||||
## TestConnection
|
||||
|
||||
`TestConnectionAsync` runs `SELECT 1` against the configured database. This is used at service startup to verify connectivity before attempting the full hierarchy query.
|
||||
|
||||
## Key source files
|
||||
|
||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/GalaxyRepositoryService.cs` -- SQL queries and data access
|
||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/ChangeDetectionService.cs` -- Deploy timestamp polling loop
|
||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Configuration/GalaxyRepositoryConfiguration.cs` -- Connection and polling settings
|
||||
Reference in New Issue
Block a user