New deployment-wide options bound from the "OpcUa" section of appsettings.json:
- ApplicationName (default "ScadaLink-DCL")
- TrustedIssuerStorePath / TrustedPeerStorePath / RejectedCertificateStorePath
Empty paths fall back to Path.GetTempPath()/ScadaLink/pki/* so dev runs work
without explicit config — same defaults the hardcoded values previously used.
Wiring:
- ServiceCollectionExtensions binds OpcUaGlobalOptions to the OpcUa section.
- DataConnectionFactory takes IOptions<OpcUaGlobalOptions> and constructs
RealOpcUaClientFactory with the snapshot.
- RealOpcUaClient(globalOptions) replaces the hardcoded ApplicationName and
the three CertificateTrustList store paths in ApplicationConfiguration.
- Parameterless ctors on factory and client preserved for the existing test
suite (32/32 DCL tests still green).
OpcUaConnectionOptions record gains DiscardOldest, SubscriptionPriority,
SubscriptionDisplayName, TimestampsToReturn, plus OpcUaDeadbandOptions and
OpcUaUserIdentityOptions nullable sub-records.
OpcUaDataConnection.ConnectAsync copies all new fields from the typed
OpcUaEndpointConfig (including the Deadband and UserIdentity sub-objects)
into the OpcUaConnectionOptions record.
RealOpcUaClient:
- BuildUserIdentity translates TokenType into Opc.Ua.UserIdentity:
Anonymous → null, UsernamePassword → new UserIdentity(name, utf8(pass)),
X509Certificate → new UserIdentity(X509CertificateLoader.LoadPkcs12FromFile(...)).
- Subscription uses opts.SubscriptionDisplayName and opts.SubscriptionPriority.
- MonitoredItem.DiscardOldest is opts.DiscardOldest (was hardcoded true).
- BuildDataChangeFilter materializes a DataChangeFilter when Deadband is set.
- ReadAsync uses MapTimestampsToReturn for opts.TimestampsToReturn (was hardcoded Source).
X509CertificateLoader replaces obsolete X509Certificate2(string,string) ctor
(SYSLIB0057 on .NET 10). UserIdentity(string,byte[]) ctor used because the
(string,string) overload was removed in OPC Foundation 1.5.378.106.
- Add JoeAppEngine folder to OPC UA nodes.json (BTCS, AlarmCntsBySeverity, Scheduler/ScanTime)
- Fix DataConnectionActor: capture Self in PreStart for use from non-actor threads,
preventing Self.Tell failure in Disconnected event handler
- Implement InstanceActor.HandleConnectionQualityChanged to mark attributes Bad on disconnect
- Fix LmxFakeProxy TagMapper to serialize arrays as JSON instead of "System.Int32[]"
- Allow DataType and DataSourceReference updates in TemplateService.UpdateAttributeAsync
- Update test_infra_opcua.md with JoeAppEngine documentation
- DataConnectionActor now stores and passes connection details to adapter ConnectAsync
- DataConnectionManagerActor passes connection details when creating actor
- RealOpcUaClient uses DiscoveryClient for endpoint selection with no-security preference
- Added certificate trust store paths to prevent TrustedIssuerCertificates error
- Sanitize connection names for Akka actor paths (replace spaces)
- Add connection binding UI to Instances page (per-attribute and bulk assign)
- FlatteningService populates Connections dict from bound data connections
- Real OPC UA client using OPC Foundation SDK for live tag subscriptions
- DataConnectionFactory uses RealOpcUaClientFactory by default
- OpcUaDataConnection supports both "endpoint" and "EndpointUrl" config keys