ac5db0a9f8
Important 1: ShelveAlarmAsync Timed branch now multiplies shelvingTimeSeconds × 1000.0
before passing to CallMethodAsync — OPC UA Part 9 TimedShelve ShelvingTime is a Duration
in milliseconds, not seconds. IOpcUaClientService XML doc and ShelveCommand --duration
description updated to document the seconds-in / ms-out contract.
Important 2: ShelveAlarmAsync builds shelvingStateNodeId with the same
EndsWith(".ShelvingState") guard already used by the .Condition suffix in
AcknowledgeAlarmAsync / ConfirmAlarmAsync, preventing double-append.
Important 3: Add 6 service-layer tests to OpcUaClientServiceTests —
ConfirmAlarmAsync_OnSuccess_ReturnsGood
ConfirmAlarmAsync_OnServiceResultException_ReturnsBadStatusCode
ShelveAlarmAsync_OneShot_CallsMethodWithNoArgs
ShelveAlarmAsync_Timed_PassesDurationInMilliseconds (regression guard for Important 1)
ShelveAlarmAsync_Unshelve_CallsMethodWithNoArgs
ShelveAlarmAsync_OnServiceResultException_ReturnsBadStatusCode
FakeSessionAdapter extended with CallMethodInputArgs list to record per-call input
arguments so the Timed test can assert the ms value.
Minor 4: ShelveCommand output changed from "Shelve (OneShot) successful" to
"{shelveKind} successful/failed" so Unshelve reads "Unshelve successful: …".
Minor 6: ShelveCommand --duration description updated to "(must be > 0; in seconds,
converted to milliseconds for the OPC UA call; required for --kind Timed)".
79 lines
3.2 KiB
C#
79 lines
3.2 KiB
C#
using CliFx.Attributes;
|
|
using CliFx.Exceptions;
|
|
using CliFx.Infrastructure;
|
|
using Opc.Ua;
|
|
using ZB.MOM.WW.OtOpcUa.Client.Shared;
|
|
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
|
|
|
|
[Command("shelve", Description = "Shelve or unshelve an active alarm condition (OPC UA Part 9 ShelvedStateMachine)")]
|
|
public class ShelveCommand : CommandBase
|
|
{
|
|
/// <summary>
|
|
/// Creates the shelve command used to shelve or unshelve an OPC UA alarm condition from the terminal.
|
|
/// </summary>
|
|
/// <param name="factory">The factory that creates the shared client service for the command run.</param>
|
|
public ShelveCommand(IOpcUaClientServiceFactory factory) : base(factory)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the condition node ID of the alarm to shelve or unshelve.
|
|
/// </summary>
|
|
[CommandOption("node", 'n', Description = "Condition node ID of the alarm to shelve/unshelve", IsRequired = true)]
|
|
public string NodeId { get; init; } = default!;
|
|
|
|
/// <summary>
|
|
/// Gets the shelve operation kind: OneShot, Timed, or Unshelve.
|
|
/// </summary>
|
|
[CommandOption("kind", 'k', Description = "Shelve operation: OneShot | Timed | Unshelve", IsRequired = true)]
|
|
public string Kind { get; init; } = default!;
|
|
|
|
/// <summary>
|
|
/// Gets the shelving duration in seconds for Timed shelving (must be > 0; ignored for OneShot and Unshelve).
|
|
/// The value is passed in seconds by the operator and converted to milliseconds for the OPC UA TimedShelve call.
|
|
/// </summary>
|
|
[CommandOption("duration", 'd', Description = "Shelving duration in seconds (must be > 0; in seconds, converted to milliseconds for the OPC UA call; required for --kind Timed)")]
|
|
public double DurationSeconds { get; init; }
|
|
|
|
/// <summary>
|
|
/// Connects to the server and shelves or unshelves the specified alarm condition.
|
|
/// </summary>
|
|
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
|
public override async ValueTask ExecuteAsync(IConsole console)
|
|
{
|
|
ConfigureLogging();
|
|
|
|
if (!Enum.TryParse<ShelveKind>(Kind, ignoreCase: true, out var shelveKind))
|
|
throw new CommandException(
|
|
$"Invalid --kind value '{Kind}'. Expected one of: OneShot, Timed, Unshelve.");
|
|
|
|
if (shelveKind == ShelveKind.Timed && DurationSeconds <= 0)
|
|
throw new CommandException(
|
|
"--duration must be greater than 0 when --kind is Timed.");
|
|
|
|
IOpcUaClientService? service = null;
|
|
try
|
|
{
|
|
var ct = console.RegisterCancellationHandler();
|
|
(service, _) = await CreateServiceAndConnectAsync(ct);
|
|
|
|
var statusCode = await service.ShelveAlarmAsync(NodeId, shelveKind, DurationSeconds, ct);
|
|
|
|
if (StatusCode.IsGood(statusCode))
|
|
await console.Output.WriteLineAsync($"{shelveKind} successful: {NodeId}");
|
|
else
|
|
await console.Output.WriteLineAsync($"{shelveKind} failed: {statusCode}");
|
|
}
|
|
finally
|
|
{
|
|
if (service != null)
|
|
{
|
|
await service.DisconnectAsync();
|
|
service.Dispose();
|
|
}
|
|
}
|
|
}
|
|
}
|