Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*DRAFT* Add EventMonitoredItem comfort #2543

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions Libraries/Opc.Ua.Client/Events/EventField.cs
@@ -0,0 +1,38 @@
namespace Opc.Ua.Client.Events
{
/// <summary>
/// Object representing an event field
/// </summary>
public class EventField
{
/// <summary>
/// Name of this event field
/// </summary>
public string Name { get; }

/// <summary>
/// Value of this event
/// </summary>
public Variant Value { get; }

/// <summary>
/// Object representing an event field
/// </summary>
/// <param name="name">Name of the field</param>
/// <param name="value">Value of the field</param>
public EventField(string name, Variant value)
{
Name = name;
Value = value;
}

/// <summary>
/// String representation: [Name]: [Value]
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{Name}: {Value}";
}
}
}
97 changes: 97 additions & 0 deletions Libraries/Opc.Ua.Client/Events/Extensions.cs
@@ -0,0 +1,97 @@
using System;
using System.Linq;

namespace Opc.Ua.Client.Events
{
/// <summary>
///
/// </summary>
public static class Extensions
{

/// <summary>
///
/// </summary>
/// <param name="session"></param>
/// <param name="nodeId"></param>
/// <param name="browseDirection"></param>
/// <param name="referenceTypeId"></param>
/// <returns></returns>
public static ReferenceDescriptionCollection FetchReferences(this ISession session, NodeId nodeId, BrowseDirection browseDirection, NodeId referenceTypeId)
{
if (session is null)
{
throw new ArgumentNullException(nameof(session));
}
// browse for all references.
byte[] continuationPoint;
ReferenceDescriptionCollection descriptions;

session.Browse(
null,
null,
nodeId,
0,
browseDirection,
referenceTypeId,
true,
0,
out continuationPoint,
out descriptions);

// process any continuation point.
while (continuationPoint != null)
{
byte[] revisedContinuationPoint;
ReferenceDescriptionCollection additionalDescriptions;

session.BrowseNext(
null,
false,
continuationPoint,
out revisedContinuationPoint,
out additionalDescriptions);

continuationPoint = revisedContinuationPoint;

descriptions.AddRange(additionalDescriptions);
}

return descriptions;
}

/// <summary>
///
/// </summary>
/// <param name="session"></param>
/// <param name="rvic"></param>
/// <returns></returns>
public static DataValueCollection Read(this ISession session, ReadValueIdCollection rvic)
{
session.Read(null, 0, TimestampsToReturn.Neither, rvic, out DataValueCollection dt, out DiagnosticInfoCollection dg);
return dt;
}

/// <summary>
///
/// </summary>
/// <param name="session"></param>
/// <param name="rvi"></param>
/// <returns></returns>
public static DataValue Read(this ISession session, ReadValueId rvi)
{
return session.Read(new ReadValueIdCollection { rvi }).First();
}


/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static NodeId ToNodeId(this ReferenceDescription id)
{
return ExpandedNodeId.ToNodeId(id.NodeId, new NamespaceTable());
}
}
}
31 changes: 31 additions & 0 deletions Libraries/Opc.Ua.Client/Events/IEvent.cs
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using Opc.Ua.Client.Methods;

namespace Opc.Ua.Client.Events
{
/// <summary>
/// Interface of an event
/// </summary>
public interface IEvent
{
/// <summary>
/// Event fields
/// </summary>
IReadOnlyList<EventField> Fields { get; }

/// <summary>
/// Acknowledge
/// </summary>
MethodCallReturnValue Acknowledge(LocalizedText comment);

/// <summary>
/// Confirm
/// </summary>
MethodCallReturnValue Confirm(LocalizedText comment);

/// <summary>
/// Add comment to this event
/// </summary>
MethodCallReturnValue AddComment(LocalizedText comment);
}
}
13 changes: 13 additions & 0 deletions Libraries/Opc.Ua.Client/Events/ISessionContainer.cs
@@ -0,0 +1,13 @@
namespace Opc.Ua.Client.Events
{
/// <summary>
/// Interface for an object containing the session
/// </summary>
public interface ISessionContainer
{
/// <summary>
/// The contained session object
/// </summary>
ISession Session { get; set; }
}
}
67 changes: 67 additions & 0 deletions Libraries/Opc.Ua.Client/Events/OpcEvent.cs
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Opc.Ua.Client.Methods;

namespace Opc.Ua.Client.Events
{
/// <summary>
/// Object for an event
/// </summary>
public class OpcEvent : IEvent
{
/// <summary>
/// Event fields
/// </summary>
public IReadOnlyList<EventField> Fields { get; }

private readonly NodeId _objectNodeId;
private readonly byte[] _eventId;
private readonly IEventMethodCollection _eventMethods;

/// <summary>
/// Constructor
/// </summary>
public OpcEvent(IEventMethodCollection eventMethods, IEnumerable<EventField> fields)
{
Fields = fields.ToList();
_eventMethods = eventMethods;
_objectNodeId = GetEventField<NodeId>("ConditionNodeId", x => x.Name.Equals("ConditionId", StringComparison.Ordinal));
_eventId = GetEventField<byte[]>("EventId", x => x.Name.Equals("/EventId", StringComparison.Ordinal));
}

/// <summary>
/// Acknowledge this event
/// </summary>
public MethodCallReturnValue Acknowledge(LocalizedText comment)
{
return _eventMethods.Acknowledge.CallMethod(_objectNodeId, _eventId, comment);
}

/// <summary>
/// Confirm this event
/// </summary>
public MethodCallReturnValue Confirm(LocalizedText comment)
{
return _eventMethods.Confirm.CallMethod(_objectNodeId, _eventId, comment);
}

/// <summary>
/// Add comment to this event
/// </summary>
public MethodCallReturnValue AddComment(LocalizedText comment)
{
return _eventMethods.AddComment.CallMethod(_objectNodeId, _eventId, comment);
}

private T GetEventField<T>(string eventFieldName, Func<EventField, bool> searchCriteria)
{
var relevantField = Fields.FirstOrDefault(searchCriteria);
if (relevantField is null)
{
throw new OpcUaEventFieldNotFoundException(eventFieldName);
}
return (T)relevantField.Value.Value;
}
}
}
65 changes: 65 additions & 0 deletions Libraries/Opc.Ua.Client/Events/OpcUaEventFieldNotFoundException.cs
@@ -0,0 +1,65 @@
using System;

namespace Opc.Ua.Client.Events
{
/// <summary>
/// Exception when event field not found
/// </summary>
public class OpcUaEventFieldNotFoundException : Exception
{
private const string DefaultMessage = "Event field with given name not found!";

/// <summary>
/// Name of the event field
/// </summary>
public string EventFieldName { get; }

/// <summary>
/// Exception when event field not found
/// </summary>
public OpcUaEventFieldNotFoundException(string eventFieldName)
: this(eventFieldName, "")
{
EventFieldName = eventFieldName;
}

/// <summary>
/// Exception when event field not found
/// </summary>
public OpcUaEventFieldNotFoundException(string eventFieldName, string userMessage)
: this(eventFieldName, userMessage, null)
{

}

/// <summary>
/// Exception when event field not found
/// </summary>
public OpcUaEventFieldNotFoundException() : this("")
{

}

/// <summary>
/// Exception when event field not found
/// </summary>
/// <param name="message"></param>
/// <param name="innerException"></param>
public OpcUaEventFieldNotFoundException(string message, Exception innerException) : this("", message, innerException)
{

}

/// <summary>
/// Exception when event field not found
/// </summary>
/// <param name="eventFieldName">Field that was not found</param>
/// <param name="userMessage">userdefined message for the exception</param>
/// <param name="innerException">Inner Exception</param>
public OpcUaEventFieldNotFoundException(string eventFieldName, string userMessage, Exception innerException)
: base($"{DefaultMessage}{eventFieldName}{userMessage}", innerException)
{
EventFieldName = eventFieldName;
}
}
}
22 changes: 22 additions & 0 deletions Libraries/Opc.Ua.Client/Methods/EventMethod.cs
@@ -0,0 +1,22 @@
using System.Collections.Generic;

namespace Opc.Ua.Client.Methods
{
/// <summary>
/// A standard event method
/// </summary>
internal class EventMethod : MethodBase, IEventMethod
{
internal EventMethod(ISession session, NodeId methodNodeId) : base(session, methodNodeId)
{
}

/// <summary>
/// Call this method
/// </summary>
public MethodCallReturnValue CallMethod(NodeId objectNodeId, byte[] eventId, LocalizedText comment)
{
return Call(objectNodeId, new List<Variant> { eventId, comment });
}
}
}
30 changes: 30 additions & 0 deletions Libraries/Opc.Ua.Client/Methods/EventMethodCollection.cs
@@ -0,0 +1,30 @@
namespace Opc.Ua.Client.Methods
{
/// <summary>
/// Method collection for standard events
/// </summary>
public class EventMethodCollection : IEventMethodCollection
{
/// <summary>
/// Acknowledge
/// </summary>
public IEventMethod Acknowledge { get; }

/// <summary>
/// Confirm
/// </summary>
public IEventMethod Confirm { get; }

/// <summary>
/// Add comment
/// </summary>
public IEventMethod AddComment { get; }

internal EventMethodCollection(ISession session)
{
Acknowledge = new EventMethod(session, MethodIds.AcknowledgeableConditionType_Acknowledge);
Confirm = new EventMethod(session, MethodIds.AcknowledgeableConditionType_Confirm);
AddComment = new EventMethod(session, MethodIds.ConditionType_AddComment);
}
}
}
17 changes: 17 additions & 0 deletions Libraries/Opc.Ua.Client/Methods/IEventMethod.cs
@@ -0,0 +1,17 @@
namespace Opc.Ua.Client.Methods
{
/// <summary>
/// A standard event method
/// </summary>
public interface IEventMethod
{
/// <summary>
/// Call this method and Return a MethodCallReturnValue
/// </summary>
/// <param name="objectNodeId">the Object NodeId</param>
/// <param name="eventId">the EventId</param>
/// <param name="comment">Comment to set for the event</param>
/// <returns>MethodCallReturnValue</returns>
MethodCallReturnValue CallMethod(NodeId objectNodeId, byte[] eventId, LocalizedText comment);
}
}