Resolve DA, A&C, and security spec gaps with ServerCapabilities, alarm methods, and modern profiles
Add ServerCapabilities/OperationLimits node, enable diagnostics, add OnModifyMonitoredItemsComplete override for DA compliance. Wire shelving, enable/disable, confirm, and addcomment handlers on alarm conditions with LocalTime/Quality event fields for Part 9 compliance. Add Aes128/Aes256 security profiles, X.509 certificate authentication, and AUDIT-prefixed auth logging. Fix flaky probe monitor test. Update docs for all changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -327,6 +327,11 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
condition.Retain.Value = false;
|
||||
condition.OnReportEvent = (context, node, e) => Server.ReportEvent(context, e);
|
||||
condition.OnAcknowledge = OnAlarmAcknowledge;
|
||||
condition.OnConfirm = OnAlarmConfirm;
|
||||
condition.OnAddComment = OnAlarmAddComment;
|
||||
condition.OnEnableDisable = OnAlarmEnableDisable;
|
||||
condition.OnShelve = OnAlarmShelve;
|
||||
condition.OnTimedUnshelve = OnAlarmTimedUnshelve;
|
||||
|
||||
// Add HasCondition reference from source to condition
|
||||
if (sourceVariable != null)
|
||||
@@ -425,6 +430,48 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
}
|
||||
}
|
||||
|
||||
private ServiceResult OnAlarmConfirm(
|
||||
ISystemContext context, ConditionState condition, byte[] eventId, LocalizedText comment)
|
||||
{
|
||||
Log.Information("Alarm confirmed: {Name} (Comment={Comment})",
|
||||
condition.ConditionName?.Value, comment?.Text);
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
private ServiceResult OnAlarmAddComment(
|
||||
ISystemContext context, ConditionState condition, byte[] eventId, LocalizedText comment)
|
||||
{
|
||||
Log.Information("Alarm comment added: {Name} — {Comment}",
|
||||
condition.ConditionName?.Value, comment?.Text);
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
private ServiceResult OnAlarmEnableDisable(
|
||||
ISystemContext context, ConditionState condition, bool enabling)
|
||||
{
|
||||
Log.Information("Alarm {Action}: {Name}",
|
||||
enabling ? "ENABLED" : "DISABLED", condition.ConditionName?.Value);
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
private ServiceResult OnAlarmShelve(
|
||||
ISystemContext context, AlarmConditionState alarm, bool shelving, bool oneShot, double shelvingTime)
|
||||
{
|
||||
alarm.SetShelvingState(context, shelving, oneShot, shelvingTime);
|
||||
Log.Information("Alarm {Action}: {Name} (OneShot={OneShot}, Time={Time}s)",
|
||||
shelving ? "SHELVED" : "UNSHELVED", alarm.ConditionName?.Value, oneShot,
|
||||
shelvingTime / 1000.0);
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
private ServiceResult OnAlarmTimedUnshelve(
|
||||
ISystemContext context, AlarmConditionState alarm)
|
||||
{
|
||||
alarm.SetShelvingState(context, false, false, 0);
|
||||
Log.Information("Alarm timed unshelve: {Name}", alarm.ConditionName?.Value);
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
private void ReportAlarmEvent(AlarmInfo info, bool active)
|
||||
{
|
||||
var condition = info.ConditionNode;
|
||||
@@ -443,6 +490,16 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
condition.Message.Value = new LocalizedText("en", message);
|
||||
condition.SetSeverity(SystemContext, (EventSeverity)severity);
|
||||
|
||||
// Populate additional event fields
|
||||
if (condition.LocalTime != null)
|
||||
condition.LocalTime.Value = new TimeZoneDataType
|
||||
{
|
||||
Offset = (short)TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes,
|
||||
DaylightSavingInOffset = TimeZoneInfo.Local.IsDaylightSavingTime(DateTime.Now)
|
||||
};
|
||||
if (condition.Quality != null)
|
||||
condition.Quality.Value = StatusCodes.Good;
|
||||
|
||||
// Retain while active or unacknowledged
|
||||
condition.Retain.Value = active || condition.AckedState?.Id?.Value == false;
|
||||
|
||||
@@ -1808,6 +1865,15 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
RestoreTransferredSubscriptions(transferredTagRefs);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnModifyMonitoredItemsComplete(ServerSystemContext context,
|
||||
IList<IMonitoredItem> monitoredItems)
|
||||
{
|
||||
foreach (var item in monitoredItems)
|
||||
Log.Debug("MonitoredItem modified: Id={Id}, SamplingInterval={Interval}ms",
|
||||
item.Id, item.SamplingInterval);
|
||||
}
|
||||
|
||||
private static string? GetNodeIdString(IMonitoredItem item)
|
||||
{
|
||||
if (item.ManagerHandle is NodeState node)
|
||||
|
||||
Reference in New Issue
Block a user