Auto: twincat-5.1 — IAlarmSource via TC3 EventLogger (gated, scaffold)
Closes #316
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
using CliFx.Attributes;
|
||||
using CliFx.Infrastructure;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// PR 5.1 / #316 — stream TC3 EventLogger alarms to the terminal until Ctrl+C.
|
||||
/// Mirrors the OPC UA Client CLI <c>alarms</c> verb shape: subscribe + print every
|
||||
/// incoming <see cref="AlarmEventArgs"/> with timestamp, source, severity, and
|
||||
/// message text. Requires <c>EnableAlarms=true</c> on the driver — set via the
|
||||
/// base options builder when the verb is selected.
|
||||
/// </summary>
|
||||
[Command("alarms", Description =
|
||||
"Subscribe to TC3 EventLogger alarms via the driver's IAlarmSource bridge and " +
|
||||
"stream events to stdout until Ctrl+C.")]
|
||||
public sealed class AlarmsCommand : TwinCATCommandBase
|
||||
{
|
||||
[CommandOption("source", Description =
|
||||
"Optional alarm source filter (matched case-insensitively against the event's " +
|
||||
"Source field). Repeat the flag to match multiple sources; omit to subscribe to " +
|
||||
"every event the EventLogger surfaces.")]
|
||||
public IReadOnlyList<string> Sources { get; init; } = Array.Empty<string>();
|
||||
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
var ct = console.RegisterCancellationHandler();
|
||||
|
||||
// Empty Tags + EnableAlarms=true builds a driver that opens only the alarm path.
|
||||
// TwinCATDriverOptions is a regular class with init-only properties — rebuild
|
||||
// the instance instead of using a record-style `with` clone.
|
||||
var baseOptions = BuildOptions([]);
|
||||
var options = new TwinCATDriverOptions
|
||||
{
|
||||
Devices = baseOptions.Devices,
|
||||
Tags = baseOptions.Tags,
|
||||
Probe = baseOptions.Probe,
|
||||
Timeout = baseOptions.Timeout,
|
||||
UseNativeNotifications = baseOptions.UseNativeNotifications,
|
||||
EnableControllerBrowse = baseOptions.EnableControllerBrowse,
|
||||
MaxArrayExpansion = baseOptions.MaxArrayExpansion,
|
||||
EnableAlarms = true,
|
||||
};
|
||||
|
||||
await using var driver = new TwinCATDriver(options, DriverInstanceId);
|
||||
IAlarmSubscriptionHandle? handle = null;
|
||||
try
|
||||
{
|
||||
await driver.InitializeAsync("{}", ct);
|
||||
|
||||
driver.OnAlarmEvent += (_, e) =>
|
||||
{
|
||||
var line =
|
||||
$"[{e.SourceTimestampUtc:HH:mm:ss.fff}] " +
|
||||
$"{e.SourceNodeId} " +
|
||||
$"sev={e.Severity} " +
|
||||
$"type={e.AlarmType} " +
|
||||
$"cond={e.ConditionId} " +
|
||||
$"\"{e.Message}\"";
|
||||
console.Output.WriteLine(line);
|
||||
};
|
||||
|
||||
handle = await driver.SubscribeAlarmsAsync(Sources, ct);
|
||||
|
||||
var filterDesc = Sources.Count == 0
|
||||
? "all sources"
|
||||
: $"sources [{string.Join(", ", Sources)}]";
|
||||
await console.Output.WriteLineAsync(
|
||||
$"Subscribed to TC3 EventLogger alarms on {AmsNetId}:{AmsPort} ({filterDesc}). Ctrl+C to stop.");
|
||||
await console.Output.WriteLineAsync(
|
||||
"Note: Beckhoff doesn't ship a managed TcEventLogger wrapper; the driver " +
|
||||
"uses a best-effort decode of AMS port 110 notifications. Some fields may " +
|
||||
"surface as 'Unknown' until a binary-protocol decoder lands.");
|
||||
try
|
||||
{
|
||||
await Task.Delay(System.Threading.Timeout.InfiniteTimeSpan, ct);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Expected on Ctrl+C.
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handle is not null)
|
||||
{
|
||||
try { await driver.UnsubscribeAlarmsAsync(handle, CancellationToken.None); }
|
||||
catch { /* teardown best-effort */ }
|
||||
}
|
||||
await driver.ShutdownAsync(CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user