UI_SequentMicrosystems-RPI/Services/RTD8TMService.cs

662 lines
20 KiB
C#

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<byte, string[]> ChanelNames = new SortedList<byte, string[]>();
private SortedList<byte, float[]> ActualValues = new SortedList<byte, float[]>();
private SortedList<byte, byte[]> ValuesType = new SortedList<byte, byte[]>();
private SortedList<byte, float[]> Calibrations = new SortedList<byte, float[]>();
public SortedList<byte, List<List<RTD8TMPointModel>>> GraphData = new();
public SortedList<byte, List<List<RTD8TMPointModel>>> 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<TEventArgs>(object? sender, TEventArgs? e);
public event AsyncEventHandler<bool>? EventUpdateValues;
public event AsyncEventHandler<bool>? EventUpdateGraph;
public RTD8TMService()
{
_timer.AutoReset = true;
_timer.Elapsed += TimerElapsed;
_timer.Start();
}
//Main Parameters Work
/// <summary>
/// Set Device Address
/// </summary>
/// <param name="address">Address [Base url] (http://1.2.3.4)</param>
public void SetAddress(string address)
{
Address = address;
GetChanelsNames();
GetValueTypes();
GetCalibrations();
}
/// <summary>
/// Get used device Address
/// </summary>
/// <returns>Address or empty string</returns>
public string GetAddress()
{
if (Address == null)
{
return "";
}
else
{
return Address;
}
}
//Actual Data
/// <summary>
/// Read Actual values from Device
/// </summary>
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}");
}
}
/// <summary>
/// Request for actual data
/// </summary>
/// <returns></returns>
public SortedList<byte, float[]> GetActualData()
{
return ActualValues;
}
/// <summary>
/// Get actual data Value
/// </summary>
/// <param name="stack">Stack ID</param>
/// <param name="chanel">Chanel ID</param>
/// <returns>Measure Resistance</returns>
public float GetActualData(byte stack, byte chanel)
{
if (ActualValues.ContainsKey(stack))
{
return ActualValues[stack][chanel];
}
else
{
return 0;
}
}
//ChanelsNames
/// <summary>
/// Read configured chanels Names from Device
/// </summary>
public async void GetChanelsNames()
{
if (Address == null) return;
ChanelNames = await _RTD8TM.GetNames(Address);
AutoUpdateChanelsName();
}
/// <summary>
/// Set new Chanels Names
/// </summary>
/// <param name="names">chanels names sorted list</param>
#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);
}
/// <summary>
/// Update Chanels Names for not null loading names
/// </summary>
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] = "----------";
}
}
}
}
/// <summary>
/// Get chanel names
/// </summary>
/// <returns>Chanels names object</returns>
public SortedList<byte, string[]> GetChanelNames()
{
return ChanelNames;
}
/// <summary>
/// Set chanel Name
/// </summary>
/// <param name="stack">Stack ID</param>
/// <param name="chanel">Chanel ID</param>
/// <param name="name">New Name</param>
public void SetChanelNames(byte stack, byte chanel, string name)
{
if (!ChanelNames.ContainsKey(stack))
{
ChanelNames.Add(stack, new string[8]);
}
ChanelNames[stack][chanel] = name;
}
/// <summary>
/// Read chanel name
/// </summary>
/// <param name="stack">Stack ID</param>
/// <param name="chanel">Chanel ID</param>
/// <returns>Chanel name</returns>
public string GetChanelName(byte stack, byte chanel)
{
if (ChanelNames.ContainsKey(stack))
{
return ChanelNames[stack][chanel];
}
else
{
return "----------";
}
}
/// <summary>
/// Clear chanels Names to default
/// </summary>
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
/// <summary>
/// Get Chart data
/// </summary>
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();
}
/// <summary>
/// Get data for graph visualize
/// </summary>
/// <returns>saved chart chanel Data</returns>
public List<RTD8TMPointModel> 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<RTD8TMPointModel>();
}
List<RTD8TMPointModel> 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;
}
/// <summary>
/// Clear data from Graph
/// </summary>
public void ClearChart()
{
GraphData.Clear();
}
private async void GetFilteredChartData()
{
GraphFiltered = new SortedList<byte, List<List<RTD8TMPointModel>>>();
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<List<RTD8TMPointModel>>());
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;
}
/// <summary>
/// Get all Chart Data
/// </summary>
/// <returns></returns>
public SortedList<byte, List<List<RTD8TMPointModel>>> GetAllChartData()
{
return GraphData;
}
/// <summary>
/// Set Chart Data (used by syncservice)
/// </summary>
/// <param name="data"></param>
public void SetChartData(SortedList<byte, List<List<RTD8TMPointModel>>> data)
{
Console.WriteLine($"RTD8TMService:SetChartData - {JsonConvert.SerializeObject(data)}");
GraphData = data;
}
//Values Types
/// <summary>
/// Set Value Type identifier
/// </summary>
/// <param name="StackID">Stack ID</param>
/// <param name="ChanelID">Chanel ID</param>
/// <param name="Type">Value Type</param>
public void SetValueType(byte StackID, byte ChanelID, byte Type)
{
if (!ValuesType.ContainsKey(StackID))
{
ValuesType.Add(StackID, new byte[8]);
}
ValuesType[StackID][ChanelID] = Type;
}
/// <summary>
/// Get Value Type
/// </summary>
/// <param name="StackID">Stack ID</param>
/// <param name="ChanelID">Chanel ID</param>
/// <returns>Value Type</returns>
public byte GetValueType(byte StackID, byte ChanelID)
{
if (ValuesType.ContainsKey(StackID))
{
return ValuesType[StackID][ChanelID];
}
else
{
return 0;
}
}
/// <summary>
/// Get ValueTypes From API
/// </summary>
public async void GetValueTypes()
{
if (Address == null) { return; }
ValuesType = await _RTD8TM.GetValueTypes(Address);
}
/// <summary>
/// Post ValueTypes to API
/// </summary>
public void PostValueTypes()
{
if (Address == null) { return; }
_RTD8TM.PostValueTypes(Address, ValuesType);
}
public void ClearValueTypes()
{
ValuesType.Clear();
}
//calibrations
/// <summary>
/// Read Calibrations from API
/// </summary>
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]);
}
}
}
/// <summary>
/// Post calibrations to API
/// </summary>
public void PostCalibrations()
{
if (Address == null) { return; }
_RTD8TM.PostCalibration(Address, Calibrations);
}
/// <summary>
/// Get calibration of specific chanel
/// </summary>
/// <param name="stack"></param>
/// <param name="chanel"></param>
/// <returns></returns>
public float GetCalibration(byte stack, byte chanel)
{
if (Calibrations.ContainsKey(stack))
{
return Calibrations[stack][chanel];
}
else
{
return 0;
}
}
/// <summary>
/// Set chanel Calibration Change
/// </summary>
/// <param name="stack"></param>
/// <param name="chanel"></param>
/// <param name="value"></param>
public void SetCalibration(byte stack, byte chanel, float value)
{
if (!Calibrations.ContainsKey(stack))
{
Calibrations.Add(stack, new float[8]);
}
Calibrations[stack][chanel] = value;
}
}
}