Change log system
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 client’s 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 client’s 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user