FeederPlugin.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using TeamAAS.Core;
  7. using TeamAAS.Feeder.Interfaces;
  8. using TeamAAS.FlowEditor.Models;
  9. using TeamAAS.FlowEditor.Plugins;
  10. using TeamAAS.Feeder.Models;
  11. using Plugins.Feeder.Models;
  12. namespace Plugins.Feeder
  13. {
  14. [Plugin("供料器送料", PluginCategory.硬件模块, typeof(FeederPluginModel),
  15. "PackageVariant")]
  16. [Serializable]
  17. public class FeederPlugin : BasePlugin<FeederPluginModel>
  18. {
  19. public override List<OutputField> DeclareOutputs() => new List<OutputField>
  20. {
  21. new OutputField("供料器", typeof(string)),
  22. new OutputField("流程", typeof(string)),
  23. new OutputField("执行步数", typeof(int)),
  24. new OutputField("结果", typeof(bool)),
  25. };
  26. public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
  27. {
  28. var res = new Dictionary<string, object>();
  29. results = res;
  30. // 统一失败出口:写 Error + 结果=false + 记 1 级错误日志(任何阈值都落盘)
  31. NodeRunStatus Fail(string message)
  32. {
  33. res["Error"] = message;
  34. res["结果"] = false;
  35. Log(1, $"供料器送料失败: {message}", TeamAAS.LogLevel.Error);
  36. return NodeRunStatus.Failed;
  37. }
  38. var mgr = Service<IFeederManager>();
  39. if (mgr == null)
  40. return Fail("FeederManager 未初始化");
  41. Log(3, $"开始送料,供料器={Model.FeederName}, 流程={Model.SequenceKey}");
  42. var info = mgr.GetAll().FirstOrDefault(f =>
  43. string.Equals(f.FeederName, Model.FeederName, StringComparison.OrdinalIgnoreCase));
  44. if (info == null)
  45. return Fail($"未找到供料器 \"{Model.FeederName}\"");
  46. res["供料器"] = info.FeederName;
  47. // SequenceKey 格式: "供料器名/流程名" 或纯 "流程名"
  48. var seqName = Model.SequenceKey;
  49. var slashIdx = seqName?.IndexOf('/') ?? -1;
  50. if (slashIdx >= 0) seqName = seqName.Substring(slashIdx + 1);
  51. var seq = info.Sequences.FirstOrDefault(s =>
  52. string.Equals(s.Name, seqName, StringComparison.OrdinalIgnoreCase));
  53. if (seq == null)
  54. return Fail($"供料器 \"{info.FeederName}\" 上不存在流程 \"{seqName}\"");
  55. res["流程"] = seq.Name;
  56. var enabledSteps = seq.Steps.Where(s => s.Enabled).ToList();
  57. res["执行步数"] = enabledSteps.Count;
  58. Log(4, $"流程 \"{seq.Name}\" 启用步骤 {enabledSteps.Count} 个");
  59. var device = mgr.GetOrCreateDevice(info);
  60. if (device == null)
  61. return Fail("创建设备实例失败");
  62. try
  63. {
  64. if (!device.IsConnected && Model.AutoConnect)
  65. {
  66. try { device.ConnectAsync().GetAwaiter().GetResult(); }
  67. catch (Exception ex)
  68. {
  69. return Fail($"连接供料器失败: {ex.Message}");
  70. }
  71. }
  72. if (!device.IsConnected)
  73. return Fail($"供料器 \"{info.FeederName}\" 未连接");
  74. int stepIdx = 0;
  75. foreach (var step in enabledSteps)
  76. {
  77. token.ThrowIfCancellationRequested();
  78. stepIdx++;
  79. if (step.StepType == SequenceStepType.Delay)
  80. {
  81. Log(4, $"第{stepIdx}步: 延时 {step.TimeMs}ms");
  82. Task.Delay(step.TimeMs, token).Wait(token);
  83. }
  84. else
  85. {
  86. try
  87. {
  88. Log(4, $"第{stepIdx}步: 方向={step.Direction}, 时长={step.TimeMs}ms");
  89. device.RunDirectionAsync(step.Direction, step.TimeMs)
  90. .GetAwaiter().GetResult();
  91. }
  92. catch (Exception ex)
  93. {
  94. return Fail($"第{stepIdx}步执行失败: {ex.Message}");
  95. }
  96. }
  97. }
  98. if (Model.StopWhenDone)
  99. {
  100. try { device.StopAsync().GetAwaiter().GetResult(); } catch { }
  101. }
  102. res["结果"] = true;
  103. Log(2, $"送料完成,供料器={info.FeederName}, 流程={seq.Name}, 执行 {enabledSteps.Count} 步");
  104. return NodeRunStatus.Success;
  105. }
  106. catch (OperationCanceledException)
  107. {
  108. try { device.StopAsync().GetAwaiter().GetResult(); } catch { }
  109. return Fail("用户取消");
  110. }
  111. catch (Exception ex)
  112. {
  113. try { device.StopAsync().GetAwaiter().GetResult(); } catch { }
  114. return Fail(ex.Message);
  115. }
  116. }
  117. }
  118. }