Phase 0 — mechanical rename ZB.MOM.WW.LmxOpcUa.* → ZB.MOM.WW.OtOpcUa.*
Renames all 11 projects (5 src + 6 tests), the .slnx solution file, all source-file namespaces, all axaml namespace references, and all v1 documentation references in CLAUDE.md and docs/*.md (excluding docs/v2/ which is already in OtOpcUa form). Also updates the TopShelf service registration name from "LmxOpcUa" to "OtOpcUa" per Phase 0 Task 0.6.
Preserves runtime identifiers per Phase 0 Out-of-Scope rules to avoid breaking v1/v2 client trust during coexistence: OPC UA `ApplicationUri` defaults (`urn:{GalaxyName}:LmxOpcUa`), server `EndpointPath` (`/LmxOpcUa`), `ServerName` default (feeds cert subject CN), `MxAccessConfiguration.ClientName` default (defensive — stays "LmxOpcUa" for MxAccess audit-trail consistency), client OPC UA identifiers (`ApplicationName = "LmxOpcUaClient"`, `ApplicationUri = "urn:localhost:LmxOpcUaClient"`, cert directory `%LocalAppData%\LmxOpcUaClient\pki\`), and the `LmxOpcUaServer` class name (class rename out of Phase 0 scope per Task 0.5 sed pattern; happens in Phase 1 alongside `LmxNodeManager → GenericDriverNodeManager` Core extraction). 23 LmxOpcUa references retained, all enumerated and justified in `docs/v2/implementation/exit-gate-phase-0.md`.
Build clean: 0 errors, 30 warnings (lower than baseline 167). Tests at strict improvement over baseline: 821 passing / 1 failing vs baseline 820 / 2 (one flaky pre-existing failure passed this run; the other still fails — both pre-existing and unrelated to the rename). `Client.UI.Tests`, `Historian.Aveva.Tests`, `Client.Shared.Tests`, `IntegrationTests` all match baseline exactly. Exit gate compliance results recorded in `docs/v2/implementation/exit-gate-phase-0.md` with all 7 checks PASS or DEFERRED-to-PR-review (#7 service install verification needs Windows service permissions on the reviewer's box).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
20
CLAUDE.md
20
CLAUDE.md
@@ -63,11 +63,11 @@ Key tables: `gobject` (hierarchy/deployment), `template_definition` (object cate
|
|||||||
## Build Commands
|
## Build Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet restore ZB.MOM.WW.LmxOpcUa.slnx
|
dotnet restore ZB.MOM.WW.OtOpcUa.slnx
|
||||||
dotnet build ZB.MOM.WW.LmxOpcUa.slnx
|
dotnet build ZB.MOM.WW.OtOpcUa.slnx
|
||||||
dotnet test ZB.MOM.WW.LmxOpcUa.slnx # all tests
|
dotnet test ZB.MOM.WW.OtOpcUa.slnx # all tests
|
||||||
dotnet test tests/ZB.MOM.WW.LmxOpcUa.Tests # unit tests only
|
dotnet test tests/ZB.MOM.WW.OtOpcUa.Tests # unit tests only
|
||||||
dotnet test tests/ZB.MOM.WW.LmxOpcUa.IntegrationTests # integration tests only
|
dotnet test tests/ZB.MOM.WW.OtOpcUa.IntegrationTests # integration tests only
|
||||||
dotnet test --filter "FullyQualifiedName~MyTestClass.MyMethod" # single test
|
dotnet test --filter "FullyQualifiedName~MyTestClass.MyMethod" # single test
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -102,11 +102,11 @@ Use the DeepWiki MCP (`mcp__deepwiki`) to query documentation for the OPC UA .NE
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Use the Client CLI at `src/ZB.MOM.WW.LmxOpcUa.Client.CLI/` for manual testing against the running OPC UA server. Supports connect, read, write, browse, subscribe, historyread, alarms, and redundancy commands. See `docs/Client.CLI.md` for full documentation.
|
Use the Client CLI at `src/ZB.MOM.WW.OtOpcUa.Client.CLI/` for manual testing against the running OPC UA server. Supports connect, read, write, browse, subscribe, historyread, alarms, and redundancy commands. See `docs/Client.CLI.md` for full documentation.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- browse -u opc.tcp://localhost:4840 -r -d 3
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- browse -u opc.tcp://localhost:4840 -r -d 3
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- read -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode"
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- read -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode"
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- subscribe -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode" -i 500
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- subscribe -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode" -i 500
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<Solution>
|
|
||||||
<Folder Name="/src/">
|
|
||||||
<Project Path="src/ZB.MOM.WW.LmxOpcUa.Host/ZB.MOM.WW.LmxOpcUa.Host.csproj"/>
|
|
||||||
<Project Path="src/ZB.MOM.WW.LmxOpcUa.Historian.Aveva/ZB.MOM.WW.LmxOpcUa.Historian.Aveva.csproj"/>
|
|
||||||
<Project Path="src/ZB.MOM.WW.LmxOpcUa.Client.Shared/ZB.MOM.WW.LmxOpcUa.Client.Shared.csproj"/>
|
|
||||||
<Project Path="src/ZB.MOM.WW.LmxOpcUa.Client.CLI/ZB.MOM.WW.LmxOpcUa.Client.CLI.csproj"/>
|
|
||||||
<Project Path="src/ZB.MOM.WW.LmxOpcUa.Client.UI/ZB.MOM.WW.LmxOpcUa.Client.UI.csproj"/>
|
|
||||||
</Folder>
|
|
||||||
<Folder Name="/tests/">
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.Tests/ZB.MOM.WW.LmxOpcUa.Tests.csproj"/>
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.Historian.Aveva.Tests/ZB.MOM.WW.LmxOpcUa.Historian.Aveva.Tests.csproj"/>
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.IntegrationTests/ZB.MOM.WW.LmxOpcUa.IntegrationTests.csproj"/>
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.Client.Shared.Tests/ZB.MOM.WW.LmxOpcUa.Client.Shared.Tests.csproj"/>
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.Client.CLI.Tests/ZB.MOM.WW.LmxOpcUa.Client.CLI.Tests.csproj"/>
|
|
||||||
<Project Path="tests/ZB.MOM.WW.LmxOpcUa.Client.UI.Tests/ZB.MOM.WW.LmxOpcUa.Client.UI.Tests.csproj"/>
|
|
||||||
</Folder>
|
|
||||||
</Solution>
|
|
||||||
17
ZB.MOM.WW.OtOpcUa.slnx
Normal file
17
ZB.MOM.WW.OtOpcUa.slnx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<Solution>
|
||||||
|
<Folder Name="/src/">
|
||||||
|
<Project Path="src/ZB.MOM.WW.OtOpcUa.Host/ZB.MOM.WW.OtOpcUa.Host.csproj"/>
|
||||||
|
<Project Path="src/ZB.MOM.WW.OtOpcUa.Historian.Aveva/ZB.MOM.WW.OtOpcUa.Historian.Aveva.csproj"/>
|
||||||
|
<Project Path="src/ZB.MOM.WW.OtOpcUa.Client.Shared/ZB.MOM.WW.OtOpcUa.Client.Shared.csproj"/>
|
||||||
|
<Project Path="src/ZB.MOM.WW.OtOpcUa.Client.CLI/ZB.MOM.WW.OtOpcUa.Client.CLI.csproj"/>
|
||||||
|
<Project Path="src/ZB.MOM.WW.OtOpcUa.Client.UI/ZB.MOM.WW.OtOpcUa.Client.UI.csproj"/>
|
||||||
|
</Folder>
|
||||||
|
<Folder Name="/tests/">
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.Tests/ZB.MOM.WW.OtOpcUa.Tests.csproj"/>
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.Historian.Aveva.Tests/ZB.MOM.WW.OtOpcUa.Historian.Aveva.Tests.csproj"/>
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.IntegrationTests/ZB.MOM.WW.OtOpcUa.IntegrationTests.csproj"/>
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests.csproj"/>
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests.csproj"/>
|
||||||
|
<Project Path="tests/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/ZB.MOM.WW.OtOpcUa.Client.UI.Tests.csproj"/>
|
||||||
|
</Folder>
|
||||||
|
</Solution>
|
||||||
@@ -78,5 +78,5 @@ If no previous state is cached (first build), the full `BuildAddressSpace` path
|
|||||||
|
|
||||||
## Key source files
|
## Key source files
|
||||||
|
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/OpcUa/LmxNodeManager.cs` -- Node manager with `BuildAddressSpace`, `SyncAddressSpace`, and `TopologicalSort`
|
- `src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/LmxNodeManager.cs` -- Node manager with `BuildAddressSpace`, `SyncAddressSpace`, and `TopologicalSort`
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/OpcUa/AddressSpaceBuilder.cs` -- Testable in-memory model builder
|
- `src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/AddressSpaceBuilder.cs` -- Testable in-memory model builder
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`ZB.MOM.WW.LmxOpcUa.Client.CLI` is a cross-platform command-line client for the LmxOpcUa OPC UA server. It targets .NET 10 and uses the shared `IOpcUaClientService` from `Client.Shared` for all OPC UA operations. Commands are routed and parsed by [CliFx](https://github.com/Tyrrrz/CliFx).
|
`ZB.MOM.WW.OtOpcUa.Client.CLI` is a cross-platform command-line client for the LmxOpcUa OPC UA server. It targets .NET 10 and uses the shared `IOpcUaClientService` from `Client.Shared` for all OPC UA operations. Commands are routed and parsed by [CliFx](https://github.com/Tyrrrz/CliFx).
|
||||||
|
|
||||||
The CLI is the primary tool for operators and developers to test and interact with the server from a terminal. It supports all core operations: connectivity testing, browsing, reading, writing, subscriptions, alarm monitoring, history reads, and redundancy queries.
|
The CLI is the primary tool for operators and developers to test and interact with the server from a terminal. It supports all core operations: connectivity testing, browsing, reading, writing, subscriptions, alarm monitoring, history reads, and redundancy queries.
|
||||||
|
|
||||||
## Build and Run
|
## Build and Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd src/ZB.MOM.WW.LmxOpcUa.Client.CLI
|
cd src/ZB.MOM.WW.OtOpcUa.Client.CLI
|
||||||
dotnet build
|
dotnet build
|
||||||
dotnet run -- <command> [options]
|
dotnet run -- <command> [options]
|
||||||
```
|
```
|
||||||
@@ -240,5 +240,5 @@ Application URI: urn:localhost:LmxOpcUa:instance1
|
|||||||
The Client CLI has 52 unit tests covering option parsing, service invocation, output formatting, and cleanup behavior:
|
The Client CLI has 52 unit tests covering option parsing, service invocation, output formatting, and cleanup behavior:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet test tests/ZB.MOM.WW.LmxOpcUa.Client.CLI.Tests
|
dotnet test tests/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`ZB.MOM.WW.LmxOpcUa.Client.UI` is a cross-platform Avalonia desktop application for connecting to and interacting with the LmxOpcUa OPC UA server. It targets .NET 10 and uses the shared `IOpcUaClientService` from `Client.Shared` for all OPC UA operations.
|
`ZB.MOM.WW.OtOpcUa.Client.UI` is a cross-platform Avalonia desktop application for connecting to and interacting with the LmxOpcUa OPC UA server. It targets .NET 10 and uses the shared `IOpcUaClientService` from `Client.Shared` for all OPC UA operations.
|
||||||
|
|
||||||
The UI provides a single-window interface for browsing the address space, reading and writing values, monitoring live subscriptions, managing alarms, and querying historical data.
|
The UI provides a single-window interface for browsing the address space, reading and writing values, monitoring live subscriptions, managing alarms, and querying historical data.
|
||||||
|
|
||||||
## Build and Run
|
## Build and Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd src/ZB.MOM.WW.LmxOpcUa.Client.UI
|
cd src/ZB.MOM.WW.OtOpcUa.Client.UI
|
||||||
dotnet build
|
dotnet build
|
||||||
dotnet run
|
dotnet run
|
||||||
```
|
```
|
||||||
@@ -254,7 +254,7 @@ All service event handlers (data changes, alarm events, connection state changes
|
|||||||
The UI has 102 unit tests covering ViewModel logic and headless rendering:
|
The UI has 102 unit tests covering ViewModel logic and headless rendering:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet test tests/ZB.MOM.WW.LmxOpcUa.Client.UI.Tests
|
dotnet test tests/ZB.MOM.WW.OtOpcUa.Client.UI.Tests
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests use:
|
Tests use:
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ Three boolean properties act as feature flags that control optional subsystems:
|
|||||||
|
|
||||||
- **`OpcUa.AlarmTrackingEnabled`** -- When `true`, the node manager creates `AlarmConditionState` nodes for alarm attributes and monitors `InAlarm` transitions. Disabled by default because alarm tracking adds per-attribute overhead.
|
- **`OpcUa.AlarmTrackingEnabled`** -- When `true`, the node manager creates `AlarmConditionState` nodes for alarm attributes and monitors `InAlarm` transitions. Disabled by default because alarm tracking adds per-attribute overhead.
|
||||||
- **`OpcUa.AlarmFilter.ObjectFilters`** -- List of wildcard template-name patterns that scope alarm tracking to matching objects and their descendants. An empty list preserves the current unfiltered behavior; a non-empty list includes an object only when any name in its template derivation chain matches any pattern, then propagates the inclusion to every descendant in the containment hierarchy. `*` is the only wildcard, matching is case-insensitive, and the Galaxy `$` prefix on template names is normalized so operators can write `TestMachine*` instead of `$TestMachine*`. Each list entry may itself contain comma-separated patterns (`"TestMachine*, Pump_*"`) for convenience. When the list is non-empty but `AlarmTrackingEnabled` is `false`, the validator emits a warning because the filter has no effect. See [Alarm Tracking](AlarmTracking.md#template-based-alarm-object-filter) for the full matching algorithm and telemetry.
|
- **`OpcUa.AlarmFilter.ObjectFilters`** -- List of wildcard template-name patterns that scope alarm tracking to matching objects and their descendants. An empty list preserves the current unfiltered behavior; a non-empty list includes an object only when any name in its template derivation chain matches any pattern, then propagates the inclusion to every descendant in the containment hierarchy. `*` is the only wildcard, matching is case-insensitive, and the Galaxy `$` prefix on template names is normalized so operators can write `TestMachine*` instead of `$TestMachine*`. Each list entry may itself contain comma-separated patterns (`"TestMachine*, Pump_*"`) for convenience. When the list is non-empty but `AlarmTrackingEnabled` is `false`, the validator emits a warning because the filter has no effect. See [Alarm Tracking](AlarmTracking.md#template-based-alarm-object-filter) for the full matching algorithm and telemetry.
|
||||||
- **`Historian.Enabled`** -- When `true`, the service calls `HistorianPluginLoader.TryLoad(config)` to load the `ZB.MOM.WW.LmxOpcUa.Historian.Aveva` plugin from the `Historian/` subfolder next to the host exe and registers the resulting `IHistorianDataSource` with the OPC UA server host. Disabled by default because not all deployments have a Historian instance -- when disabled the plugin is not probed and the Wonderware SDK DLLs are not required on the host. If the flag is `true` but the plugin or its SDK dependencies cannot be loaded, the server still starts and every history read returns `BadHistoryOperationUnsupported` with a warning in the log.
|
- **`Historian.Enabled`** -- When `true`, the service calls `HistorianPluginLoader.TryLoad(config)` to load the `ZB.MOM.WW.OtOpcUa.Historian.Aveva` plugin from the `Historian/` subfolder next to the host exe and registers the resulting `IHistorianDataSource` with the OPC UA server host. Disabled by default because not all deployments have a Historian instance -- when disabled the plugin is not probed and the Wonderware SDK DLLs are not required on the host. If the flag is `true` but the plugin or its SDK dependencies cannot be loaded, the server still starts and every history read returns `BadHistoryOperationUnsupported` with a warning in the log.
|
||||||
- **`GalaxyRepository.ExtendedAttributes`** -- When `true`, the repository loads additional Galaxy attribute metadata beyond the core set needed for the address space. Disabled by default to minimize startup query time.
|
- **`GalaxyRepository.ExtendedAttributes`** -- When `true`, the repository loads additional Galaxy attribute metadata beyond the core set needed for the address space. Disabled by default to minimize startup query time.
|
||||||
- **`GalaxyRepository.Scope`** -- When set to `LocalPlatform`, the repository filters the hierarchy and attributes to only include objects hosted by the platform whose `node_name` matches this machine (or the explicit `PlatformName` override). Ancestor areas are retained to keep the browse tree connected. Default is `Galaxy` (load everything). See [Galaxy Repository — Platform Scope Filter](GalaxyRepository.md#platform-scope-filter).
|
- **`GalaxyRepository.Scope`** -- When set to `LocalPlatform`, the repository filters the hierarchy and attributes to only include objects hosted by the platform whose `node_name` matches this machine (or the explicit `PlatformName` override). Ancestor areas are retained to keep the browse tree connected. Default is `Galaxy` (load everything). See [Galaxy Repository — Platform Scope Filter](GalaxyRepository.md#platform-scope-filter).
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,6 @@ For historized attributes, `AccessLevels.HistoryRead` is added to the access lev
|
|||||||
|
|
||||||
## Key source files
|
## Key source files
|
||||||
|
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/MxDataTypeMapper.cs` -- Type and CLR mapping
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/MxDataTypeMapper.cs` -- Type and CLR mapping
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/SecurityClassificationMapper.cs` -- Write access mapping
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/SecurityClassificationMapper.cs` -- Write access mapping
|
||||||
- `gr/data_type_mapping.md` -- Reference documentation for the full mapping table
|
- `gr/data_type_mapping.md` -- Reference documentation for the full mapping table
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ The polling approach is used because the Galaxy Repository database does not pro
|
|||||||
|
|
||||||
## Key source files
|
## Key source files
|
||||||
|
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/GalaxyRepositoryService.cs` -- SQL queries and data access
|
- `src/ZB.MOM.WW.OtOpcUa.Host/GalaxyRepository/GalaxyRepositoryService.cs` -- SQL queries and data access
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/PlatformScopeFilter.cs` -- Platform-based hierarchy and attribute filtering
|
- `src/ZB.MOM.WW.OtOpcUa.Host/GalaxyRepository/PlatformScopeFilter.cs` -- Platform-based hierarchy and attribute filtering
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/ChangeDetectionService.cs` -- Deploy timestamp polling loop
|
- `src/ZB.MOM.WW.OtOpcUa.Host/GalaxyRepository/ChangeDetectionService.cs` -- Deploy timestamp polling loop
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Configuration/GalaxyRepositoryConfiguration.cs` -- Connection, polling, and scope settings
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Configuration/GalaxyRepositoryConfiguration.cs` -- Connection, polling, and scope settings
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/PlatformInfo.cs` -- Platform-to-hostname DTO
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/PlatformInfo.cs` -- Platform-to-hostname DTO
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
# Historical Data Access
|
# Historical Data Access
|
||||||
|
|
||||||
`LmxNodeManager` exposes OPC UA historical data access (HDA) through an abstract `IHistorianDataSource` interface (`Historian/IHistorianDataSource.cs`). The Wonderware Historian implementation lives in a separate assembly, `ZB.MOM.WW.LmxOpcUa.Historian.Aveva`, which is loaded at runtime only when `Historian.Enabled=true`. This keeps the `aahClientManaged` SDK out of the core Host so deployments that do not need history do not need the SDK installed.
|
`LmxNodeManager` exposes OPC UA historical data access (HDA) through an abstract `IHistorianDataSource` interface (`Historian/IHistorianDataSource.cs`). The Wonderware Historian implementation lives in a separate assembly, `ZB.MOM.WW.OtOpcUa.Historian.Aveva`, which is loaded at runtime only when `Historian.Enabled=true`. This keeps the `aahClientManaged` SDK out of the core Host so deployments that do not need history do not need the SDK installed.
|
||||||
|
|
||||||
## Plugin Architecture
|
## Plugin Architecture
|
||||||
|
|
||||||
The historian surface is split across two assemblies:
|
The historian surface is split across two assemblies:
|
||||||
|
|
||||||
- **`ZB.MOM.WW.LmxOpcUa.Host`** (core) owns only OPC UA / BCL types:
|
- **`ZB.MOM.WW.OtOpcUa.Host`** (core) owns only OPC UA / BCL types:
|
||||||
- `IHistorianDataSource` -- the interface `LmxNodeManager` depends on
|
- `IHistorianDataSource` -- the interface `LmxNodeManager` depends on
|
||||||
- `HistorianEventDto` -- SDK-free representation of a historian event record
|
- `HistorianEventDto` -- SDK-free representation of a historian event record
|
||||||
- `HistorianAggregateMap` -- maps OPC UA aggregate NodeIds to AnalogSummary column names
|
- `HistorianAggregateMap` -- maps OPC UA aggregate NodeIds to AnalogSummary column names
|
||||||
- `HistorianPluginLoader` -- loads the plugin via `Assembly.LoadFrom` at startup
|
- `HistorianPluginLoader` -- loads the plugin via `Assembly.LoadFrom` at startup
|
||||||
- `HistoryContinuationPointManager` -- paginates HistoryRead results
|
- `HistoryContinuationPointManager` -- paginates HistoryRead results
|
||||||
- **`ZB.MOM.WW.LmxOpcUa.Historian.Aveva`** (plugin) owns everything SDK-bound:
|
- **`ZB.MOM.WW.OtOpcUa.Historian.Aveva`** (plugin) owns everything SDK-bound:
|
||||||
- `HistorianDataSource` -- implements `IHistorianDataSource`, wraps `aahClientManaged`
|
- `HistorianDataSource` -- implements `IHistorianDataSource`, wraps `aahClientManaged`
|
||||||
- `IHistorianConnectionFactory` / `SdkHistorianConnectionFactory` -- opens and polls `ArchestrA.HistorianAccess` connections
|
- `IHistorianConnectionFactory` / `SdkHistorianConnectionFactory` -- opens and polls `ArchestrA.HistorianAccess` connections
|
||||||
- `AvevaHistorianPluginEntry.Create(HistorianConfiguration)` -- the static factory invoked by the loader
|
- `AvevaHistorianPluginEntry.Create(HistorianConfiguration)` -- the static factory invoked by the loader
|
||||||
|
|
||||||
The plugin assembly and its SDK dependencies (`aahClientManaged.dll`, `aahClient.dll`, `aahClientCommon.dll`, `Historian.CBE.dll`, `Historian.DPAPI.dll`, `ArchestrA.CloudHistorian.Contract.dll`) deploy to a `Historian/` subfolder next to `ZB.MOM.WW.LmxOpcUa.Host.exe`. See [Service Hosting](ServiceHosting.md#required-runtime-assemblies) for the full layout and deployment matrix.
|
The plugin assembly and its SDK dependencies (`aahClientManaged.dll`, `aahClient.dll`, `aahClientCommon.dll`, `Historian.CBE.dll`, `Historian.DPAPI.dll`, `ArchestrA.CloudHistorian.Contract.dll`) deploy to a `Historian/` subfolder next to `ZB.MOM.WW.OtOpcUa.Host.exe`. See [Service Hosting](ServiceHosting.md#required-runtime-assemblies) for the full layout and deployment matrix.
|
||||||
|
|
||||||
## Plugin Loading
|
## Plugin Loading
|
||||||
|
|
||||||
When the service starts with `Historian.Enabled=true`, `OpcUaService` calls `HistorianPluginLoader.TryLoad(config)`. The loader:
|
When the service starts with `Historian.Enabled=true`, `OpcUaService` calls `HistorianPluginLoader.TryLoad(config)`. The loader:
|
||||||
|
|
||||||
1. Probes `AppDomain.CurrentDomain.BaseDirectory\Historian\ZB.MOM.WW.LmxOpcUa.Historian.Aveva.dll`.
|
1. Probes `AppDomain.CurrentDomain.BaseDirectory\Historian\ZB.MOM.WW.OtOpcUa.Historian.Aveva.dll`.
|
||||||
2. Installs a one-shot `AppDomain.AssemblyResolve` handler that redirects any `aahClientManaged`/`aahClientCommon`/`Historian.*` lookups to the same subfolder, so the CLR can resolve SDK dependencies when the plugin first JITs.
|
2. Installs a one-shot `AppDomain.AssemblyResolve` handler that redirects any `aahClientManaged`/`aahClientCommon`/`Historian.*` lookups to the same subfolder, so the CLR can resolve SDK dependencies when the plugin first JITs.
|
||||||
3. Calls the plugin's `AvevaHistorianPluginEntry.Create(HistorianConfiguration)` via reflection and returns the resulting `IHistorianDataSource`.
|
3. Calls the plugin's `AvevaHistorianPluginEntry.Create(HistorianConfiguration)` via reflection and returns the resulting `IHistorianDataSource`.
|
||||||
4. On any failure (plugin missing, entry type not found, SDK assembly unresolvable, bad image), logs a warning with the expected plugin path and returns `null`. The server starts normally and `LmxNodeManager` returns `BadHistoryOperationUnsupported` for every history call.
|
4. On any failure (plugin missing, entry type not found, SDK assembly unresolvable, bad image), logs a warning with the expected plugin path and returns `null`. The server starts normally and `LmxNodeManager` returns `BadHistoryOperationUnsupported` for every history call.
|
||||||
@@ -35,7 +35,7 @@ The plugin uses the AVEVA Historian managed SDK (`aahClientManaged.dll`) to quer
|
|||||||
- **`HistoryQuery`** -- Raw historical samples with timestamp, value (numeric or string), and OPC quality.
|
- **`HistoryQuery`** -- Raw historical samples with timestamp, value (numeric or string), and OPC quality.
|
||||||
- **`AnalogSummaryQuery`** -- Pre-computed aggregates with properties for Average, Minimum, Maximum, ValueCount, First, Last, StdDev, and more.
|
- **`AnalogSummaryQuery`** -- Pre-computed aggregates with properties for Average, Minimum, Maximum, ValueCount, First, Last, StdDev, and more.
|
||||||
|
|
||||||
The SDK DLLs are located in `lib/` and originate from `C:\Program Files (x86)\Wonderware\Historian\`. Only the plugin project (`src/ZB.MOM.WW.LmxOpcUa.Historian.Aveva/`) references them at build time; the core Host project does not.
|
The SDK DLLs are located in `lib/` and originate from `C:\Program Files (x86)\Wonderware\Historian\`. Only the plugin project (`src/ZB.MOM.WW.OtOpcUa.Historian.Aveva/`) references them at build time; the core Host project does not.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -152,15 +152,15 @@ The .NET runtime's garbage collector releases COM references non-deterministical
|
|||||||
|
|
||||||
## Key source files
|
## Key source files
|
||||||
|
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/StaComThread.cs` -- STA thread and Win32 message pump
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/StaComThread.cs` -- STA thread and Win32 message pump
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.cs` -- Core client class (partial)
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.cs` -- Core client class (partial)
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.Connection.cs` -- Connect, disconnect, reconnect
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.Connection.cs` -- Connect, disconnect, reconnect
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.Subscription.cs` -- Subscribe, unsubscribe, replay
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.Subscription.cs` -- Subscribe, unsubscribe, replay
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.ReadWrite.cs` -- Read and write operations
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.ReadWrite.cs` -- Read and write operations
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.EventHandlers.cs` -- OnDataChange and OnWriteComplete handlers
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.EventHandlers.cs` -- OnDataChange and OnWriteComplete handlers
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxAccessClient.Monitor.cs` -- Background health monitor
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxAccessClient.Monitor.cs` -- Background health monitor
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/MxProxyAdapter.cs` -- COM object wrapper
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/MxProxyAdapter.cs` -- COM object wrapper
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/MxAccess/GalaxyRuntimeProbeManager.cs` -- Per-host `ScanState` probes, state machine, `IsHostStopped` lookup
|
- `src/ZB.MOM.WW.OtOpcUa.Host/MxAccess/GalaxyRuntimeProbeManager.cs` -- Per-host `ScanState` probes, state machine, `IsHostStopped` lookup
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/GalaxyRuntimeStatus.cs` -- Per-host DTO
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/GalaxyRuntimeStatus.cs` -- Per-host DTO
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/GalaxyRuntimeState.cs` -- `Unknown` / `Running` / `Stopped` enum
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/GalaxyRuntimeState.cs` -- `Unknown` / `Running` / `Stopped` enum
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Domain/IMxAccessClient.cs` -- Client interface
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Domain/IMxAccessClient.cs` -- Client interface
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ On startup, `OpcUaServerHost.StartAsync` calls `CheckApplicationInstanceCertific
|
|||||||
|
|
||||||
## Key source files
|
## Key source files
|
||||||
|
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/OpcUa/OpcUaServerHost.cs` -- Application lifecycle and programmatic configuration
|
- `src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/OpcUaServerHost.cs` -- Application lifecycle and programmatic configuration
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/OpcUa/LmxOpcUaServer.cs` -- StandardServer subclass and node manager creation
|
- `src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/LmxOpcUaServer.cs` -- StandardServer subclass and node manager creation
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/OpcUa/SecurityProfileResolver.cs` -- Profile-name to ServerSecurityPolicy mapping
|
- `src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/SecurityProfileResolver.cs` -- Profile-name to ServerSecurityPolicy mapping
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Configuration/OpcUaConfiguration.cs` -- Configuration POCO
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Configuration/OpcUaConfiguration.cs` -- Configuration POCO
|
||||||
- `src/ZB.MOM.WW.LmxOpcUa.Host/Configuration/SecurityProfileConfiguration.cs` -- Security configuration POCO
|
- `src/ZB.MOM.WW.OtOpcUa.Host/Configuration/SecurityProfileConfiguration.cs` -- Security configuration POCO
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ When deploying a redundant pair, the following configuration properties must dif
|
|||||||
The Client CLI includes a `redundancy` command that reads the redundancy state from a running server.
|
The Client CLI includes a `redundancy` command that reads the redundancy state from a running server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- redundancy -u opc.tcp://localhost:4840/LmxOpcUa
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- redundancy -u opc.tcp://localhost:4840/LmxOpcUa
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- redundancy -u opc.tcp://localhost:4841/LmxOpcUa
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- redundancy -u opc.tcp://localhost:4841/LmxOpcUa
|
||||||
```
|
```
|
||||||
|
|
||||||
The command reads the following standard OPC UA nodes and displays their values:
|
The command reads the following standard OPC UA nodes and displays their values:
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ TopShelf provides these deployment modes from the same executable:
|
|||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `LmxOpcUa.Host.exe` | Run as a console application (foreground) |
|
| `OtOpcUa.Host.exe` | Run as a console application (foreground) |
|
||||||
| `LmxOpcUa.Host.exe install` | Install as a Windows service |
|
| `OtOpcUa.Host.exe install` | Install as a Windows service |
|
||||||
| `LmxOpcUa.Host.exe uninstall` | Remove the Windows service |
|
| `OtOpcUa.Host.exe uninstall` | Remove the Windows service |
|
||||||
| `LmxOpcUa.Host.exe start` | Start the installed service |
|
| `OtOpcUa.Host.exe start` | Start the installed service |
|
||||||
| `LmxOpcUa.Host.exe stop` | Stop the installed service |
|
| `OtOpcUa.Host.exe stop` | Stop the installed service |
|
||||||
|
|
||||||
The service is configured to run as `LocalSystem` and start automatically on boot.
|
The service is configured to run as `LocalSystem` and start automatically on boot.
|
||||||
|
|
||||||
@@ -146,26 +146,26 @@ Install additional instances using TopShelf's `-servicename` flag:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd C:\publish\lmxopcua\instance2
|
cd C:\publish\lmxopcua\instance2
|
||||||
ZB.MOM.WW.LmxOpcUa.Host.exe install -servicename "LmxOpcUa2" -displayname "LMX OPC UA Server (Instance 2)"
|
ZB.MOM.WW.OtOpcUa.Host.exe install -servicename "LmxOpcUa2" -displayname "LMX OPC UA Server (Instance 2)"
|
||||||
```
|
```
|
||||||
|
|
||||||
See [Redundancy Guide](Redundancy.md) for full deployment details.
|
See [Redundancy Guide](Redundancy.md) for full deployment details.
|
||||||
|
|
||||||
## Required Runtime Assemblies
|
## Required Runtime Assemblies
|
||||||
|
|
||||||
The build uses Costura.Fody to embed all NuGet dependencies into the single `ZB.MOM.WW.LmxOpcUa.Host.exe`. The only native dependency that must sit alongside the executable in every deployment is the MXAccess COM toolkit:
|
The build uses Costura.Fody to embed all NuGet dependencies into the single `ZB.MOM.WW.OtOpcUa.Host.exe`. The only native dependency that must sit alongside the executable in every deployment is the MXAccess COM toolkit:
|
||||||
|
|
||||||
| Assembly | Purpose |
|
| Assembly | Purpose |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| `ArchestrA.MxAccess.dll` | MXAccess COM interop — runtime data access to Galaxy tags |
|
| `ArchestrA.MxAccess.dll` | MXAccess COM interop — runtime data access to Galaxy tags |
|
||||||
|
|
||||||
The Wonderware Historian SDK is packaged as a **runtime-loaded plugin** so hosts that will not use historical data access do not need the SDK installed. The plugin lives in a `Historian/` subfolder next to `ZB.MOM.WW.LmxOpcUa.Host.exe`:
|
The Wonderware Historian SDK is packaged as a **runtime-loaded plugin** so hosts that will not use historical data access do not need the SDK installed. The plugin lives in a `Historian/` subfolder next to `ZB.MOM.WW.OtOpcUa.Host.exe`:
|
||||||
|
|
||||||
```
|
```
|
||||||
ZB.MOM.WW.LmxOpcUa.Host.exe
|
ZB.MOM.WW.OtOpcUa.Host.exe
|
||||||
ArchestrA.MxAccess.dll
|
ArchestrA.MxAccess.dll
|
||||||
Historian/
|
Historian/
|
||||||
ZB.MOM.WW.LmxOpcUa.Historian.Aveva.dll
|
ZB.MOM.WW.OtOpcUa.Historian.Aveva.dll
|
||||||
aahClientManaged.dll
|
aahClientManaged.dll
|
||||||
aahClientCommon.dll
|
aahClientCommon.dll
|
||||||
aahClient.dll
|
aahClient.dll
|
||||||
@@ -174,7 +174,7 @@ Historian/
|
|||||||
ArchestrA.CloudHistorian.Contract.dll
|
ArchestrA.CloudHistorian.Contract.dll
|
||||||
```
|
```
|
||||||
|
|
||||||
At startup, if `Historian.Enabled=true` in `appsettings.json`, `HistorianPluginLoader` probes `Historian/ZB.MOM.WW.LmxOpcUa.Historian.Aveva.dll` via `Assembly.LoadFrom` and instantiates the plugin's entry point. An `AppDomain.AssemblyResolve` handler redirects the SDK assembly lookups (`aahClientManaged`, `aahClientCommon`, …) to the same subfolder so the CLR can resolve them when the plugin first JITs. If the plugin directory is absent or any SDK dependency fails to load, the loader logs a warning and the server continues to run with history support disabled — `LmxNodeManager` returns `BadHistoryOperationUnsupported` for every history call.
|
At startup, if `Historian.Enabled=true` in `appsettings.json`, `HistorianPluginLoader` probes `Historian/ZB.MOM.WW.OtOpcUa.Historian.Aveva.dll` via `Assembly.LoadFrom` and instantiates the plugin's entry point. An `AppDomain.AssemblyResolve` handler redirects the SDK assembly lookups (`aahClientManaged`, `aahClientCommon`, …) to the same subfolder so the CLR can resolve them when the plugin first JITs. If the plugin directory is absent or any SDK dependency fails to load, the loader logs a warning and the server continues to run with history support disabled — `LmxNodeManager` returns `BadHistoryOperationUnsupported` for every history call.
|
||||||
|
|
||||||
Deployment matrix:
|
Deployment matrix:
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ Three new .NET 10 cross-platform projects providing a shared OPC UA client libra
|
|||||||
|
|
||||||
| Project | Type | Purpose |
|
| Project | Type | Purpose |
|
||||||
|---------|------|---------|
|
|---------|------|---------|
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.Shared` | Class library | Core OPC UA client, models, interfaces |
|
| `ZB.MOM.WW.OtOpcUa.Client.Shared` | Class library | Core OPC UA client, models, interfaces |
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.CLI` | Console app | Command-line interface using CliFx |
|
| `ZB.MOM.WW.OtOpcUa.Client.CLI` | Console app | Command-line interface using CliFx |
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.UI` | Avalonia app | Desktop UI with tree browser, subscriptions, alarms |
|
| `ZB.MOM.WW.OtOpcUa.Client.UI` | Avalonia app | Desktop UI with tree browser, subscriptions, alarms |
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.Shared.Tests` | Test project | Unit tests for shared library |
|
| `ZB.MOM.WW.OtOpcUa.Client.Shared.Tests` | Test project | Unit tests for shared library |
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.CLI.Tests` | Test project | Unit tests for CLI commands |
|
| `ZB.MOM.WW.OtOpcUa.Client.CLI.Tests` | Test project | Unit tests for CLI commands |
|
||||||
| `ZB.MOM.WW.LmxOpcUa.Client.UI.Tests` | Test project | Unit tests for UI view models |
|
| `ZB.MOM.WW.OtOpcUa.Client.UI.Tests` | Test project | Unit tests for UI view models |
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ The application shall use TopShelf for Windows service lifecycle (install, unins
|
|||||||
### Acceptance Criteria
|
### Acceptance Criteria
|
||||||
|
|
||||||
- TopShelf HostFactory configures the service with name `LmxOpcUa`, display name `LMX OPC UA Server`.
|
- TopShelf HostFactory configures the service with name `LmxOpcUa`, display name `LMX OPC UA Server`.
|
||||||
- Service installs via command line: `ZB.MOM.WW.LmxOpcUa.Host.exe install`.
|
- Service installs via command line: `ZB.MOM.WW.OtOpcUa.Host.exe install`.
|
||||||
- Service uninstalls via: `ZB.MOM.WW.LmxOpcUa.Host.exe uninstall`.
|
- Service uninstalls via: `ZB.MOM.WW.OtOpcUa.Host.exe uninstall`.
|
||||||
- Service runs as LocalSystem account (needed for MXAccess COM access and Windows Auth to SQL Server).
|
- Service runs as LocalSystem account (needed for MXAccess COM access and Windows Auth to SQL Server).
|
||||||
- Interactive console mode (exe with no args) works for development/debugging.
|
- Interactive console mode (exe with no args) works for development/debugging.
|
||||||
- `StartAutomatically` is set for Windows service registration.
|
- `StartAutomatically` is set for Windows service registration.
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ The dashboard shall display a footer with last-updated time and service identifi
|
|||||||
|
|
||||||
### Acceptance Criteria
|
### Acceptance Criteria
|
||||||
|
|
||||||
- Format: "Last updated: {timestamp} UTC | Service: ZB.MOM.WW.LmxOpcUa.Host v{version}".
|
- Format: "Last updated: {timestamp} UTC | Service: ZB.MOM.WW.OtOpcUa.Host v{version}".
|
||||||
- Timestamp is the server-side UTC time when the HTML was generated.
|
- Timestamp is the server-side UTC time when the HTML was generated.
|
||||||
- Version is read from the assembly version (`Assembly.GetExecutingAssembly().GetName().Version`).
|
- Version is read from the assembly version (`Assembly.GetExecutingAssembly().GetName().Version`).
|
||||||
|
|
||||||
|
|||||||
@@ -211,19 +211,19 @@ The Client CLI supports the `-S` (or `--security`) flag to select the transport
|
|||||||
### Connect with no security
|
### Connect with no security
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S none
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S none
|
||||||
```
|
```
|
||||||
|
|
||||||
### Connect with signing
|
### Connect with signing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S sign
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S sign
|
||||||
```
|
```
|
||||||
|
|
||||||
### Connect with signing and encryption
|
### Connect with signing and encryption
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/ZB.MOM.WW.LmxOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S encrypt
|
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S encrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
### Browse with encryption and authentication
|
### Browse with encryption and authentication
|
||||||
|
|||||||
119
docs/v2/implementation/exit-gate-phase-0.md
Normal file
119
docs/v2/implementation/exit-gate-phase-0.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Phase 0 — Exit Gate Record
|
||||||
|
|
||||||
|
**Phase**: 0 — Rename + .NET 10 cleanup
|
||||||
|
**Branch**: `phase-0-rename`
|
||||||
|
**Date**: 2026-04-17
|
||||||
|
**Implementation lead**: Claude (executing on behalf of dohertj2)
|
||||||
|
**Reviewer**: pending — PR review required before merge
|
||||||
|
|
||||||
|
## Compliance check results
|
||||||
|
|
||||||
|
### 1. No stale `LmxOpcUa` references (with allowlist)
|
||||||
|
|
||||||
|
Total `LmxOpcUa` references in `src/` + `tests/` (excluding `bin/`, `obj/`, `publish_temp/`, `docs/v2/`): **23**.
|
||||||
|
|
||||||
|
All 23 are **allowlisted retentions** per Phase 0 Out-of-Scope rules:
|
||||||
|
|
||||||
|
| File / line | Reference | Reason for retention |
|
||||||
|
|-------------|-----------|----------------------|
|
||||||
|
| `Client.CLI/Program.cs:13` | `"LmxOpcUa CLI - command-line client for the LmxOpcUa OPC UA server"` | CLI `--help` description; cosmetic, references the runtime server name which stays `LmxOpcUa` |
|
||||||
|
| `Client.Shared/Adapters/DefaultApplicationConfigurationFactory.cs:21,22,63` | `ApplicationName = "LmxOpcUaClient"`, `ApplicationUri = "urn:localhost:LmxOpcUaClient"` | OPC UA client identity. Per Phase 0 out-of-scope rule: `ApplicationUri` defaults stay to preserve v1/v2 client trust |
|
||||||
|
| `Client.Shared/Models/ConnectionSettings.cs:48` | `"LmxOpcUaClient", "pki"` | Client cert directory name `%LocalAppData%\LmxOpcUaClient\pki\`. Changing it would re-trigger trust handshake with all v1 servers |
|
||||||
|
| `Client.Shared/OpcUaClientService.cs:428` | `CreateSessionAsync(..., "LmxOpcUaClient", ...)` | OPC UA client session name |
|
||||||
|
| `Client.UI/Services/JsonSettingsService.cs:12` | `"LmxOpcUaClient"` | Client UI app-data folder; same rationale as cert path |
|
||||||
|
| `Client.UI/ViewModels/MainWindowViewModel.cs:26` | `"LmxOpcUaClient", "pki"` | Same cert path |
|
||||||
|
| `Client.UI/Views/MainWindow.axaml:81` | `Watermark="(default: AppData/LmxOpcUaClient/pki)"` | UI hint text reflecting the actual default cert path |
|
||||||
|
| `Host/appsettings.json:5` | `"EndpointPath": "/LmxOpcUa"` | OPC UA endpoint path; clients connect to `opc.tcp://host:port/LmxOpcUa`. Changing breaks v1 client connections |
|
||||||
|
| `Host/appsettings.json:6` | `"ServerName": "LmxOpcUa"` | Server's OPC UA `ApplicationName` and cert subject CN. Changing changes cert CN on regen, breaks v1 client trust |
|
||||||
|
| `Host/appsettings.json:17` | `"ClientName": "LmxOpcUa"` | OUR registration name to MxAccess. Defensive retention for audit trail consistency during v1/v2 coexistence |
|
||||||
|
| `Host/Configuration/MxAccessConfiguration.cs:11` | `ClientName default = "LmxOpcUa"` | Code default matching appsettings |
|
||||||
|
| `Host/Configuration/OpcUaConfiguration.cs:22` | `EndpointPath default = "/LmxOpcUa"` | Code default matching appsettings |
|
||||||
|
| `Host/Configuration/OpcUaConfiguration.cs:27` | `ServerName default = "LmxOpcUa"` | Code default matching appsettings |
|
||||||
|
| `Host/Configuration/OpcUaConfiguration.cs:36` | XML doc comment referencing `urn:{GalaxyName}:LmxOpcUa` ApplicationUri default | Documentation of behavior; the behavior itself is intentionally retained |
|
||||||
|
| `Host/OpcUa/LmxOpcUaServer.cs:17,19,45` | Class name `LmxOpcUaServer` | Class rename out of Phase 0 scope. Phase 0 Task 0.5 patterns rename only `ZB\.MOM\.WW\.LmxOpcUa` namespace prefix; bare class names stay. Class rename happens in Phase 1's `LmxNodeManager → GenericDriverNodeManager` work alongside the rest of the Core extraction |
|
||||||
|
| `Host/OpcUa/LmxOpcUaServer.cs:101,520` | `namespaceUri = $"urn:{_galaxyName}:LmxOpcUa"`, `ProductUri = $"urn:{_galaxyName}:LmxOpcUa"` | OPC UA `ApplicationUri` default derivation per Phase 0 out-of-scope rule |
|
||||||
|
| `Host/OpcUa/LmxOpcUaServer.cs:519` | `ProductName = "LmxOpcUa Server"` | OPC UA server identity string |
|
||||||
|
| `Host/OpcUa/OpcUaServerHost.cs:33,144,247` | References to `LmxOpcUaServer` class + `urn:{GalaxyName}:LmxOpcUa` URI | Same class-rename + URI-default rules |
|
||||||
|
|
||||||
|
**No unauthorized stale references.** Result: ✅ PASS
|
||||||
|
|
||||||
|
### 2. Build succeeds
|
||||||
|
|
||||||
|
```
|
||||||
|
dotnet build ZB.MOM.WW.OtOpcUa.slnx
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: **0 errors, 30 warnings.** Warning count is *lower* than baseline (167) — the rename did not introduce new warnings; the baseline included repeated emissions across multiple build passes that cleared on the rename build. ✅ PASS
|
||||||
|
|
||||||
|
### 3. All tests pass at or above baseline
|
||||||
|
|
||||||
|
| Test project | Baseline (pass / fail) | Phase 0 result | Verdict |
|
||||||
|
|--------------|------------------------|----------------|---------|
|
||||||
|
| `Client.UI.Tests` | 98 / 0 | 98 / 0 | ✅ |
|
||||||
|
| `Client.CLI.Tests` | 51 / 1 | 51 / 1 | ✅ same baseline failure |
|
||||||
|
| `Historian.Aveva.Tests` | 41 / 0 | 41 / 0 | ✅ |
|
||||||
|
| `Client.Shared.Tests` | 131 / 0 | 131 / 0 | ✅ |
|
||||||
|
| `IntegrationTests` | 6 / 0 | 6 / 0 | ✅ |
|
||||||
|
| `Tests` (main) | 493 / 1 | **494 / 0** | ✅ improvement (one flaky baseline failure passed this run) |
|
||||||
|
| **Total** | **820 / 2** | **821 / 1** | ✅ strict improvement |
|
||||||
|
|
||||||
|
Phase 0 exit-gate adapted requirement was: failure count = baseline (2); pass count ≥ baseline (820). Actual: failure count 1 (≤ 2), pass count 821 (≥ 820). ✅ PASS
|
||||||
|
|
||||||
|
### 4. Solution structure matches plan
|
||||||
|
|
||||||
|
`ls src/`: 5 entries, all `ZB.MOM.WW.OtOpcUa.*` — matches plan §5 expected v1-renamed surface (no new projects added; those land in Phase 1)
|
||||||
|
`ls tests/`: 6 entries, all `ZB.MOM.WW.OtOpcUa.*` — matches
|
||||||
|
`ZB.MOM.WW.OtOpcUa.slnx` exists; previous `ZB.MOM.WW.LmxOpcUa.slnx` removed
|
||||||
|
✅ PASS
|
||||||
|
|
||||||
|
### 5. .NET targets unchanged
|
||||||
|
|
||||||
|
| Project type | Expected | Actual | Verdict |
|
||||||
|
|--------------|----------|--------|---------|
|
||||||
|
| Client.CLI | net10.0 | net10.0 | ✅ |
|
||||||
|
| Client.Shared | net10.0 | net10.0 | ✅ |
|
||||||
|
| Client.UI | net10.0 | net10.0 | ✅ |
|
||||||
|
| Historian.Aveva | net48 | net48 | ✅ Phase 2 splits this |
|
||||||
|
| Host | net48 | net48 | ✅ Phase 2 splits this |
|
||||||
|
| All test projects | match SUT | match SUT | ✅ |
|
||||||
|
|
||||||
|
✅ PASS
|
||||||
|
|
||||||
|
### 6. Decision compliance
|
||||||
|
|
||||||
|
This phase implements decision #9 (Rename to OtOpcUa as step 1). Citation in `entry-gate-phase-0.md` "Decision #9 confirmed" line. ✅ PASS
|
||||||
|
|
||||||
|
### 7. Service registration
|
||||||
|
|
||||||
|
Not separately tested in this run (would require Windows service install on the build machine). The TopShelf `SetServiceName("OtOpcUa")` change is in `src/ZB.MOM.WW.OtOpcUa.Host/Program.cs:37` (verified by grep). Manual service install/uninstall verification is **deferred to the deployment-side reviewer** as part of PR review. ⚠️ DEFERRED
|
||||||
|
|
||||||
|
### Branch-naming convention deviation
|
||||||
|
|
||||||
|
Original Phase 0 doc specified branch name `v2/phase-0-rename`. Git rejected this because `v2` is itself a branch and `v2/...` would create a path conflict. Convention updated in `implementation/overview.md` and `phase-0-rename-and-net10.md` to use `phase-0-rename` (no `v2/` prefix). All future phase branches follow the same pattern. ⚠️ DEVIATION DOCUMENTED
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Check | Status |
|
||||||
|
|-------|--------|
|
||||||
|
| 1. No stale references (with allowlist) | ✅ PASS |
|
||||||
|
| 2. Build succeeds | ✅ PASS |
|
||||||
|
| 3. Tests at or above baseline | ✅ PASS (strict improvement: 821/1 vs baseline 820/2) |
|
||||||
|
| 4. Solution structure matches plan | ✅ PASS |
|
||||||
|
| 5. .NET targets unchanged | ✅ PASS |
|
||||||
|
| 6. Decision compliance | ✅ PASS |
|
||||||
|
| 7. Service registration | ⚠️ DEFERRED to PR review |
|
||||||
|
|
||||||
|
**Exit gate status: READY FOR PR REVIEW.**
|
||||||
|
|
||||||
|
## Deviations from Phase 0 doc
|
||||||
|
|
||||||
|
1. **Pre-existing test failures preserved as baseline** (documented at entry gate)
|
||||||
|
2. **Branch name** `phase-0-rename` instead of `v2/phase-0-rename` (git path conflict with existing `v2` branch — convention updated in overview.md)
|
||||||
|
3. **Service install verification deferred** to PR reviewer (requires Windows service install permissions on the test box)
|
||||||
|
|
||||||
|
None of these deviations affect the rename's correctness; all are documented in this record per the gate rules in `implementation/overview.md`.
|
||||||
|
|
||||||
|
## Signoff
|
||||||
|
|
||||||
|
Implementation lead: Claude (Opus 4.7) — 2026-04-17
|
||||||
|
Reviewer: pending — PR review required before merge to `v2`
|
||||||
@@ -2,11 +2,11 @@ using CliFx;
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for all CLI commands providing common connection options and helpers.
|
/// Abstract base class for all CLI commands providing common connection options and helpers.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("alarms", Description = "Subscribe to alarm events")]
|
[Command("alarms", Description = "Subscribe to alarm events")]
|
||||||
public class AlarmsCommand : CommandBase
|
public class AlarmsCommand : CommandBase
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("browse", Description = "Browse the OPC UA address space")]
|
[Command("browse", Description = "Browse the OPC UA address space")]
|
||||||
public class BrowseCommand : CommandBase
|
public class BrowseCommand : CommandBase
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("connect", Description = "Test connection to an OPC UA server")]
|
[Command("connect", Description = "Test connection to an OPC UA server")]
|
||||||
public class ConnectCommand : CommandBase
|
public class ConnectCommand : CommandBase
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("historyread", Description = "Read historical data from a node")]
|
[Command("historyread", Description = "Read historical data from a node")]
|
||||||
public class HistoryReadCommand : CommandBase
|
public class HistoryReadCommand : CommandBase
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("read", Description = "Read a value from a node")]
|
[Command("read", Description = "Read a value from a node")]
|
||||||
public class ReadCommand : CommandBase
|
public class ReadCommand : CommandBase
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("redundancy", Description = "Read redundancy state from an OPC UA server")]
|
[Command("redundancy", Description = "Read redundancy state from an OPC UA server")]
|
||||||
public class RedundancyCommand : CommandBase
|
public class RedundancyCommand : CommandBase
|
||||||
@@ -2,10 +2,10 @@ using System.Collections.Concurrent;
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("subscribe", Description = "Monitor a node for value changes")]
|
[Command("subscribe", Description = "Monitor a node for value changes")]
|
||||||
public class SubscribeCommand : CommandBase
|
public class SubscribeCommand : CommandBase
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Commands;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
||||||
|
|
||||||
[Command("write", Description = "Write a value to a node")]
|
[Command("write", Description = "Write a value to a node")]
|
||||||
public class WriteCommand : CommandBase
|
public class WriteCommand : CommandBase
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.CLI.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses node ID strings into OPC UA <see cref="NodeId" /> objects.
|
/// Parses node ID strings into OPC UA <see cref="NodeId" /> objects.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using CliFx;
|
using CliFx;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.CLI;
|
using ZB.MOM.WW.OtOpcUa.Client.CLI;
|
||||||
|
|
||||||
return await new CliApplicationBuilder()
|
return await new CliApplicationBuilder()
|
||||||
.AddCommandsFromThisAssembly()
|
.AddCommandsFromThisAssembly()
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>ZB.MOM.WW.LmxOpcUa.Client.CLI</RootNamespace>
|
<RootNamespace>ZB.MOM.WW.OtOpcUa.Client.CLI</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ZB.MOM.WW.LmxOpcUa.Client.Shared\ZB.MOM.WW.LmxOpcUa.Client.Shared.csproj"/>
|
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Client.Shared\ZB.MOM.WW.OtOpcUa.Client.Shared.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using Opc.Ua.Configuration;
|
using Opc.Ua.Configuration;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Production implementation that builds a real OPC UA ApplicationConfiguration.
|
/// Production implementation that builds a real OPC UA ApplicationConfiguration.
|
||||||
@@ -2,7 +2,7 @@ using Opc.Ua;
|
|||||||
using Opc.Ua.Client;
|
using Opc.Ua.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Production endpoint discovery that queries the real server.
|
/// Production endpoint discovery that queries the real server.
|
||||||
@@ -2,7 +2,7 @@ using Opc.Ua;
|
|||||||
using Opc.Ua.Client;
|
using Opc.Ua.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Production session adapter wrapping a real OPC UA Session.
|
/// Production session adapter wrapping a real OPC UA Session.
|
||||||
@@ -2,7 +2,7 @@ using Opc.Ua;
|
|||||||
using Opc.Ua.Client;
|
using Opc.Ua.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Production session factory that creates real OPC UA sessions.
|
/// Production session factory that creates real OPC UA sessions.
|
||||||
@@ -2,7 +2,7 @@ using Opc.Ua;
|
|||||||
using Opc.Ua.Client;
|
using Opc.Ua.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Production subscription adapter wrapping a real OPC UA Subscription.
|
/// Production subscription adapter wrapping a real OPC UA Subscription.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates and configures an OPC UA ApplicationConfiguration.
|
/// Creates and configures an OPC UA ApplicationConfiguration.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstracts OPC UA endpoint discovery for testability.
|
/// Abstracts OPC UA endpoint discovery for testability.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstracts the OPC UA session for read, write, browse, history, and subscription operations.
|
/// Abstracts the OPC UA session for read, write, browse, history, and subscription operations.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates OPC UA sessions from a configured endpoint.
|
/// Creates OPC UA sessions from a configured endpoint.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstracts OPC UA subscription and monitored item management.
|
/// Abstracts OPC UA subscription and monitored item management.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps the library's AggregateType enum to OPC UA aggregate function NodeIds.
|
/// Maps the library's AggregateType enum to OPC UA aggregate function NodeIds.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses and normalizes failover URL sets for redundant OPC UA connections.
|
/// Parses and normalizes failover URL sets for redundant OPC UA connections.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps between the library's SecurityMode enum and OPC UA SDK MessageSecurityMode.
|
/// Maps between the library's SecurityMode enum and OPC UA SDK MessageSecurityMode.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts raw string values into typed values based on the current value's runtime type.
|
/// Converts raw string values into typed values based on the current value's runtime type.
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using BrowseResult = ZB.MOM.WW.LmxOpcUa.Client.Shared.Models.BrowseResult;
|
using BrowseResult = ZB.MOM.WW.OtOpcUa.Client.Shared.Models.BrowseResult;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shared OPC UA client service contract for CLI and UI consumers.
|
/// Shared OPC UA client service contract for CLI and UI consumers.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Factory for creating <see cref="IOpcUaClientService" /> instances.
|
/// Factory for creating <see cref="IOpcUaClientService" /> instances.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggregate functions for processed history reads.
|
/// Aggregate functions for processed history reads.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event data for an alarm or condition notification from the OPC UA server.
|
/// Event data for an alarm or condition notification from the OPC UA server.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single node in the browse result set.
|
/// Represents a single node in the browse result set.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Information about the current OPC UA session.
|
/// Information about the current OPC UA session.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Settings for establishing an OPC UA client connection.
|
/// Settings for establishing an OPC UA client connection.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the current state of the OPC UA client connection.
|
/// Represents the current state of the OPC UA client connection.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event data raised when the client connection state changes.
|
/// Event data raised when the client connection state changes.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event data for a monitored data value change.
|
/// Event data for a monitored data value change.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Redundancy information read from the server.
|
/// Redundancy information read from the server.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transport security mode for the OPC UA connection.
|
/// Transport security mode for the OPC UA connection.
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Helpers;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using BrowseResult = ZB.MOM.WW.LmxOpcUa.Client.Shared.Models.BrowseResult;
|
using BrowseResult = ZB.MOM.WW.OtOpcUa.Client.Shared.Models.BrowseResult;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Full implementation of <see cref="IOpcUaClientService" /> using adapter abstractions for testability.
|
/// Full implementation of <see cref="IOpcUaClientService" /> using adapter abstractions for testability.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default factory that creates <see cref="OpcUaClientService" /> instances with production adapters.
|
/// Default factory that creates <see cref="OpcUaClientService" /> instances with production adapters.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>ZB.MOM.WW.LmxOpcUa.Client.Shared</RootNamespace>
|
<RootNamespace>ZB.MOM.WW.OtOpcUa.Client.Shared</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InternalsVisibleTo Include="ZB.MOM.WW.LmxOpcUa.Client.Shared.Tests"/>
|
<InternalsVisibleTo Include="ZB.MOM.WW.OtOpcUa.Client.Shared.Tests"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Application xmlns="https://github.com/avaloniaui"
|
<Application xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.App"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.App"
|
||||||
RequestedThemeVariant="Light">
|
RequestedThemeVariant="Light">
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<FluentTheme />
|
<FluentTheme />
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI;
|
||||||
|
|
||||||
public class App : Application
|
public class App : Application
|
||||||
{
|
{
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -1,6 +1,6 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Controls.DateTimeRangePicker">
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Controls.DateTimeRangePicker">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<StackPanel Spacing="2">
|
<StackPanel Spacing="2">
|
||||||
<TextBlock Text="Start (UTC)" FontSize="11" Foreground="Gray" />
|
<TextBlock Text="Start (UTC)" FontSize="11" Foreground="Gray" />
|
||||||
@@ -5,7 +5,7 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Controls;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Controls;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A date/time range picker using formatted text boxes and preset duration buttons.
|
/// A date/time range picker using formatted text boxes and preset duration buttons.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Formats OPC UA status codes as "0xHEX (description)".
|
/// Formats OPC UA status codes as "0xHEX (description)".
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Helpers;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Formats OPC UA values for display, with array support.
|
/// Formats OPC UA values for display, with array support.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI;
|
||||||
|
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispatches actions to the Avalonia UI thread.
|
/// Dispatches actions to the Avalonia UI thread.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads and saves user settings.
|
/// Loads and saves user settings.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstraction for dispatching actions to the UI thread.
|
/// Abstraction for dispatching actions to the UI thread.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Persists user settings to a JSON file under LocalApplicationData.
|
/// Persists user settings to a JSON file under LocalApplicationData.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispatcher that executes actions synchronously on the calling thread.
|
/// Dispatcher that executes actions synchronously on the calling thread.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Persisted user connection settings.
|
/// Persisted user connection settings.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single alarm event row.
|
/// Represents a single alarm event row.
|
||||||
@@ -2,11 +2,11 @@ using System.Collections.ObjectModel;
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ViewModel for the alarms panel.
|
/// ViewModel for the alarms panel.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ViewModel for the OPC UA browse tree panel.
|
/// ViewModel for the OPC UA browse tree panel.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single historical value row.
|
/// Represents a single historical value row.
|
||||||
@@ -2,11 +2,11 @@ using System.Collections.ObjectModel;
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ViewModel for the history panel.
|
/// ViewModel for the history panel.
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main window ViewModel coordinating all panels.
|
/// Main window ViewModel coordinating all panels.
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ViewModel for the read/write panel.
|
/// ViewModel for the read/write panel.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single active subscription row.
|
/// Represents a single active subscription row.
|
||||||
@@ -2,11 +2,11 @@ using System.Collections.ObjectModel;
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Opc.Ua;
|
using Opc.Ua;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ViewModel for the subscriptions panel.
|
/// ViewModel for the subscriptions panel.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.Shared;
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single node in the OPC UA browse tree with lazy-load support.
|
/// Represents a single node in the OPC UA browse tree with lazy-load support.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Window xmlns="https://github.com/avaloniaui"
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.AckAlarmWindow"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.AckAlarmWindow"
|
||||||
Title="Acknowledge Alarm"
|
Title="Acknowledge Alarm"
|
||||||
Width="420"
|
Width="420"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class AckAlarmWindow : Window
|
public partial class AckAlarmWindow : Window
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.AlarmsView"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.AlarmsView"
|
||||||
x:DataType="vm:AlarmsViewModel">
|
x:DataType="vm:AlarmsViewModel">
|
||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<!-- Controls -->
|
<!-- Controls -->
|
||||||
@@ -3,9 +3,9 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class AlarmsView : UserControl
|
public partial class AlarmsView : UserControl
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.BrowseTreeView"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.BrowseTreeView"
|
||||||
x:DataType="vm:BrowseTreeViewModel">
|
x:DataType="vm:BrowseTreeViewModel">
|
||||||
<TreeView ItemsSource="{Binding RootNodes}"
|
<TreeView ItemsSource="{Binding RootNodes}"
|
||||||
Name="BrowseTree"
|
Name="BrowseTree"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class BrowseTreeView : UserControl
|
public partial class BrowseTreeView : UserControl
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
xmlns:controls="using:ZB.MOM.WW.LmxOpcUa.Client.UI.Controls"
|
xmlns:controls="using:ZB.MOM.WW.OtOpcUa.Client.UI.Controls"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.HistoryView"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.HistoryView"
|
||||||
x:DataType="vm:HistoryViewModel">
|
x:DataType="vm:HistoryViewModel">
|
||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<!-- Controls -->
|
<!-- Controls -->
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class HistoryView : UserControl
|
public partial class HistoryView : UserControl
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<Window xmlns="https://github.com/avaloniaui"
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
xmlns:views="using:ZB.MOM.WW.LmxOpcUa.Client.UI.Views"
|
xmlns:views="using:ZB.MOM.WW.OtOpcUa.Client.UI.Views"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.MainWindow"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.MainWindow"
|
||||||
x:DataType="vm:MainWindowViewModel"
|
x:DataType="vm:MainWindowViewModel"
|
||||||
Title="OPC UA Client"
|
Title="OPC UA Client"
|
||||||
Width="1200"
|
Width="1200"
|
||||||
@@ -4,9 +4,9 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using Svg.Skia;
|
using Svg.Skia;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ public partial class MainWindow : Window
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
using var stream = assembly.GetManifestResourceStream("ZB.MOM.WW.LmxOpcUa.Client.UI.Assets.app-icon.svg");
|
using var stream = assembly.GetManifestResourceStream("ZB.MOM.WW.OtOpcUa.Client.UI.Assets.app-icon.svg");
|
||||||
if (stream == null) return;
|
if (stream == null) return;
|
||||||
|
|
||||||
using var svg = new SKSvg();
|
using var svg = new SKSvg();
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.ReadWriteView"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.ReadWriteView"
|
||||||
x:DataType="vm:ReadWriteViewModel">
|
x:DataType="vm:ReadWriteViewModel">
|
||||||
<StackPanel Spacing="8" Margin="8">
|
<StackPanel Spacing="8" Margin="8">
|
||||||
<!-- Selected Node -->
|
<!-- Selected Node -->
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class ReadWriteView : UserControl
|
public partial class ReadWriteView : UserControl
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels"
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.SubscriptionsView"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.SubscriptionsView"
|
||||||
x:DataType="vm:SubscriptionsViewModel">
|
x:DataType="vm:SubscriptionsViewModel">
|
||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<!-- Add/Remove Controls -->
|
<!-- Add/Remove Controls -->
|
||||||
@@ -2,9 +2,9 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class SubscriptionsView : UserControl
|
public partial class SubscriptionsView : UserControl
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Window xmlns="https://github.com/avaloniaui"
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="ZB.MOM.WW.LmxOpcUa.Client.UI.Views.WriteValueWindow"
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.WriteValueWindow"
|
||||||
Title="Write Value"
|
Title="Write Value"
|
||||||
Width="420"
|
Width="420"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
using ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Views;
|
namespace ZB.MOM.WW.OtOpcUa.Client.UI.Views;
|
||||||
|
|
||||||
public partial class WriteValueWindow : Window
|
public partial class WriteValueWindow : Window
|
||||||
{
|
{
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user