using Newtonsoft.Json; using System.Diagnostics.Metrics; using System.Threading.Channels; using System.Timers; using UI_SequentMicrosystems.Components; using UI_SequentMicrosystems.Models; using Wrapper_Api_SequentMicrosystems.RTD8TM; namespace UI_SequentMicrosystems.Services { public class RTD8TMService { private SortedList ChanelNames = new SortedList(); private SortedList ActualValues = new SortedList(); private SortedList ValuesType = new SortedList(); private SortedList Calibrations = new SortedList(); public SortedList>> GraphData = new(); public SortedList>> GraphFiltered = new(); private int GraphFilteredCountPoint { get; set; } private byte GraphDataCounterCount = 10; private byte GraphDataCounter = 9; private string? Address { get; set; } private RTD8TM _RTD8TM = new RTD8TM(); private System.Timers.Timer _timer = new(1000); //update timer public delegate Task AsyncEventHandler(object? sender, TEventArgs? e); public event AsyncEventHandler? EventUpdateValues; public event AsyncEventHandler? EventUpdateGraph; public RTD8TMService() { _timer.AutoReset = true; _timer.Elapsed += TimerElapsed; _timer.Start(); } //Main Parameters Work /// /// Set Device Address /// /// Address [Base url] (http://1.2.3.4) public void SetAddress(string address) { Address = address; GetChanelsNames(); GetValueTypes(); GetCalibrations(); } /// /// Get used device Address /// /// Address or empty string public string GetAddress() { if (Address == null) { return ""; } else { return Address; } } //Actual Data /// /// Read Actual values from Device /// private async void GetActualValues() { if (Address == null) { return; } try { ActualValues = await _RTD8TM.Get(Address); foreach (byte stack in ActualValues.Keys) { if (Calibrations.ContainsKey(stack)) { for (byte chanel = 0; chanel < 8; chanel++) { ActualValues[stack][chanel] += Calibrations[stack][chanel]; } } } if (GraphDataCounter >= GraphDataCounterCount) { GraphDataCounter = 0; ReadChartData(); } else { GraphDataCounter++; } } catch (Exception ex) { Console.WriteLine($"Reading actual Data fail with message: {ex.Message}"); } } /// /// Request for actual data /// /// public SortedList GetActualData() { return ActualValues; } /// /// Get actual data Value /// /// Stack ID /// Chanel ID /// Measure Resistance public float GetActualData(byte stack, byte chanel) { if (ActualValues.ContainsKey(stack)) { return ActualValues[stack][chanel]; } else { return 0; } } //ChanelsNames /// /// Read configured chanels Names from Device /// public async void GetChanelsNames() { if (Address == null) return; ChanelNames = await _RTD8TM.GetNames(Address); AutoUpdateChanelsName(); } /// /// Set new Chanels Names /// /// chanels names sorted list #pragma warning disable CS1998 // V této asynchronní metodě chybí operátory await a spustí se synchronně. public async Task SetChanelsNames() #pragma warning restore CS1998 // V této asynchronní metodě chybí operátory await a spustí se synchronně. { if (Address == null) return; _RTD8TM.PostNames(Address, ChanelNames); } /// /// Update Chanels Names for not null loading names /// private void AutoUpdateChanelsName() { if (ActualValues.Count <= 0) return; foreach (byte key in ActualValues.Keys) { if (!ChanelNames.ContainsKey(key)) { ChanelNames.Add(key, new string[8]); } for (int i = 0; i < 8; i++) { if (ChanelNames[key][i] == null) { ChanelNames[key][i] = "----------"; } } } } /// /// Get chanel names /// /// Chanels names object public SortedList GetChanelNames() { return ChanelNames; } /// /// Set chanel Name /// /// Stack ID /// Chanel ID /// New Name public void SetChanelNames(byte stack, byte chanel, string name) { if (!ChanelNames.ContainsKey(stack)) { ChanelNames.Add(stack, new string[8]); } ChanelNames[stack][chanel] = name; } /// /// Read chanel name /// /// Stack ID /// Chanel ID /// Chanel name public string GetChanelName(byte stack, byte chanel) { if (ChanelNames.ContainsKey(stack)) { return ChanelNames[stack][chanel]; } else { return "----------"; } } /// /// Clear chanels Names to default /// public void ClearChanelNames() { ChanelNames.Clear(); AutoUpdateChanelsName(); } //Timer private async void TimerElapsed(object? o, ElapsedEventArgs? e) { GetActualValues(); AutoUpdateChanelsName(); if (EventUpdateValues != null) { await EventUpdateValues.Invoke(this, true); } } //Graph Data /// /// Get Chart data /// public void ReadChartData() { DateTime time = DateTime.Now; foreach (byte stack in ActualValues.Keys) { if (!GraphData.ContainsKey(stack)) { GraphData.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphData[stack].Add(new()); } } for (byte chanel = 0; chanel < 8; chanel++) { GraphData[stack][chanel].Add(new RTD8TMPointModel() { Value = ActualValues[stack][chanel], Time = time }); } } GetFilteredChartData(); } /// /// Get data for graph visualize /// /// saved chart chanel Data public List GetChartData(byte StackID, byte Chanel) { Console.WriteLine($"RTD8TMService:GetChartData({StackID}, {Chanel}) - start reading"); if (!GraphFiltered.ContainsKey(StackID)) { Console.WriteLine($"RTD8TMService:GetChartData({StackID}, {Chanel}) - Return new() - Unknow StackID - Stack_Keys: {JsonConvert.SerializeObject(GraphFiltered.Keys)}"); return new List(); } List RecalculatedData = new(); byte chanelRecalcTo = GetValueType(StackID, Chanel); RTD8TMChanelComponent _RTD8TMChanelComponent = new RTD8TMChanelComponent(); float LastValue = -1; int CountErrors = 0; foreach (RTD8TMPointModel point in GraphFiltered[StackID][Chanel]) { RTD8TMPointModel recalculated = new() { Time = point.Time, Value = _RTD8TMChanelComponent.RecalculateValues(point.Value, chanelRecalcTo) }; if (LastValue == -1 || CountErrors > 1 || (recalculated.Value >= (LastValue - 10) && recalculated.Value <= (LastValue + 10))) { RecalculatedData.Add(recalculated); LastValue = recalculated.Value; CountErrors = 0; } else { CountErrors++; } } Console.WriteLine($"RTD8TMService:GetChartData({StackID}, {Chanel})"); return RecalculatedData; } /// /// Clear data from Graph /// public void ClearChart() { GraphData.Clear(); } private async void GetFilteredChartData() { GraphFiltered = new SortedList>>(); foreach (byte stack in GraphData.Keys) { int pointsCount = GraphData[stack][0].Count; int counter = 0; Console.WriteLine($"RTD8TMService:GetFilteredChartData - Stack: {stack} | PointsCount: {pointsCount} | counter: {counter} | GraphData_Keys: {JsonConvert.SerializeObject(GraphData.Keys)}"); if (pointsCount < 100) { GraphFiltered = GraphData; } else if (pointsCount >= 100 && pointsCount < 500) // one from five { GraphFiltered.Add(stack, new List>()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 3) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } else if (pointsCount >= 500 && pointsCount < 1000) // one from ten { GraphFiltered.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 8) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } else if (pointsCount >= 1000 && pointsCount < 1500) // one from fifteen { GraphFiltered.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 13) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } else if (pointsCount >= 1500 && pointsCount < 2000) // one from twenty { GraphFiltered.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 18) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } else if (pointsCount >= 2000 && pointsCount < 3500) // one from TwentyFive { GraphFiltered.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 23) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } else if (pointsCount >= 3500) // one from twenty { GraphFiltered.Add(stack, new()); for (int chanel = 0; chanel < 8; chanel++) { GraphFiltered[stack].Add(new()); foreach (RTD8TMPointModel GraphPoint in GraphData[stack][chanel]) { if (counter > 28) { GraphFiltered[stack][chanel].Add(GraphPoint); counter = 0; } else { counter++; } } } } //případně další } if (EventUpdateGraph != null) { if (CountFilteredChartData() != GraphFilteredCountPoint) { GraphFilteredCountPoint = CountFilteredChartData(); await EventUpdateGraph.Invoke(this, true); } } Console.WriteLine($"RTD8TMService:GetFilteredChartData - GraphFiltered_Keys: {JsonConvert.SerializeObject(GraphFiltered.Keys)}"); } public int CountFilteredChartData() { foreach (byte stack in GraphFiltered.Keys) { return GraphFiltered[stack][0].Count; } return 0; } public int CountChartData() { foreach (byte stack in GraphData.Keys) { return GraphData[stack][0].Count; } return 0; } /// /// Get all Chart Data /// /// public SortedList>> GetAllChartData() { return GraphData; } /// /// Set Chart Data (used by syncservice) /// /// public void SetChartData(SortedList>> data) { Console.WriteLine($"RTD8TMService:SetChartData - {JsonConvert.SerializeObject(data)}"); GraphData = data; } //Values Types /// /// Set Value Type identifier /// /// Stack ID /// Chanel ID /// Value Type public void SetValueType(byte StackID, byte ChanelID, byte Type) { if (!ValuesType.ContainsKey(StackID)) { ValuesType.Add(StackID, new byte[8]); } ValuesType[StackID][ChanelID] = Type; } /// /// Get Value Type /// /// Stack ID /// Chanel ID /// Value Type public byte GetValueType(byte StackID, byte ChanelID) { if (ValuesType.ContainsKey(StackID)) { return ValuesType[StackID][ChanelID]; } else { return 0; } } /// /// Get ValueTypes From API /// public async void GetValueTypes() { if (Address == null) { return; } ValuesType = await _RTD8TM.GetValueTypes(Address); } /// /// Post ValueTypes to API /// public void PostValueTypes() { if (Address == null) { return; } _RTD8TM.PostValueTypes(Address, ValuesType); } public void ClearValueTypes() { ValuesType.Clear(); } //calibrations /// /// Read Calibrations from API /// private async void GetCalibrations() { if (Address == null) { return; } Calibrations = await _RTD8TM.GetCalibration(Address); foreach (byte stack in ActualValues.Keys) { if (!Calibrations.ContainsKey(stack)) { Calibrations.Add(stack, new float[8]); } } } /// /// Post calibrations to API /// public void PostCalibrations() { if (Address == null) { return; } _RTD8TM.PostCalibration(Address, Calibrations); } /// /// Get calibration of specific chanel /// /// /// /// public float GetCalibration(byte stack, byte chanel) { if (Calibrations.ContainsKey(stack)) { return Calibrations[stack][chanel]; } else { return 0; } } /// /// Set chanel Calibration Change /// /// /// /// public void SetCalibration(byte stack, byte chanel, float value) { if (!Calibrations.ContainsKey(stack)) { Calibrations.Add(stack, new float[8]); } Calibrations[stack][chanel] = value; } } }