Change log system

This commit is contained in:
luosheng
2023-03-01 09:36:07 +08:00
parent 46222348be
commit a8c9fefbce
80 changed files with 2227 additions and 1921 deletions

View File

@@ -1,100 +1,100 @@
using System.Linq;
using Opc.Ua;
using System;
using Opc.Ua;
using Opc.Ua.Client;
using System;
using System.Linq;
namespace Hylasoft.Opc.Ua
{
/// <summary>
/// List of static utility methods
/// </summary>
internal static class ClientUtils
{
// TODO I didn't write these methods. I should rewrite it once I understand whtat it does, beacuse it looks crazy
public static EndpointDescription SelectEndpoint(Uri discoveryUrl, bool useSecurity)
/// <summary>
/// List of static utility methods
/// </summary>
internal static class ClientUtils
{
var configuration = EndpointConfiguration.Create();
configuration.OperationTimeout = 5000;
EndpointDescription endpointDescription1 = null;
using (var discoveryClient = DiscoveryClient.Create(discoveryUrl, configuration))
{
var endpoints = discoveryClient.GetEndpoints(null);
foreach (var endpointDescription2 in endpoints.Where(endpointDescription2 => endpointDescription2.EndpointUrl.StartsWith(discoveryUrl.Scheme)))
{
if (useSecurity)
{
if (endpointDescription2.SecurityMode == MessageSecurityMode.None)
continue;
}
else if (endpointDescription2.SecurityMode != MessageSecurityMode.None)
continue;
if (endpointDescription1 == null)
endpointDescription1 = endpointDescription2;
if (endpointDescription2.SecurityLevel > endpointDescription1.SecurityLevel)
endpointDescription1 = endpointDescription2;
}
if (endpointDescription1 == null)
{
if (endpoints.Count > 0)
endpointDescription1 = endpoints[0];
}
}
var uri = Utils.ParseUri(endpointDescription1.EndpointUrl);
if (uri != null && uri.Scheme == discoveryUrl.Scheme)
endpointDescription1.EndpointUrl = new UriBuilder(uri)
{
Host = discoveryUrl.DnsSafeHost,
Port = discoveryUrl.Port
}.ToString();
return endpointDescription1;
}
// TODO I didn't write these methods. I should rewrite it once I understand whtat it does, beacuse it looks crazy
public static ReferenceDescriptionCollection Browse(Session session, NodeId nodeId)
{
var desc = new BrowseDescription
{
NodeId = nodeId,
BrowseDirection = BrowseDirection.Forward,
IncludeSubtypes = true,
NodeClassMask = 0U,
ResultMask = 63U,
};
return Browse(session, desc, true);
}
public static ReferenceDescriptionCollection Browse(Session session, BrowseDescription nodeToBrowse, bool throwOnError)
{
try
{
var descriptionCollection = new ReferenceDescriptionCollection();
var nodesToBrowse = new BrowseDescriptionCollection { nodeToBrowse };
BrowseResultCollection results;
DiagnosticInfoCollection diagnosticInfos;
session.Browse(null, null, 0U, nodesToBrowse, out results, out diagnosticInfos);
ClientBase.ValidateResponse(results, nodesToBrowse);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToBrowse);
while (!StatusCode.IsBad(results[0].StatusCode))
public static EndpointDescription SelectEndpoint(Uri discoveryUrl, bool useSecurity)
{
for (var index = 0; index < results[0].References.Count; ++index)
descriptionCollection.Add(results[0].References[index]);
if (results[0].References.Count == 0 || results[0].ContinuationPoint == null)
return descriptionCollection;
var continuationPoints = new ByteStringCollection();
continuationPoints.Add(results[0].ContinuationPoint);
session.BrowseNext(null, false, continuationPoints, out results, out diagnosticInfos);
ClientBase.ValidateResponse(results, continuationPoints);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints);
var configuration = EndpointConfiguration.Create();
configuration.OperationTimeout = 5000;
EndpointDescription endpointDescription1 = null;
using (var discoveryClient = DiscoveryClient.Create(discoveryUrl, configuration))
{
var endpoints = discoveryClient.GetEndpoints(null);
foreach (var endpointDescription2 in endpoints.Where(endpointDescription2 => endpointDescription2.EndpointUrl.StartsWith(discoveryUrl.Scheme)))
{
if (useSecurity)
{
if (endpointDescription2.SecurityMode == MessageSecurityMode.None)
continue;
}
else if (endpointDescription2.SecurityMode != MessageSecurityMode.None)
continue;
if (endpointDescription1 == null)
endpointDescription1 = endpointDescription2;
if (endpointDescription2.SecurityLevel > endpointDescription1.SecurityLevel)
endpointDescription1 = endpointDescription2;
}
if (endpointDescription1 == null)
{
if (endpoints.Count > 0)
endpointDescription1 = endpoints[0];
}
}
var uri = Utils.ParseUri(endpointDescription1.EndpointUrl);
if (uri != null && uri.Scheme == discoveryUrl.Scheme)
endpointDescription1.EndpointUrl = new UriBuilder(uri)
{
Host = discoveryUrl.DnsSafeHost,
Port = discoveryUrl.Port
}.ToString();
return endpointDescription1;
}
public static ReferenceDescriptionCollection Browse(Session session, NodeId nodeId)
{
var desc = new BrowseDescription
{
NodeId = nodeId,
BrowseDirection = BrowseDirection.Forward,
IncludeSubtypes = true,
NodeClassMask = 0U,
ResultMask = 63U,
};
return Browse(session, desc, true);
}
public static ReferenceDescriptionCollection Browse(Session session, BrowseDescription nodeToBrowse, bool throwOnError)
{
try
{
var descriptionCollection = new ReferenceDescriptionCollection();
var nodesToBrowse = new BrowseDescriptionCollection { nodeToBrowse };
BrowseResultCollection results;
DiagnosticInfoCollection diagnosticInfos;
session.Browse(null, null, 0U, nodesToBrowse, out results, out diagnosticInfos);
ClientBase.ValidateResponse(results, nodesToBrowse);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToBrowse);
while (!StatusCode.IsBad(results[0].StatusCode))
{
for (var index = 0; index < results[0].References.Count; ++index)
descriptionCollection.Add(results[0].References[index]);
if (results[0].References.Count == 0 || results[0].ContinuationPoint == null)
return descriptionCollection;
var continuationPoints = new ByteStringCollection();
continuationPoints.Add(results[0].ContinuationPoint);
session.BrowseNext(null, false, continuationPoints, out results, out diagnosticInfos);
ClientBase.ValidateResponse(results, continuationPoints);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints);
}
throw new ServiceResultException(results[0].StatusCode);
}
catch (Exception ex)
{
if (throwOnError)
throw new ServiceResultException(ex, 2147549184U);
return null;
}
}
throw new ServiceResultException(results[0].StatusCode);
}
catch (Exception ex)
{
if (throwOnError)
throw new ServiceResultException(ex, 2147549184U);
return null;
}
}
}
}

View File

@@ -2,33 +2,33 @@
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Useful extension methods for OPC Clients
/// </summary>
public static class ClientExtensions
{
/// <summary>
/// Reads a tag from the OPC. If for whatever reason the read fails (Tag doesn't exist, server not available) returns a default value
/// Useful extension methods for OPC Clients
/// </summary>
/// <param name="client">the opc client to use for the read</param>
/// <param name="tag">The fully qualified identifier of the tag</param>
/// <param name="defaultValue">the default value to read if the read fails</param>
/// <returns></returns>
public static ReadEvent<T> ReadOrdefault<T>(this IClient<Node> client, string tag, T defaultValue = default(T))
public static class ClientExtensions
{
try
{
return client.Read<T>(tag);
}
catch (OpcException)
{
var readEvent = new ReadEvent<T>();
readEvent.Quality = Quality.Good;
readEvent.Value = defaultValue;
readEvent.SourceTimestamp = DateTime.Now;
readEvent.ServerTimestamp = DateTime.Now;
return readEvent;
}
/// <summary>
/// Reads a tag from the OPC. If for whatever reason the read fails (Tag doesn't exist, server not available) returns a default value
/// </summary>
/// <param name="client">the opc client to use for the read</param>
/// <param name="tag">The fully qualified identifier of the tag</param>
/// <param name="defaultValue">the default value to read if the read fails</param>
/// <returns></returns>
public static ReadEvent<T> ReadOrdefault<T>(this IClient<Node> client, string tag, T defaultValue = default(T))
{
try
{
return client.Read<T>(tag);
}
catch (OpcException)
{
var readEvent = new ReadEvent<T>();
readEvent.Quality = Quality.Good;
readEvent.Value = defaultValue;
readEvent.SourceTimestamp = DateTime.Now;
readEvent.ServerTimestamp = DateTime.Now;
return readEvent;
}
}
}
}
}

View File

@@ -4,100 +4,100 @@ using System.Threading.Tasks;
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Client interface to perform basic Opc tasks, like discovery, monitoring, reading/writing tags,
/// </summary>
public interface IClient<out TNode> : IDisposable
/// <summary>
/// Client interface to perform basic Opc tasks, like discovery, monitoring, reading/writing tags,
/// </summary>
public interface IClient<out TNode> : IDisposable
where TNode : Node
{
/// <summary>
/// Connect the client to the OPC Server
/// </summary>
Task Connect();
{
/// <summary>
/// Connect the client to the OPC Server
/// </summary>
Task Connect();
/// <summary>
/// Gets the current status of the OPC Client
/// </summary>
OpcStatus Status { get; }
/// <summary>
/// Gets the current status of the OPC Client
/// </summary>
OpcStatus Status { get; }
/// <summary>
/// Gets the datatype of an OPC tag
/// </summary>
/// <param name="tag">Tag to get datatype of</param>
/// <returns>System Type</returns>
System.Type GetDataType(string tag);
/// <summary>
/// Gets the datatype of an OPC tag
/// </summary>
/// <param name="tag">Tag to get datatype of</param>
/// <returns>System Type</returns>
System.Type GetDataType(string tag);
/// <summary>
/// Read a tag
/// </summary>
/// <typeparam name="T">The type of tag to read</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` reads the tag `bar` on the folder `foo`</param>
/// <returns>The value retrieved from the OPC</returns>
ReadEvent<T> Read<T>(string tag);
/// <summary>
/// Read a tag
/// </summary>
/// <typeparam name="T">The type of tag to read</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` reads the tag `bar` on the folder `foo`</param>
/// <returns>The value retrieved from the OPC</returns>
ReadEvent<T> Read<T>(string tag);
/// <summary>
/// Write a value on the specified opc tag
/// </summary>
/// <typeparam name="T">The type of tag to write on</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo`</param>
/// <param name="item"></param>
void Write<T>(string tag, T item);
/// <summary>
/// Write a value on the specified opc tag
/// </summary>
/// <typeparam name="T">The type of tag to write on</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo`</param>
/// <param name="item"></param>
void Write<T>(string tag, T item);
/// <summary>
/// Monitor the specified tag for changes
/// </summary>
/// <typeparam name="T">the type of tag to monitor</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` monitors the tag `bar` on the folder `foo`</param>
/// <param name="callback">the callback to execute when the value is changed.
/// The first parameter is the new value of the node, the second is an `unsubscribe` function to unsubscribe the callback</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")]
void Monitor<T>(string tag, Action<ReadEvent<T>, Action> callback);
/// <summary>
/// Monitor the specified tag for changes
/// </summary>
/// <typeparam name="T">the type of tag to monitor</typeparam>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` monitors the tag `bar` on the folder `foo`</param>
/// <param name="callback">the callback to execute when the value is changed.
/// The first parameter is the new value of the node, the second is an `unsubscribe` function to unsubscribe the callback</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")]
void Monitor<T>(string tag, Action<ReadEvent<T>, Action> callback);
/// <summary>
/// Finds a node on the Opc Server
/// </summary>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` finds the tag `bar` on the folder `foo`</param>
/// <returns>If there is a tag, it returns it, otherwise it throws an </returns>
TNode FindNode(string tag);
/// <summary>
/// Finds a node on the Opc Server
/// </summary>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` finds the tag `bar` on the folder `foo`</param>
/// <returns>If there is a tag, it returns it, otherwise it throws an </returns>
TNode FindNode(string tag);
/// <summary>
/// Gets the root node of the server
/// </summary>
TNode RootNode { get; }
/// <summary>
/// Gets the root node of the server
/// </summary>
TNode RootNode { get; }
/// <summary>
/// Explore a folder on the Opc Server
/// </summary>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` finds the sub nodes of `bar` on the folder `foo`</param>
/// <returns>The list of sub-nodes</returns>
IEnumerable<TNode> ExploreFolder(string tag);
/// <summary>
/// Explore a folder on the Opc Server
/// </summary>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` finds the sub nodes of `bar` on the folder `foo`</param>
/// <returns>The list of sub-nodes</returns>
IEnumerable<TNode> ExploreFolder(string tag);
/// <summary>
/// Read a tag asynchronusly
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")]
Task<ReadEvent<T>> ReadAsync<T>(string tag);
/// <summary>
/// Read a tag asynchronusly
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")]
Task<ReadEvent<T>> ReadAsync<T>(string tag);
/// <summary>
/// Write a value on the specified opc tag asynchronously
/// </summary>
Task WriteAsync<T>(string tag, T item);
/// <summary>
/// Write a value on the specified opc tag asynchronously
/// </summary>
Task WriteAsync<T>(string tag, T item);
/// <summary>
/// Finds a node on the Opc Server asynchronously
/// </summary>
Task<Node> FindNodeAsync(string tag);
/// <summary>
/// Finds a node on the Opc Server asynchronously
/// </summary>
Task<Node> FindNodeAsync(string tag);
/// <summary>
/// Explore a folder on the Opc Server asynchronously
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
Justification = "Task")]
Task<IEnumerable<Node>> ExploreFolderAsync(string tag);
}
/// <summary>
/// Explore a folder on the Opc Server asynchronously
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
Justification = "Task")]
Task<IEnumerable<Node>> ExploreFolderAsync(string tag);
}
}

View File

@@ -1,48 +1,46 @@
using System.Collections.Generic;
namespace Hylasoft.Opc.Common
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Base class representing a node on the OPC server
/// </summary>
public abstract class Node
{
/// <summary>
/// Gets the displayed name of the node
/// Base class representing a node on the OPC server
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// Gets the dot-separated fully qualified tag of the node
/// </summary>
public string Tag { get; protected set; }
/// <summary>
/// Gets the parent node. If the node is root, returns null
/// </summary>
public Node Parent { get; private set; }
/// <summary>
/// Creates a new node
/// </summary>
/// <param name="name">the name of the node</param>
/// <param name="parent">The parent node</param>
protected Node(string name, Node parent = null)
public abstract class Node
{
Name = name;
Parent = parent;
if (parent != null && !string.IsNullOrEmpty(parent.Tag))
Tag = parent.Tag + '.' + name;
else
Tag = name;
}
/// <summary>
/// Gets the displayed name of the node
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// Overrides ToString()
/// </summary>
public override string ToString()
{
return Tag;
/// <summary>
/// Gets the dot-separated fully qualified tag of the node
/// </summary>
public string Tag { get; protected set; }
/// <summary>
/// Gets the parent node. If the node is root, returns null
/// </summary>
public Node Parent { get; private set; }
/// <summary>
/// Creates a new node
/// </summary>
/// <param name="name">the name of the node</param>
/// <param name="parent">The parent node</param>
protected Node(string name, Node parent = null)
{
Name = name;
Parent = parent;
if (parent != null && !string.IsNullOrEmpty(parent.Tag))
Tag = parent.Tag + '.' + name;
else
Tag = name;
}
/// <summary>
/// Overrides ToString()
/// </summary>
public override string ToString()
{
return Tag;
}
}
}
}

View File

@@ -4,67 +4,67 @@ using System.Runtime.Serialization;
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Identifies an exception occurred during OPC Communication
/// </summary>
[Serializable]
public class OpcException : Exception
{
/// <summary>
/// Initialize a new instance of the OpcException class
/// Identifies an exception occurred during OPC Communication
/// </summary>
public OpcException()
[Serializable]
public class OpcException : Exception
{
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException()
{
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message)
: base(message)
{
}
/// <summary>
/// Returns an (optional) associated OPC UA StatusCode for the exception.
/// </summary>
public StatusCode? Status { get; private set; }
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message, StatusCode status)
: base(message)
{
Status = status;
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message, Exception inner)
: base(message, inner)
{
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
protected OpcException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Sets the System.Runtime.Serialization.SerializationInfo with information about the exception.
/// </summary>
/// <param name="info">The System.Runtime.Serialization.SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The System.Runtime.Serialization.StreamingContext that contains contextual information about the source or destination.</param>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message)
: base(message)
{
}
/// <summary>
/// Returns an (optional) associated OPC UA StatusCode for the exception.
/// </summary>
public StatusCode? Status { get; private set; }
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message, StatusCode status)
: base(message)
{
Status = status;
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
public OpcException(string message, Exception inner)
: base(message, inner)
{
}
/// <summary>
/// Initialize a new instance of the OpcException class
/// </summary>
protected OpcException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Sets the System.Runtime.Serialization.SerializationInfo with information about the exception.
/// </summary>
/// <param name="info">The System.Runtime.Serialization.SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The System.Runtime.Serialization.StreamingContext that contains contextual information about the source or destination.</param>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
}
}

View File

@@ -1,18 +1,18 @@
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Identifies the status of an OPC connector
/// </summary>
public enum OpcStatus
{
/// <summary>
/// The client is not connected
/// Identifies the status of an OPC connector
/// </summary>
NotConnected,
public enum OpcStatus
{
/// <summary>
/// The client is not connected
/// </summary>
NotConnected,
/// <summary>
/// The client is connected
/// </summary>
Connected
}
/// <summary>
/// The client is connected
/// </summary>
Connected
}
}

View File

@@ -2,27 +2,27 @@
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Represents the quality of the value captured
/// </summary>
public enum Quality
{
/// <summary>
/// Quality: Unknown, the value of the quality could not be inferred by the library
/// Represents the quality of the value captured
/// </summary>
[Description("Unknown")]
Unknown,
public enum Quality
{
/// <summary>
/// Quality: Unknown, the value of the quality could not be inferred by the library
/// </summary>
[Description("Unknown")]
Unknown,
/// <summary>
/// Quality: Good
/// </summary>
[Description("Good")]
Good,
/// <summary>
/// Quality: Good
/// </summary>
[Description("Good")]
Good,
/// <summary>
/// Quality: Bad
/// </summary>
[Description("Bad")]
Bad
}
/// <summary>
/// Quality: Bad
/// </summary>
[Description("Bad")]
Bad
}
}

View File

@@ -1,37 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hylasoft.Opc.Common
{
/// <summary>
/// Base class representing a monitor event on the OPC server
/// </summary>
/// <typeparam name="T"></typeparam>
public class ReadEvent<T>
{
/// <summary>
/// Gets the value that was read from the server
/// Base class representing a monitor event on the OPC server
/// </summary>
public T Value { get; set; }
/// <typeparam name="T"></typeparam>
public class ReadEvent<T>
{
/// <summary>
/// Gets the value that was read from the server
/// </summary>
public T Value { get; set; }
/// <summary>
/// Gets the quality of the signal from the server
/// </summary>
[DefaultValue(Common.Quality.Unknown)]
public Quality Quality { get; set; }
/// <summary>
/// Gets the quality of the signal from the server
/// </summary>
[DefaultValue(Common.Quality.Unknown)]
public Quality Quality { get; set; }
/// <summary>
/// Gets the source timestamp on when the event ocurred
/// </summary>
public DateTime SourceTimestamp { get; set; }
/// <summary>
/// Gets the source timestamp on when the event ocurred
/// </summary>
public DateTime SourceTimestamp { get; set; }
/// <summary>
/// Gets the server timestamp on when the event ocurred
/// </summary>
public DateTime ServerTimestamp { get; set; }
}
/// <summary>
/// Gets the server timestamp on when the event ocurred
/// </summary>
public DateTime ServerTimestamp { get; set; }
}
}

View File

@@ -3,22 +3,22 @@ using OpcF = Opc.Ua;
namespace Hylasoft.Opc.Ua
{
/// <summary>
/// Class with extension methods for OPC UA
/// </summary>
public static class NodeExtensions
{
/// <summary>
/// Converts an OPC Foundation node to an Hylasoft OPC UA Node
/// Class with extension methods for OPC UA
/// </summary>
/// <param name="node">The node to convert</param>
/// <param name="parent">the parent node (optional)</param>
/// <returns></returns>
internal static UaNode ToHylaNode(this OpcF.ReferenceDescription node, Node parent = null)
public static class NodeExtensions
{
var name = node.DisplayName.ToString();
var nodeId = node.NodeId.ToString();
return new UaNode(name, nodeId, parent);
/// <summary>
/// Converts an OPC Foundation node to an Hylasoft OPC UA Node
/// </summary>
/// <param name="node">The node to convert</param>
/// <param name="parent">the parent node (optional)</param>
/// <returns></returns>
internal static UaNode ToHylaNode(this OpcF.ReferenceDescription node, Node parent = null)
{
var name = node.DisplayName.ToString();
var nodeId = node.NodeId.ToString();
return new UaNode(name, nodeId, parent);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,121 +1,120 @@
using System;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.X509Certificates;
using OpcUa = Opc.Ua;
namespace Hylasoft.Opc.Ua
{
/// <summary>
/// This class defines the configuration options for the setup of the UA client session
/// </summary>
public class UaClientOptions
{
/// <summary>
/// Specifies the (optional) certificate for the application to connect to the server
/// This class defines the configuration options for the setup of the UA client session
/// </summary>
public X509Certificate2 ApplicationCertificate { get; set; }
/// <summary>
/// Specifies the ApplicationName for the client application.
/// </summary>
public string ApplicationName { get; set; }
/// <summary>
/// Should untrusted certificates be silently accepted by the client?
/// </summary>
public bool AutoAcceptUntrustedCertificates { get; set; }
/// <summary>
/// Specifies the ConfigSectionName for the client configuration.
/// </summary>
public string ConfigSectionName { get; set; }
/// <summary>
/// default monitor interval in Milliseconds.
/// </summary>
public int DefaultMonitorInterval { get; set; }
/// <summary>
/// Specifies a name to be associated with the created sessions.
/// </summary>
public string SessionName { get; set; }
/// <summary>
/// Specifies the timeout for the sessions.
/// </summary>
public uint SessionTimeout { get; set; }
/// <summary>
/// Specify whether message exchange should be secured.
/// </summary>
public bool UseMessageSecurity { get; set; }
/// <summary>
/// The maximum number of notifications per publish request.
/// The clients responsibility is to send PublishRequests to the server,
/// in order to enable the server to send PublishResponses back.
/// The PublishResponses are used to deliver the notifications: but if there
/// are no PublishRequests, the server cannot send a notification to the client.
/// The server will also verify that the client is alive by checking that
/// new PublishRequests are received LifeTimeCount defines the number of
/// PublishingIntervals to wait for a new PublishRequest, before realizing
/// that the client is no longer active.The Subscription is then removed from
/// the server.
/// </summary>
public uint SubscriptionLifetimeCount { get; set; }
/// <summary>
/// If there is no data to send after the next PublishingInterval,
/// the server will skip it. But KeepAlive defines how many intervals may be skipped,
/// before an empty notification is sent anyway: to give the client a hint that
/// the subscription is still alive in the server and that there just has not been
/// any data arriving to the client.
/// </summary>
public uint SubscriptionKeepAliveCount { get; set; }
/// <summary>
/// Gets or sets the max subscription count.
/// </summary>
public int MaxSubscriptionCount { get; set; }
/// <summary>
/// The maximum number of messages saved in the queue for each subscription.
/// </summary>
public int MaxMessageQueueSize { get; set; }
/// <summary>
/// The maximum number of notificates saved in the queue for each monitored item.
/// </summary>
public int MaxNotificationQueueSize { get; set; }
/// <summary>
/// Gets or sets the max publish request count.
/// </summary>
public int MaxPublishRequestCount { get; set; }
/// <summary>
/// The identity to connect to the OPC server as
/// </summary>
public OpcUa.UserIdentity UserIdentity { get; set; }
/// <summary>
/// Creates a client options object
/// </summary>
public UaClientOptions()
public class UaClientOptions
{
// Initialize default values:
ApplicationName = "h-opc-client";
AutoAcceptUntrustedCertificates = true;
ConfigSectionName = "h-opc-client";
DefaultMonitorInterval = 100;
SessionName = "h-opc-client";
SessionTimeout = 60000U;
UseMessageSecurity = false;
SubscriptionLifetimeCount = 0;
SubscriptionKeepAliveCount = 0;
MaxSubscriptionCount = 100;
MaxMessageQueueSize = 10;
MaxNotificationQueueSize = 100;
MaxPublishRequestCount = 20;
/// <summary>
/// Specifies the (optional) certificate for the application to connect to the server
/// </summary>
public X509Certificate2 ApplicationCertificate { get; set; }
/// <summary>
/// Specifies the ApplicationName for the client application.
/// </summary>
public string ApplicationName { get; set; }
/// <summary>
/// Should untrusted certificates be silently accepted by the client?
/// </summary>
public bool AutoAcceptUntrustedCertificates { get; set; }
/// <summary>
/// Specifies the ConfigSectionName for the client configuration.
/// </summary>
public string ConfigSectionName { get; set; }
/// <summary>
/// default monitor interval in Milliseconds.
/// </summary>
public int DefaultMonitorInterval { get; set; }
/// <summary>
/// Specifies a name to be associated with the created sessions.
/// </summary>
public string SessionName { get; set; }
/// <summary>
/// Specifies the timeout for the sessions.
/// </summary>
public uint SessionTimeout { get; set; }
/// <summary>
/// Specify whether message exchange should be secured.
/// </summary>
public bool UseMessageSecurity { get; set; }
/// <summary>
/// The maximum number of notifications per publish request.
/// The clients responsibility is to send PublishRequests to the server,
/// in order to enable the server to send PublishResponses back.
/// The PublishResponses are used to deliver the notifications: but if there
/// are no PublishRequests, the server cannot send a notification to the client.
/// The server will also verify that the client is alive by checking that
/// new PublishRequests are received LifeTimeCount defines the number of
/// PublishingIntervals to wait for a new PublishRequest, before realizing
/// that the client is no longer active.The Subscription is then removed from
/// the server.
/// </summary>
public uint SubscriptionLifetimeCount { get; set; }
/// <summary>
/// If there is no data to send after the next PublishingInterval,
/// the server will skip it. But KeepAlive defines how many intervals may be skipped,
/// before an empty notification is sent anyway: to give the client a hint that
/// the subscription is still alive in the server and that there just has not been
/// any data arriving to the client.
/// </summary>
public uint SubscriptionKeepAliveCount { get; set; }
/// <summary>
/// Gets or sets the max subscription count.
/// </summary>
public int MaxSubscriptionCount { get; set; }
/// <summary>
/// The maximum number of messages saved in the queue for each subscription.
/// </summary>
public int MaxMessageQueueSize { get; set; }
/// <summary>
/// The maximum number of notificates saved in the queue for each monitored item.
/// </summary>
public int MaxNotificationQueueSize { get; set; }
/// <summary>
/// Gets or sets the max publish request count.
/// </summary>
public int MaxPublishRequestCount { get; set; }
/// <summary>
/// The identity to connect to the OPC server as
/// </summary>
public OpcUa.UserIdentity UserIdentity { get; set; }
/// <summary>
/// Creates a client options object
/// </summary>
public UaClientOptions()
{
// Initialize default values:
ApplicationName = "h-opc-client";
AutoAcceptUntrustedCertificates = true;
ConfigSectionName = "h-opc-client";
DefaultMonitorInterval = 100;
SessionName = "h-opc-client";
SessionTimeout = 60000U;
UseMessageSecurity = false;
SubscriptionLifetimeCount = 0;
SubscriptionKeepAliveCount = 0;
MaxSubscriptionCount = 100;
MaxMessageQueueSize = 10;
MaxNotificationQueueSize = 100;
MaxPublishRequestCount = 20;
}
}
}
}

View File

@@ -2,28 +2,28 @@
namespace Hylasoft.Opc.Ua
{
/// <summary>
/// Represents a node to be used specifically for OPC UA
/// </summary>
public class UaNode : Node
{
/// <summary>
/// The UA Id of the node
/// Represents a node to be used specifically for OPC UA
/// </summary>
public string NodeId { get; private set; }
/// <summary>
/// Instantiates a UaNode class
/// </summary>
/// <param name="name">the name of the node</param>
/// <param name="nodeId">The UA Id of the node</param>
/// <param name="parent">The parent node</param>
internal UaNode(string name, string nodeId, Node parent = null)
: base(name, parent)
public class UaNode : Node
{
NodeId = nodeId;
/// <summary>
/// The UA Id of the node
/// </summary>
public string NodeId { get; private set; }
/// <summary>
/// Instantiates a UaNode class
/// </summary>
/// <param name="name">the name of the node</param>
/// <param name="nodeId">The UA Id of the node</param>
/// <param name="parent">The parent node</param>
internal UaNode(string name, string nodeId, Node parent = null)
: base(name, parent)
{
NodeId = nodeId;
}
}
}
}