StatusViewModel.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using GeneralData;
  2. using ScottPlot.Plottables;
  3. namespace HistoryUI.ViewModels;
  4. public partial class StatusViewModel : BaseViewModel<DBFormat>
  5. {
  6. public StatusViewModel(Hardwares hardwares, IORM orm) : base(hardwares, orm)
  7. {
  8. this.DataGirdVis = Visibility.Collapsed;
  9. this.Loading = Visibility.Collapsed;
  10. this.PlotControl = new();
  11. this.InitPlot();
  12. }
  13. private void InitPlot()
  14. {
  15. this.PlotControl.Plot.Grid.XAxisStyle.MajorLineStyle.Width = 1f;
  16. this.PlotControl.Plot.Grid.YAxisStyle.MajorLineStyle.Width = 1f;
  17. this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent;
  18. this.PlotControl.Plot.RenderManager.RenderStarting += (s, e) =>
  19. {
  20. Tick[] ticks = this.PlotControl.Plot.Axes.Bottom.TickGenerator.Ticks;
  21. for (int i = 0; i < ticks.Length; i++)
  22. {
  23. DateTime dt = DateTime.FromOADate(ticks[i].Position);
  24. string label = $"{dt:MM/dd HH:mm:ss}";
  25. ticks[i] = new Tick(ticks[i].Position, label);
  26. }
  27. };
  28. PixelPadding padding = new(40, 20, 65, 10);
  29. this.PlotControl.Plot.Layout.Fixed(padding);
  30. this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent;
  31. this.Query();
  32. }
  33. [ObservableProperty]
  34. private WpfPlot _PlotControl;
  35. [ObservableProperty]
  36. private string? _Hint;
  37. [ObservableProperty]
  38. private Visibility _DataGirdVis;
  39. [ObservableProperty]
  40. private Visibility _Loading;
  41. [RelayCommand]
  42. private void Show(string para)
  43. {
  44. switch (para)
  45. {
  46. case "Show":
  47. this.DataGirdVis = Visibility.Visible;
  48. break;
  49. case "Hide":
  50. this.DataGirdVis = Visibility.Collapsed;
  51. break;
  52. default:
  53. break;
  54. }
  55. }
  56. [RelayCommand]
  57. protected override void Query()
  58. {
  59. if (!base.QueryBase(out byte mini8, out byte Channel))
  60. return;
  61. this.Loading = Visibility.Visible;
  62. _orm.Query<DBFormat>($"Mini8-{mini8}-{Channel}",
  63. t =>
  64. t.DateTime >= this.StartTime &&
  65. t.DateTime <= this.EndTime
  66. , QueryResult);
  67. }
  68. private class Area(DateTime start, DateTime? end, bool success)
  69. {
  70. public bool Success { get; set; } = success;
  71. public DateTime Start { get; } = start;
  72. public DateTime? End { get; set; } = end;
  73. }
  74. private class DataRange
  75. {
  76. public readonly List<float> target = [];
  77. public readonly List<float> temp = [];
  78. public readonly List<float> caps = [];
  79. public readonly List<float> floor = [];
  80. public readonly List<float> capsWarning = [];
  81. public readonly List<float> floorWarning = [];
  82. public readonly List<DateTime> tcBrokenLine = [];
  83. public readonly List<DateTime> time = [];
  84. public readonly List<Area> autoTuneArea = [];
  85. public readonly List<Area> tcBrockenArea = [];
  86. }
  87. private readonly List<DataRange> _DataRangeCache = [];
  88. private readonly Dictionary<int, DBFormat> _DataCache = [];
  89. private void QueryResult(List<DBFormat> results)
  90. {
  91. if (results.Count < 1)
  92. {
  93. App.Current.Dispatcher.Invoke(() => this.Loading = Visibility.Collapsed);
  94. return;
  95. }
  96. results = [.. results.OrderBy(t => t.DateTime)];
  97. _DataCache.Clear();
  98. _DataRangeCache.Clear();
  99. for (int i = 1; i <= results.Count; i++)
  100. {
  101. _DataCache.Add(i, results[i - 1]);
  102. if (_DataCache[i].ActiveTuneSet != ActiveTuneSet.AutoTune)
  103. continue;
  104. _DataCache[i].Running_P = _DataCache[i].AutoTune_P;
  105. _DataCache[i].Running_I = _DataCache[i].AutoTune_I;
  106. _DataCache[i].Running_D = _DataCache[i].AutoTune_D;
  107. }
  108. //Create Data Range
  109. DateTime? lastTime = null;
  110. AutoTuneStatus? autoTune = null;
  111. TcBorken tcBorken = TcBorken.Normal;
  112. float lastPV = 0;
  113. foreach (DBFormat dbData in results)
  114. {
  115. if (dbData.SensorBreakAlarm == TcBorken.Error)
  116. dbData.PV = lastPV;
  117. lastPV = dbData.PV;
  118. TimeSpan? span = dbData.DateTime - lastTime;
  119. if (lastTime is null || !span.HasValue || span.Value.TotalSeconds > 10)
  120. {
  121. autoTune = null;
  122. tcBorken = TcBorken.Normal;
  123. _DataRangeCache.Add(new());
  124. }
  125. lastTime = dbData.DateTime;
  126. DataRange dataRang = _DataRangeCache.Last();
  127. dataRang.time.Add(dbData.DateTime);
  128. dataRang.temp.Add(dbData.PV);
  129. dataRang.target.Add(dbData.SetPoint);
  130. dataRang.caps.Add(dbData.Caps);
  131. dataRang.floor.Add(dbData.Floor);
  132. dataRang.capsWarning.Add(dbData.CapsWarning);
  133. dataRang.floorWarning.Add(dbData.FloorWarning);
  134. if (tcBorken == dbData.SensorBreakAlarm)
  135. goto Step_AutoTuneStatusCheck;
  136. switch (dbData.SensorBreakAlarm)
  137. {
  138. case TcBorken.Normal:
  139. if (dataRang.tcBrockenArea.Count == 0)
  140. break;
  141. Area s = dataRang.tcBrockenArea.Last();
  142. s.Success = true;
  143. s.End = dbData.DateTime;
  144. break;
  145. case TcBorken.Error:
  146. dataRang.tcBrockenArea.Add(new(dbData.DateTime, null, false));
  147. break;
  148. default:
  149. break;
  150. }
  151. dataRang.tcBrokenLine.Add(dbData.DateTime);
  152. tcBorken = dbData.SensorBreakAlarm;
  153. Step_AutoTuneStatusCheck:
  154. //autoTune ??= dbData.AutoTuneStatus;
  155. if (autoTune.HasValue && autoTune == dbData.AutoTuneStatus)
  156. continue;
  157. switch (dbData.AutoTuneStatus)
  158. {
  159. case AutoTuneStatus.Triggered:
  160. case AutoTuneStatus.Tuning:
  161. autoTune = AutoTuneStatus.Tuning;
  162. dataRang.autoTuneArea.Add(new(dbData.DateTime, null, true));
  163. break;
  164. case AutoTuneStatus.Complete:
  165. autoTune = AutoTuneStatus.Complete;
  166. if (dataRang.autoTuneArea.Count == 0)
  167. {
  168. dataRang.autoTuneArea.Add(new(dataRang.time[0], dbData.DateTime, true));
  169. break;
  170. }
  171. Area area1 = dataRang.autoTuneArea.Last();
  172. area1.Success = true;
  173. area1.End = dbData.DateTime;
  174. break;
  175. case AutoTuneStatus.Aborted:
  176. case AutoTuneStatus.Timeout:
  177. case AutoTuneStatus.Overflow:
  178. autoTune = AutoTuneStatus.Aborted;
  179. if (dataRang.autoTuneArea.Count == 0)
  180. {
  181. dataRang.autoTuneArea.Add(new(dataRang.time[0], dbData.DateTime, false));
  182. break;
  183. }
  184. Area area2 = dataRang.autoTuneArea.Last();
  185. area2.Success = false;
  186. area2.End = dbData.DateTime;
  187. break;
  188. default:
  189. break;
  190. }
  191. }
  192. App.Current.Dispatcher.Invoke(() =>
  193. {
  194. this.PlotControl.Plot.Clear();
  195. this._DataRangeCache.ForEach(range => SetDataRangeInPlot(range));
  196. this.RefreshPlot();
  197. this.RefreshDataTable(results);
  198. this.Loading = Visibility.Collapsed;
  199. });
  200. }
  201. private void SetLine(List<DateTime> time, List<float> value, string color, LinePattern linePattern, MarkerStyle markerStyle, float lineWidth)
  202. {
  203. Scatter mainScatter = this.PlotControl.Plot.Add.Scatter(time, value, ScottPlot.Color.FromHex(color));
  204. mainScatter.MarkerStyle = markerStyle;
  205. mainScatter.LineWidth = lineWidth;
  206. mainScatter.LinePattern = linePattern;
  207. }
  208. private void SetDataRangeInPlot(DataRange range)
  209. {
  210. this.SetLine(range.time, range.temp, "0000cd", LinePattern.Solid, MarkerStyle.None, 2f);
  211. this.SetLine(range.time, range.caps, "FF0000", LinePattern.Dotted, MarkerStyle.None, 1.5f);
  212. this.SetLine(range.time, range.floor, "FF0000", LinePattern.Dotted, MarkerStyle.None, 1.5f);
  213. this.SetLine(range.time, range.capsWarning, "FFA500", LinePattern.Dotted, MarkerStyle.None, 1.5f);
  214. this.SetLine(range.time, range.floorWarning, "FFA500", LinePattern.Dotted, MarkerStyle.None, 1.5f);
  215. this.SetLine(range.time, range.target, "00FF00", LinePattern.Dotted, MarkerStyle.None, 1.5f);
  216. foreach (var item in range.autoTuneArea)
  217. {
  218. item.End ??= range.time.Last();
  219. _ = item.Success switch
  220. {
  221. true => this.PlotControl.Plot.Add.HorizontalSpan(item.Start.ToOADate(), item.End.Value.ToOADate(), ScottPlot.Color.FromHex("00ff00").WithAlpha(0.2)),
  222. false => this.PlotControl.Plot.Add.HorizontalSpan(item.Start.ToOADate(), item.End.Value.ToOADate(), ScottPlot.Color.FromHex("828282").WithAlpha(0.2))
  223. };
  224. }
  225. foreach (var item in range.tcBrockenArea)
  226. {
  227. item.End ??= range.time.Last();
  228. this.PlotControl.Plot.Add.HorizontalSpan(item.Start.ToOADate(), item.End.Value.ToOADate(), ScottPlot.Color.FromHex("f98083").WithAlpha(0.2));
  229. }
  230. }
  231. private void RefreshDataTable(List<DBFormat> results)
  232. {
  233. this.Results ??= [];
  234. this.Results.Clear();
  235. for (int i = 0; i < results.Count; i++)
  236. this.Results.Add(i, results[i]);
  237. }
  238. private void RefreshPlot()
  239. {
  240. this.PlotControl.Plot.HideLegend();
  241. this.PlotControl.Plot.Axes.DateTimeTicksBottom();
  242. this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Rotation = -45;
  243. this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Alignment = Alignment.MiddleRight;
  244. this.PlotControl.Plot.Axes.AutoScale();
  245. this.PlotControl.Refresh();
  246. this.PlotControl.Plot.Axes.Zoom(1.085, 1);
  247. }
  248. [RelayCommand]
  249. private void ReScale(string para)
  250. {
  251. switch (para)
  252. {
  253. case "+":
  254. this.PlotControl.Plot.Axes.Zoom(1.25, 1);
  255. break;
  256. case "-":
  257. this.PlotControl.Plot.Axes.Zoom(0.8, 1);
  258. break;
  259. case "add":
  260. this.PlotControl.Plot.Axes.Zoom(1, 1.25);
  261. break;
  262. case "minus":
  263. this.PlotControl.Plot.Axes.Zoom(1, 0.8);
  264. break;
  265. default:
  266. this.PlotControl.Plot.Axes.AutoScale();
  267. this.PlotControl.Plot.Axes.Zoom(1.085, 1);
  268. break;
  269. }
  270. this.PlotControl.Refresh();
  271. }
  272. }