From e6efc7737aaa88022522415aca3dc6dde9eff0e5 Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 14:58:31 +0200 Subject: [PATCH 1/7] Update to dotnet 7 --- Source/Dockerfile | 13 +++++++++---- Source/OPCUA.csproj | 14 +++++++++----- Source/OpcuaConnector.cs | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Source/Dockerfile b/Source/Dockerfile index 7dcf070..ca39379 100644 --- a/Source/Dockerfile +++ b/Source/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine3.13 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine3.17 AS build-env WORKDIR /app VOLUME [ "/app/config" ] @@ -9,9 +9,14 @@ WORKDIR /app/Source RUN dotnet restore --runtime alpine-x64 -RUN dotnet publish -c Release -o out --no-restore +RUN dotnet publish -c Release -o out --no-restore \ + --runtime alpine-x64 \ + --self-contained true \ + /p:PublishTrimmed=true \ + /p:PublishSingleFile=true + +FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine3.17 AS final -FROM mcr.microsoft.com/dotnet/runtime:5.0-alpine3.13 WORKDIR /app COPY --from=build-env /app/Source/out ./ COPY --from=build-env /app/Source/config ./config @@ -19,4 +24,4 @@ COPY --from=build-env /app/Source/config ./config RUN adduser -Ds /bin/sh moduleuser USER moduleuser -ENTRYPOINT ["dotnet", "RaaLabs.Edge.Connectors.OPCUA.dll"] \ No newline at end of file +ENTRYPOINT ["./RaaLabs.Edge.Connectors.OPCUA"] \ No newline at end of file diff --git a/Source/OPCUA.csproj b/Source/OPCUA.csproj index 0ec92c0..2a00abf 100644 --- a/Source/OPCUA.csproj +++ b/Source/OPCUA.csproj @@ -1,17 +1,21 @@ Exe - net5.0 + net7.0 + partial RaaLabs.Edge.Connectors.OPCUA - - - - + + + + + + + diff --git a/Source/OpcuaConnector.cs b/Source/OpcuaConnector.cs index bb222b4..697c40b 100644 --- a/Source/OpcuaConnector.cs +++ b/Source/OpcuaConnector.cs @@ -46,7 +46,7 @@ public OpcuaConnector(ILogger logger, OpcuaConfiguration opcuaConfiguration) var config = new ApplicationConfiguration() { ApplicationName = "Raa Labs OPC UA connector", - ApplicationUri = Utils.Format(@"urn:{0}:" + "Raa Labs OPC UA connector" + "", ""), + ApplicationUri = "Raa Labs OPC UA connector", ApplicationType = ApplicationType.Client, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, From 34df6318d4bb504e4cab0bacbc6a3f47ea6041cf Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 15:07:05 +0200 Subject: [PATCH 2/7] Add metricshandler --- Source/IMetricsHandler.cs | 36 ++++++++++++++++++++++++++++++++++++ Source/OPCUA.csproj | 9 +++++---- Source/OpcuaConnector.cs | 5 ++++- Source/Program.cs | 3 +++ 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 Source/IMetricsHandler.cs diff --git a/Source/IMetricsHandler.cs b/Source/IMetricsHandler.cs new file mode 100644 index 0000000..e029eb2 --- /dev/null +++ b/Source/IMetricsHandler.cs @@ -0,0 +1,36 @@ +// Copyright (c) RaaLabs. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Globalization; +using System.Diagnostics.CodeAnalysis; +using RaaLabs.Edge.Modules.Diagnostics.Metrics; +using RaaLabs.Edge.Modules.EventHandling.RequestHandling; + + +namespace RaaLabs.Edge.Connectors.OPCUA; + +/// +/// Interface for registering metrics +/// +#pragma warning disable CS1591 +[Metrics(Prefix = "raaedge")] +[Labels("iothub", "{IOTEDGE_IOTHUBHOSTNAME:env}", "edge_device", "{IOTEDGE_DEVICEID:env}", "edge_module", "{IOTEDGE_MODULEID:env}", "module", "{IOTEDGE_MODULEID:env}", "instance_number", "{InstanceNumber}")] +public interface IMetricsHandler : IMetricsClient, IWithStateFrom +{ + + [Counter(Name = "messages_received_total", Unit = "count", Description = "The total number of messages received", Exported = true)] + public void NumberOfMessagesReceived(long value); + + [Counter(Name = "messages_sent_total", Unit = "count", Description = "The total number of messages sent", Exported = true)] + public void NumberOfMessagesSent(long value); +} + +[ExcludeFromCodeCoverage] +public class MetricsHandlerState +{ + /// + /// The instance number. + /// + public string InstanceNumber { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString("x", CultureInfo.InvariantCulture); +} \ No newline at end of file diff --git a/Source/OPCUA.csproj b/Source/OPCUA.csproj index 2a00abf..7d0c904 100644 --- a/Source/OPCUA.csproj +++ b/Source/OPCUA.csproj @@ -12,10 +12,11 @@ - - - - + + + + + diff --git a/Source/OpcuaConnector.cs b/Source/OpcuaConnector.cs index 697c40b..a0371fd 100644 --- a/Source/OpcuaConnector.cs +++ b/Source/OpcuaConnector.cs @@ -27,16 +27,18 @@ public class OpcuaConnector : IRunAsync, IProduceEvent /// Initializes a new instance of /// /// for logging - public OpcuaConnector(ILogger logger, OpcuaConfiguration opcuaConfiguration) + public OpcuaConnector(ILogger logger, OpcuaConfiguration opcuaConfiguration, IMetricsHandler metricsHandler) { _logger = logger; _opcuaConfiguration = opcuaConfiguration; + _metricsHandler = metricsHandler; var securityConfig = new SecurityConfiguration() { @@ -117,6 +119,7 @@ private async Task ConnectOpcua() foreach (var opcuaDatapoint in opcuaDatapoints) { SendDatapoint(opcuaDatapoint); + _metricsHandler.NumberOfMessagesSent(1); } } catch (Exception ex) diff --git a/Source/Program.cs b/Source/Program.cs index 369b58c..21fddd3 100644 --- a/Source/Program.cs +++ b/Source/Program.cs @@ -5,6 +5,8 @@ using RaaLabs.Edge.Modules.EventHandling; using RaaLabs.Edge.Modules.EdgeHub; using RaaLabs.Edge.Modules.Configuration; +using RaaLabsDiagnostics = RaaLabs.Edge.Modules.Diagnostics.Diagnostics; + namespace RaaLabs.Edge.Connectors.OPCUA @@ -18,6 +20,7 @@ static void Main(string[] args) .WithModule() .WithModule() .WithModule() + .WithModule() .WithTask() .Build(); From ae7c57eae015c868e2a90485deaff017d5b94e2b Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 15:08:53 +0200 Subject: [PATCH 3/7] Add batch config --- Source/BatchConfiguration.cs | 23 +++++++++++++++++++++++ Source/IMetricsHandler.cs | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Source/BatchConfiguration.cs diff --git a/Source/BatchConfiguration.cs b/Source/BatchConfiguration.cs new file mode 100644 index 0000000..a0f26b8 --- /dev/null +++ b/Source/BatchConfiguration.cs @@ -0,0 +1,23 @@ +// Copyright (c) RaaLabs. All rights reserved. +// Licensed under the GPLv2 License. See LICENSE file in the project root for full license information. + +using System; +using System.Globalization; +using RaaLabs.Edge.Modules.EdgeHub; + +namespace RaaLabs.Edge.Connectors.OPCUA; + +/// +/// Config class for batching settings. +/// +public class BatchConfiguration : IEdgeHubOutgoingEventBatchConfiguration +{ + /// + /// The batch size. + /// + public int BatchSize { get; set; } = int.Parse(Environment.GetEnvironmentVariable("EDGEHUB_BATCH_SIZE") ?? "250", CultureInfo.CurrentCulture); + /// + /// The batch interval in milliseconds. + /// + public int Interval { get; set; } = int.Parse(Environment.GetEnvironmentVariable("EDGEHUB_BATCH_INTERVAL") ?? "5000", CultureInfo.CurrentCulture); +} diff --git a/Source/IMetricsHandler.cs b/Source/IMetricsHandler.cs index e029eb2..52c4bd6 100644 --- a/Source/IMetricsHandler.cs +++ b/Source/IMetricsHandler.cs @@ -1,5 +1,5 @@ // Copyright (c) RaaLabs. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed under the GPLv2 License. See LICENSE file in the project root for full license information. using System; using System.Globalization; From 9c2fd78acc372cff5017a9dcfff5b190769f32d1 Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 15:11:14 +0200 Subject: [PATCH 4/7] New namespace declaration --- Source/OpcuaClient.cs | 280 +++++++++++++++++------------------ Source/OpcuaConfiguration.cs | 25 ++-- Source/OpcuaConnector.cs | 183 ++++++++++++----------- Source/Program.cs | 27 ++-- 4 files changed, 256 insertions(+), 259 deletions(-) diff --git a/Source/OpcuaClient.cs b/Source/OpcuaClient.cs index c664921..5d53c94 100644 --- a/Source/OpcuaClient.cs +++ b/Source/OpcuaClient.cs @@ -11,185 +11,185 @@ using Opc.Ua.Client; using MoreLinq; -namespace RaaLabs.Edge.Connectors.OPCUA +namespace RaaLabs.Edge.Connectors.OPCUA; + +/// +/// OPC UA Client with only read functionality. +/// +class OpcuaClient { + private readonly OpcuaConfiguration _opcuaConfiguration; + private readonly ApplicationConfiguration _applicationConfiguration; + public Session Session { get; set; } + private readonly ILogger _logger; + private readonly Action _validateResponse; + /// - /// OPC UA Client with only read functionality. + /// Initializes a new instance of - class OpcuaClient + public OpcuaClient(ApplicationConfiguration applicationConfiguration, OpcuaConfiguration opcuaConfiguration, ILogger logger, Action validateResponse) { - private readonly OpcuaConfiguration _opcuaConfiguration; - private readonly ApplicationConfiguration _applicationConfiguration; - public Session Session { get; set; } - private readonly ILogger _logger; - private readonly Action _validateResponse; - - /// - /// Initializes a new instance of - public OpcuaClient(ApplicationConfiguration applicationConfiguration, OpcuaConfiguration opcuaConfiguration, ILogger logger, Action validateResponse) - { - _validateResponse = validateResponse; - _logger = logger; - _opcuaConfiguration = opcuaConfiguration; - _applicationConfiguration = applicationConfiguration; - _applicationConfiguration.CertificateValidator.CertificateValidation += CertificateValidation; - } + _validateResponse = validateResponse; + _logger = logger; + _opcuaConfiguration = opcuaConfiguration; + _applicationConfiguration = applicationConfiguration; + _applicationConfiguration.CertificateValidator.CertificateValidation += CertificateValidation; + } - /// - /// Creates a session with the UA server - /// - public async Task ConnectAsync() + /// + /// Creates a session with the UA server + /// + public async Task ConnectAsync() + { + try { - try + if (Session != null && Session.Connected) { - if (Session != null && Session.Connected) - { - _logger.Information("Session already connected!"); - } - else + _logger.Information("Session already connected!"); + } + else + { + _logger.Information("Connecting..."); + + EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(_opcuaConfiguration.ServerUrl, false); + EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(_applicationConfiguration); + ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration); + + Session opcuaSession = await Session.Create( + _applicationConfiguration, + endpoint, + false, + false, + _applicationConfiguration.ApplicationName, + 30 * 60 * 1000, + new UserIdentity(), + null + ); + + if (opcuaSession != null && opcuaSession.Connected) { - _logger.Information("Connecting..."); - - EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(_opcuaConfiguration.ServerUrl, false); - EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(_applicationConfiguration); - ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration); - - Session opcuaSession = await Session.Create( - _applicationConfiguration, - endpoint, - false, - false, - _applicationConfiguration.ApplicationName, - 30 * 60 * 1000, - new UserIdentity(), - null - ); - - if (opcuaSession != null && opcuaSession.Connected) - { - this.Session = opcuaSession; - } - - _logger.Information($"New Session Created with SessionName = {this.Session.SessionName}"); + this.Session = opcuaSession; } - return true; - } - catch (Exception ex) - { - _logger.Error($"Create Session Error : {ex.ToString()}"); - return false; + _logger.Information($"New Session Created with SessionName = {this.Session.SessionName}"); } + + return true; + } + catch (Exception ex) + { + _logger.Error($"Create Session Error : {ex.ToString()}"); + return false; } + } - /// - /// Disconnects the session. - /// - public void Disconnect() + /// + /// Disconnects the session. + /// + public void Disconnect() + { + try { - try + if (Session != null) { - if (Session != null) - { - _logger.Information("Disconnecting..."); + _logger.Information("Disconnecting..."); - Session.Close(); - Session.Dispose(); - Session = null; + Session.Close(); + Session.Dispose(); + Session = null; - _logger.Information("Session Disconnected."); - } - else - { - _logger.Information("Session not created!"); - } + _logger.Information("Session Disconnected."); } - catch (Exception ex) + else { - _logger.Information($"Disconnect Error : {ex.Message}"); + _logger.Information("Session not created!"); } } - - - /// - /// Read a list of nodes from Server - /// - public List ReadNodes(ReadValueIdCollection nodes) + catch (Exception ex) { - _logger.Information("Reading nodes..."); + _logger.Information($"Disconnect Error : {ex.Message}"); + } + } - Session.Read( - null, - 0, - TimestampsToReturn.Both, - nodes, - out DataValueCollection resultsValues, // DataValueCollection is ordered - out DiagnosticInfoCollection diagnosticInfos - ); - _validateResponse(resultsValues, nodes); + /// + /// Read a list of nodes from Server + /// + public List ReadNodes(ReadValueIdCollection nodes) + { + _logger.Information("Reading nodes..."); - var resultsValuesGroups = resultsValues.Batch(2); - List outputs = FormatOutput(resultsValuesGroups); + Session.Read( + null, + 0, + TimestampsToReturn.Both, + nodes, + out DataValueCollection resultsValues, // DataValueCollection is ordered + out DiagnosticInfoCollection diagnosticInfos + ); - return outputs; - } + _validateResponse(resultsValues, nodes); - /// - /// Handles the certificate validation event. - /// This event is triggered every time an untrusted certificate is received from the server. - /// - private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e) - { - bool certificateAccepted = true; + var resultsValuesGroups = resultsValues.Batch(2); + List outputs = FormatOutput(resultsValuesGroups); - // **** - // Implement a custom logic to decide if the certificate should be - // accepted or not and set certificateAccepted flag accordingly. - // The certificate can be retrieved from the e.Certificate field - // *** + return outputs; + } - ServiceResult error = e.Error; - while (error != null) - { - _logger.Information(error.ToString()); - error = error.InnerResult; - } + /// + /// Handles the certificate validation event. + /// This event is triggered every time an untrusted certificate is received from the server. + /// + private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e) + { + bool certificateAccepted = true; - if (certificateAccepted) - { - _logger.Information("Untrusted Certificate accepted. SubjectName = {0}", e.Certificate.SubjectName); - } + // **** + // Implement a custom logic to decide if the certificate should be + // accepted or not and set certificateAccepted flag accordingly. + // The certificate can be retrieved from the e.Certificate field + // *** - e.AcceptAll = certificateAccepted; + ServiceResult error = e.Error; + while (error != null) + { + _logger.Information(error.ToString()); + error = error.InnerResult; } - /// - /// Creates a List based on two ReadValueIds, one with the value and one with the nodeId. - /// - /// - /// - private static List FormatOutput(IEnumerable> resultsValuesGroups) + if (certificateAccepted) { - List datapoints = new List(); + _logger.Information("Untrusted Certificate accepted. SubjectName = {0}", e.Certificate.SubjectName); + } + e.AcceptAll = certificateAccepted; + } - foreach (var resultValueGroup in resultsValuesGroups) + /// + /// Creates a List based on two ReadValueIds, one with the value and one with the nodeId. + /// + /// + /// + private static List FormatOutput(IEnumerable> resultsValuesGroups) + { + List datapoints = new List(); + + + foreach (var resultValueGroup in resultsValuesGroups) + { + var opcuaDatapointOutput = new Events.OpcuaDatapointOutput { - var opcuaDatapointOutput = new Events.OpcuaDatapointOutput - { - Source = "OPCUA", - Tag = resultValueGroup.ElementAt(0).Value.ToString(), // this is the node id - Timestamp = ((DateTimeOffset)resultValueGroup.ElementAt(1).ServerTimestamp).ToUnixTimeMilliseconds(), - Value = resultValueGroup.ElementAt(1).Value.ToString() // this is the node value - }; + Source = "OPCUA", + Tag = resultValueGroup.ElementAt(0).Value.ToString(), // this is the node id + Timestamp = ((DateTimeOffset)resultValueGroup.ElementAt(1).ServerTimestamp).ToUnixTimeMilliseconds(), + Value = resultValueGroup.ElementAt(1).Value.ToString() // this is the node value + }; - datapoints.Add(opcuaDatapointOutput); - } - - return datapoints; + datapoints.Add(opcuaDatapointOutput); } + + return datapoints; } } + diff --git a/Source/OpcuaConfiguration.cs b/Source/OpcuaConfiguration.cs index 30dd023..722123d 100644 --- a/Source/OpcuaConfiguration.cs +++ b/Source/OpcuaConfiguration.cs @@ -5,20 +5,19 @@ using System.Diagnostics.CodeAnalysis; using RaaLabs.Edge.Modules.Configuration; -namespace RaaLabs.Edge.Connectors.OPCUA +namespace RaaLabs.Edge.Connectors.OPCUA; + +[Name("configuration.json")] +[RestartOnChange] +[ExcludeFromCodeCoverage] +public class OpcuaConfiguration : IConfiguration { - [Name("configuration.json")] - [RestartOnChange] - [ExcludeFromCodeCoverage] - public class OpcuaConfiguration : IConfiguration - { - public string ServerUrl { get; } - public ISet NodeIds { get; } + public string ServerUrl { get; } + public ISet NodeIds { get; } - public OpcuaConfiguration(string serverUrl, ISet nodeIds) - { - ServerUrl = serverUrl; - NodeIds = nodeIds; - } + public OpcuaConfiguration(string serverUrl, ISet nodeIds) + { + ServerUrl = serverUrl; + NodeIds = nodeIds; } } diff --git a/Source/OpcuaConnector.cs b/Source/OpcuaConnector.cs index a0371fd..c898125 100644 --- a/Source/OpcuaConnector.cs +++ b/Source/OpcuaConnector.cs @@ -11,121 +11,120 @@ using RaaLabs.Edge.Modules.EventHandling; -namespace RaaLabs.Edge.Connectors.OPCUA +namespace RaaLabs.Edge.Connectors.OPCUA; + +/// +/// Represents an implementation for +/// +public class OpcuaConnector : IRunAsync, IProduceEvent { /// - /// Represents an implementation for + /// + /// + public event EventEmitter SendDatapoint; + private OpcuaClient _opcuaClient; + private readonly ReadValueIdCollection _nodesToRead; + private readonly ApplicationInstance _opcuaAppInstance; + private readonly ILogger _logger; + private readonly OpcuaConfiguration _opcuaConfiguration; + private readonly IMetricsHandler _metricsHandler; + + + /// + /// Initializes a new instance of /// - public class OpcuaConnector : IRunAsync, IProduceEvent + /// for logging + public OpcuaConnector(ILogger logger, OpcuaConfiguration opcuaConfiguration, IMetricsHandler metricsHandler) { - /// - /// - /// - public event EventEmitter SendDatapoint; - private OpcuaClient _opcuaClient; - private readonly ReadValueIdCollection _nodesToRead; - private readonly ApplicationInstance _opcuaAppInstance; - private readonly ILogger _logger; - private readonly OpcuaConfiguration _opcuaConfiguration; - private readonly IMetricsHandler _metricsHandler; - - - /// - /// Initializes a new instance of - /// - /// for logging - public OpcuaConnector(ILogger logger, OpcuaConfiguration opcuaConfiguration, IMetricsHandler metricsHandler) + _logger = logger; + _opcuaConfiguration = opcuaConfiguration; + _metricsHandler = metricsHandler; + + var securityConfig = new SecurityConfiguration() { - _logger = logger; - _opcuaConfiguration = opcuaConfiguration; - _metricsHandler = metricsHandler; + AutoAcceptUntrustedCertificates = true // ONLY for debugging/early dev + }; - var securityConfig = new SecurityConfiguration() - { - AutoAcceptUntrustedCertificates = true // ONLY for debugging/early dev - }; + var config = new ApplicationConfiguration() + { + ApplicationName = "Raa Labs OPC UA connector", + ApplicationUri = "Raa Labs OPC UA connector", + ApplicationType = ApplicationType.Client, + TransportConfigurations = new TransportConfigurationCollection(), + TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, + ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }, + TraceConfiguration = new TraceConfiguration(), + SecurityConfiguration = securityConfig + }; + + _opcuaAppInstance = new ApplicationInstance() + { + ApplicationName = "Raa Labs OPC UA connector", + ApplicationType = ApplicationType.Client, + ApplicationConfiguration = config + }; - var config = new ApplicationConfiguration() - { - ApplicationName = "Raa Labs OPC UA connector", - ApplicationUri = "Raa Labs OPC UA connector", - ApplicationType = ApplicationType.Client, - TransportConfigurations = new TransportConfigurationCollection(), - TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, - ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }, - TraceConfiguration = new TraceConfiguration(), - SecurityConfiguration = securityConfig - }; - - _opcuaAppInstance = new ApplicationInstance() - { - ApplicationName = "Raa Labs OPC UA connector", - ApplicationType = ApplicationType.Client, - ApplicationConfiguration = config - }; + _nodesToRead = InitializeReadValueIdCollection(); + } - _nodesToRead = InitializeReadValueIdCollection(); + private ReadValueIdCollection InitializeReadValueIdCollection() + { + ReadValueIdCollection nodesToRead = new ReadValueIdCollection(){}; + foreach (var nodeId in _opcuaConfiguration.NodeIds) + { + // Because nodeId and value cannot be read using the same ReadValueId, but nodeId and value are required + nodesToRead.Add(new ReadValueId() { NodeId = nodeId, AttributeId = Attributes.NodeId }); + nodesToRead.Add(new ReadValueId() { NodeId = nodeId, AttributeId = Attributes.Value }); } - private ReadValueIdCollection InitializeReadValueIdCollection() - { - ReadValueIdCollection nodesToRead = new ReadValueIdCollection(){}; - foreach (var nodeId in _opcuaConfiguration.NodeIds) - { - // Because nodeId and value cannot be read using the same ReadValueId, but nodeId and value are required - nodesToRead.Add(new ReadValueId() { NodeId = nodeId, AttributeId = Attributes.NodeId }); - nodesToRead.Add(new ReadValueId() { NodeId = nodeId, AttributeId = Attributes.Value }); - } + return nodesToRead; + } - return nodesToRead; - } + public async Task Run() + { + _logger.Information("Raa Labs OPC UA connector"); + _opcuaClient = new OpcuaClient(_opcuaAppInstance.ApplicationConfiguration, _opcuaConfiguration, _logger, ClientBase.ValidateResponse); + await _opcuaClient.ConnectAsync(); - public async Task Run() + while (true) { - _logger.Information("Raa Labs OPC UA connector"); - _opcuaClient = new OpcuaClient(_opcuaAppInstance.ApplicationConfiguration, _opcuaConfiguration, _logger, ClientBase.ValidateResponse); - await _opcuaClient.ConnectAsync(); - - while (true) - { - var policy = Policy - .Handle() - .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(Math.Min(Math.Pow(2, retryAttempt), 3600)), - (exception, timeSpan, context) => - { - _logger.Error(exception, $"OPC UA connector threw an exception during connect - retrying"); - }); - - await policy.ExecuteAsync(async () => + var policy = Policy + .Handle() + .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(Math.Min(Math.Pow(2, retryAttempt), 3600)), + (exception, timeSpan, context) => { - await ConnectOpcua(); + _logger.Error(exception, $"OPC UA connector threw an exception during connect - retrying"); }); - await Task.Delay(1000); - } + await policy.ExecuteAsync(async () => + { + await ConnectOpcua(); + }); + + await Task.Delay(1000); } + } - private async Task ConnectOpcua() + private async Task ConnectOpcua() + { + try { - try + if (!_opcuaClient.Session.Connected) { - if (!_opcuaClient.Session.Connected) - { - await _opcuaClient.ConnectAsync(); - } + await _opcuaClient.ConnectAsync(); + } - List opcuaDatapoints = _opcuaClient.ReadNodes(_nodesToRead); + List opcuaDatapoints = _opcuaClient.ReadNodes(_nodesToRead); - foreach (var opcuaDatapoint in opcuaDatapoints) - { - SendDatapoint(opcuaDatapoint); - _metricsHandler.NumberOfMessagesSent(1); - } - } - catch (Exception ex) + foreach (var opcuaDatapoint in opcuaDatapoints) { - _logger.Information(ex.ToString()); + SendDatapoint(opcuaDatapoint); + _metricsHandler.NumberOfMessagesSent(1); } } + catch (Exception ex) + { + _logger.Information(ex.ToString()); + } } -} \ No newline at end of file +} diff --git a/Source/Program.cs b/Source/Program.cs index 21fddd3..9200bfa 100644 --- a/Source/Program.cs +++ b/Source/Program.cs @@ -9,22 +9,21 @@ -namespace RaaLabs.Edge.Connectors.OPCUA +namespace RaaLabs.Edge.Connectors.OPCUA; + +[ExcludeFromCodeCoverage] +static class Program { - [ExcludeFromCodeCoverage] - static class Program + static void Main(string[] args) { - static void Main(string[] args) - { - var application = new ApplicationBuilder() - .WithModule() - .WithModule() - .WithModule() - .WithModule() - .WithTask() - .Build(); + var application = new ApplicationBuilder() + .WithModule() + .WithModule() + .WithModule() + .WithModule() + .WithTask() + .Build(); - application.Run().Wait(); - } + application.Run().Wait(); } } From 706df09c86968026838d3b9325e282fe36c0c1bd Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 15:16:05 +0200 Subject: [PATCH 5/7] Update workflows --- .github/workflows/dotnet.yml | 12 ++++++------ .github/workflows/sonarcloud.yml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 967725c..73304e4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -1,8 +1,8 @@ -name: .NET 5.0 +name: .NET env: PRERELEASE_BRANCHES: experimental,alpha,beta,rc - DOCKER_HUB_REPO: raaedge.azurecr.io/connectors-opcua + DOCKER_HUB_REPO: ${{ secrets.RAAEDGE_LOGIN_SERVER }}/connectors-opcua COVERAGE_FOLDER: Coverage on: @@ -23,13 +23,13 @@ jobs: cascading-release: ${{ steps.context.outputs.cascading-release }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '5.0.x' + dotnet-version: '7.0.x' - name: Install dependencies run: dotnet restore --no-cache --verbosity normal - name: Build @@ -72,7 +72,7 @@ jobs: docker push ${{ env.DOCKER_HUB_REPO }}:latest - name: Create GitHub Release - uses: dolittle/github-release-action@v1 + uses: dolittle/github-release-action@v2 if: ${{ steps.context.outputs.should-publish == 'true' }} with: cascading-release: ${{ steps.context.outputs.cascading-release }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 7077d22..23fc183 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -21,13 +21,13 @@ jobs: cascading-release: ${{ steps.context.outputs.cascading-release }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '5.0.x' + dotnet-version: '7.0.x' - name: Install dependencies run: dotnet restore --no-cache --verbosity normal - name: Build @@ -36,10 +36,10 @@ jobs: run: dotnet test --configuration Release --no-build /p:CollectCoverage=true /p:CoverletOutput=${{ github.workspace }}/${{ env.COVERAGE_FOLDER }}/ /p:MergeWith=${{ github.workspace }}/${{ env.COVERAGE_FOLDER }}/coverage/ /p:CoverletOutputFormat=opencover - name: SonarScanner for .NET Core with pull request decoration support - uses: highbyte/sonarscan-dotnet@2.0 + uses: highbyte/sonarscan-dotnet@2.2.1 with: sonarProjectKey: RaaLabs_${{ github.event.repository.name }} - sonarProjectName: ${{ github.event.repository.name }} + sonarProjectName: ${{ github.event.repository.name }} sonarOrganization: raalabs dotnetTestArguments: --logger trx --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover - sonarBeginArguments: /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" -d:sonar.cs.vstest.reportsPaths="**/TestResults/*.trx" + sonarBeginArguments: /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" -d:sonar.cs.vstest.reportsPaths="**/TestResults/*.trx" From 714ffa3ffaa355cdcb48aa3845600ba72c794348 Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 15:17:16 +0200 Subject: [PATCH 6/7] Tripped over the v, again ... --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 23fc183..4781201 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -36,7 +36,7 @@ jobs: run: dotnet test --configuration Release --no-build /p:CollectCoverage=true /p:CoverletOutput=${{ github.workspace }}/${{ env.COVERAGE_FOLDER }}/ /p:MergeWith=${{ github.workspace }}/${{ env.COVERAGE_FOLDER }}/coverage/ /p:CoverletOutputFormat=opencover - name: SonarScanner for .NET Core with pull request decoration support - uses: highbyte/sonarscan-dotnet@2.2.1 + uses: highbyte/sonarscan-dotnet@v2.2.1 with: sonarProjectKey: RaaLabs_${{ github.event.repository.name }} sonarProjectName: ${{ github.event.repository.name }} From ffa6b45ad0b461da20383ca904209892f8eb3b1b Mon Sep 17 00:00:00 2001 From: Rafael Schlatter Date: Thu, 20 Apr 2023 20:15:38 +0200 Subject: [PATCH 7/7] Update nugets --- Source/OPCUA.csproj | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Source/OPCUA.csproj b/Source/OPCUA.csproj index 7d0c904..55833b9 100644 --- a/Source/OPCUA.csproj +++ b/Source/OPCUA.csproj @@ -17,12 +17,10 @@ - - - - - - - + + + + + \ No newline at end of file