Updated aggregation service
This commit is contained in:
parent
bc9b3b95b9
commit
b13ff6efbe
|
@ -15,11 +15,12 @@ public static class Aggregator
|
||||||
var timeUntilNextHour = nextRoundedHour - currentDateTime;
|
var timeUntilNextHour = nextRoundedHour - currentDateTime;
|
||||||
|
|
||||||
// Output the current and next rounded hour times
|
// Output the current and next rounded hour times
|
||||||
|
Console.WriteLine("------------------------------------------HourlyDataAggregationManager-------------------------------------------");
|
||||||
Console.WriteLine("Current Date and Time: " + currentDateTime);
|
Console.WriteLine("Current Date and Time: " + currentDateTime);
|
||||||
Console.WriteLine("Next Rounded Hour: " + nextRoundedHour);
|
Console.WriteLine("Next Rounded Hour: " + nextRoundedHour);
|
||||||
|
|
||||||
// Output the time until the next rounded hour
|
// Output the time until the next rounded hour
|
||||||
Console.WriteLine("Waiting for " + timeUntilNextHour.TotalMinutes + " minutes...");
|
Console.WriteLine("Waiting for " + timeUntilNextHour.TotalMinutes + " minutes...");
|
||||||
|
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
// Wait until the next rounded hour
|
// Wait until the next rounded hour
|
||||||
await Task.Delay(timeUntilNextHour);
|
await Task.Delay(timeUntilNextHour);
|
||||||
|
@ -28,7 +29,8 @@ public static class Aggregator
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CreateHourlyAverage();
|
AggregatedData hourlyAggregatedData=CreateAverage("LogDirectory",DateTime.Now.AddHours(-1).ToUnixTime(),DateTime.Now.ToUnixTime());
|
||||||
|
hourlyAggregatedData.Save("HourlyData");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -38,22 +40,50 @@ public static class Aggregator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateHourlyAverage()
|
public static async Task DailyDataAggregationManager()
|
||||||
{
|
{
|
||||||
var myDirectory = "LogDirectory";
|
var currentDateTime = DateTime.Now;
|
||||||
|
var nextRoundedHour = currentDateTime.AddDays(1).AddHours(-currentDateTime.Hour).AddMinutes(-currentDateTime.Minute).AddSeconds(-currentDateTime.Second);
|
||||||
|
|
||||||
|
// Calculate the time until the next rounded hour
|
||||||
|
var timeUntilNextDay = nextRoundedHour - currentDateTime;
|
||||||
|
Console.WriteLine("------------------------------------------DailyDataAggregationManager-------------------------------------------");
|
||||||
|
// Output the current and next rounded hour times
|
||||||
|
Console.WriteLine("Current Date and Time: " + currentDateTime);
|
||||||
|
Console.WriteLine("Next Rounded Hour: " + nextRoundedHour);
|
||||||
|
// Output the time until the next rounded hour
|
||||||
|
Console.WriteLine("Waiting for " + timeUntilNextDay.TotalHours + " hours...");
|
||||||
|
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
|
||||||
|
// Wait until the next rounded hour
|
||||||
|
await Task.Delay(timeUntilNextDay);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AggregatedData dailyAggregatedData=CreateAverage("HourlyData",DateTime.Now.AddDays(-1).ToUnixTime(),DateTime.Now.ToUnixTime());
|
||||||
|
dailyAggregatedData.Save("DailyData");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("An error has occured when calculating daily aggregated data, exception is:\n" + e);
|
||||||
|
}
|
||||||
|
await Task.Delay(TimeSpan.FromHours(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AggregatedData CreateAverage(string myDirectory,long afterTimestamp,long beforeTimestamp)
|
||||||
|
{
|
||||||
// Get all CSV files in the specified directory
|
// Get all CSV files in the specified directory
|
||||||
var csvFiles = Directory.GetFiles(myDirectory, "*.csv");
|
var csvFiles = Directory.GetFiles(myDirectory, "*.csv");
|
||||||
|
|
||||||
var currentTimestamp = DateTime.Now.ToUnixTime();
|
|
||||||
var oneHourBefore = DateTime.Now.AddHours(-1).ToUnixTime();
|
|
||||||
|
|
||||||
var socAverage = new List<Double>();
|
var socAverage = new List<Double>();
|
||||||
var pvPowerAverage = new List<Double>();
|
var pvPowerAverage = new List<Double>();
|
||||||
var batteryPowerAverage = new List<Double>();
|
var batteryPowerAverage = new List<Double>();
|
||||||
|
|
||||||
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||||||
Console.WriteLine("File timestamp should start after "+ DateTime.Now.AddHours(-1));
|
Console.WriteLine("File timestamp should start after "+ afterTimestamp);
|
||||||
|
|
||||||
foreach (var csvFile in csvFiles)
|
foreach (var csvFile in csvFiles)
|
||||||
{
|
{
|
||||||
|
@ -62,7 +92,7 @@ public static class Aggregator
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsFileWithinTimeRange(csvFile, oneHourBefore, currentTimestamp))
|
if (IsFileWithinTimeRange(csvFile, afterTimestamp, beforeTimestamp))
|
||||||
{
|
{
|
||||||
using var reader = new StreamReader(csvFile);
|
using var reader = new StreamReader(csvFile);
|
||||||
|
|
||||||
|
@ -71,6 +101,7 @@ public static class Aggregator
|
||||||
|
|
||||||
var line = reader.ReadLine();
|
var line = reader.ReadLine();
|
||||||
var lines = line?.Split(';');
|
var lines = line?.Split(';');
|
||||||
|
|
||||||
|
|
||||||
// Assuming there are always three columns (variable name and its value)
|
// Assuming there are always three columns (variable name and its value)
|
||||||
if (lines is { Length: 3 })
|
if (lines is { Length: 3 })
|
||||||
|
@ -81,18 +112,15 @@ public static class Aggregator
|
||||||
{
|
{
|
||||||
switch (variableName)
|
switch (variableName)
|
||||||
{
|
{
|
||||||
case var _ when GetVariable(variableName,"/Battery/Soc"):
|
case var _ when variableName is "/Battery/Soc" or "/AvgSoc" :
|
||||||
// Code to execute when variableName matches IsSoc condition
|
|
||||||
socAverage.Add(value);
|
socAverage.Add(value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case var _ when GetVariable(variableName, "/PvOnDc/Dc/Power"):
|
case var _ when variableName is "/PvOnDc/Dc/Power" or "/AvgPvPower":
|
||||||
// Code to execute when variableName matches IsPvPower condition
|
|
||||||
pvPowerAverage.Add(value);
|
pvPowerAverage.Add(value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case var _ when GetVariable(variableName, "/Battery/Dc/Power"):
|
case var _ when variableName is "/Battery/Dc/Power" or "/BatteryPowerAverage":
|
||||||
// Code to execute when variableName matches IsBatteryPower condition
|
|
||||||
batteryPowerAverage.Add(value);
|
batteryPowerAverage.Add(value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -105,37 +133,38 @@ public static class Aggregator
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Handle cases where variableValue is not a valid number
|
//Handle cases where variableValue is not a valid number
|
||||||
Console.WriteLine(
|
// Console.WriteLine(
|
||||||
$"Invalid numeric value for variable {variableName}:{lines[1].Trim()}");
|
// $"Invalid numeric value for variable {variableName}:{lines[1].Trim()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Handle invalid column format
|
// Handle invalid column format
|
||||||
Console.WriteLine("Invalid format in column");
|
//Console.WriteLine("Invalid format in column");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the average of values
|
AggregatedData aggregatedData = new AggregatedData
|
||||||
var avgSoc = socAverage.Any() ? socAverage.Average() : 0.0;
|
{
|
||||||
var avgPvPower = pvPowerAverage.Any() ? pvPowerAverage.Average() : 0.0;
|
AvgSoc = socAverage.Any() ? socAverage.Average() : 0.0,
|
||||||
var avgBatteryPower = batteryPowerAverage.Any() ? batteryPowerAverage.Average() : 0.0;
|
AvgPvPower = pvPowerAverage.Any() ? pvPowerAverage.Average() : 0.0,
|
||||||
|
BatteryPowerAverage = batteryPowerAverage.Any() ? batteryPowerAverage.Average() : 0.0
|
||||||
|
};
|
||||||
|
|
||||||
// Print the stored CSV data for verification
|
// Print the stored CSV data for verification
|
||||||
|
Console.WriteLine($"SOC: {aggregatedData.AvgSoc}");
|
||||||
Console.WriteLine($"SOC: {avgSoc}");
|
Console.WriteLine($"PvPower: {aggregatedData.AvgPvPower}");
|
||||||
Console.WriteLine($"PvPower: {avgPvPower}");
|
Console.WriteLine($"Battery: {aggregatedData.BatteryPowerAverage}");
|
||||||
Console.WriteLine($"Battery: {avgBatteryPower}");
|
|
||||||
|
|
||||||
Console.WriteLine("CSV data reading and storage completed.");
|
Console.WriteLine("CSV data reading and storage completed.");
|
||||||
//Create a new file to folder "Hourly Aggregated Data and push it to S3"
|
|
||||||
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
return aggregatedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Custom method to check if a string is numeric
|
// Custom method to check if a string is numeric
|
||||||
private static Boolean GetVariable(String value, String path)
|
private static Boolean GetVariable(String value, String path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using InnovEnergy.App.SaliMax.Devices;
|
using InnovEnergy.App.SaliMax.Devices;
|
||||||
|
using InnovEnergy.Lib.Units;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using static System.Text.Json.JsonSerializer;
|
using static System.Text.Json.JsonSerializer;
|
||||||
|
|
||||||
|
@ -7,49 +8,31 @@ namespace InnovEnergy.App.SaliMax.AggregationService;
|
||||||
// shut up trim warnings
|
// shut up trim warnings
|
||||||
#pragma warning disable IL2026
|
#pragma warning disable IL2026
|
||||||
|
|
||||||
public class HourlyData //TODO: let IE choose from config files (Json) and connect to GUI
|
public class AggregatedData
|
||||||
{
|
{
|
||||||
private static String DefaultHDataPath => Path.Combine(Environment.CurrentDirectory, "HourlyData/config.json");
|
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
||||||
|
|
||||||
public required Double MinSoc { get; set; }
|
public required Double AvgSoc { get; set; }
|
||||||
public required Double MaxChargeBatteryVoltage { get; set; }
|
public required Double AvgPvPower { get; set; }
|
||||||
public required Double MinDischargeBatteryVoltage { get; set; }
|
public required Double BatteryPowerAverage { get; set; }
|
||||||
private static String? LastSavedData { get; set; }
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
public static HourlyData Default => new()
|
|
||||||
{
|
|
||||||
MinSoc = 20,
|
|
||||||
MaxChargeBatteryVoltage = 0,
|
|
||||||
MinDischargeBatteryVoltage = 0
|
|
||||||
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
public static HourlyData Default => new()
|
|
||||||
{
|
|
||||||
MinSoc = 20,
|
|
||||||
MaxChargeBatteryVoltage = 0,
|
|
||||||
MinDischargeBatteryVoltage = 0
|
|
||||||
|
|
||||||
};
|
public void Save(String directory)
|
||||||
#endif
|
|
||||||
|
|
||||||
public void Save(String? path = null)
|
|
||||||
{
|
{
|
||||||
var dataFilePath = path ?? DefaultHDataPath;
|
var date = DateTime.Now.ToUnixTime();
|
||||||
|
var defaultHDataPath = Environment.CurrentDirectory + "/"+directory+"/";
|
||||||
|
var dataFilePath = defaultHDataPath+date+".csv";
|
||||||
|
|
||||||
|
if (!Directory.Exists(defaultHDataPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(defaultHDataPath);
|
||||||
|
Console.WriteLine("Directory created successfully.");
|
||||||
|
}
|
||||||
|
Console.WriteLine("data file path is "+dataFilePath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var jsonString = Serialize(this, JsonOptions);
|
var csvString = Units.ToCsv(this);
|
||||||
|
File.WriteAllText(dataFilePath, csvString);
|
||||||
if (LastSavedData == jsonString)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LastSavedData = jsonString;
|
|
||||||
|
|
||||||
File.WriteAllText(dataFilePath, jsonString);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -58,35 +41,18 @@ public class HourlyData //TODO: let IE choose from config files (Json) and conne
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HourlyData Load(String? path = null)
|
// public static HourlyData? Load(String dataFilePath)
|
||||||
{
|
// {
|
||||||
var dataFilePath = path ?? DefaultHDataPath;
|
// try
|
||||||
try
|
// {
|
||||||
{
|
// var csvString = File.ReadAllText(dataFilePath);
|
||||||
var jsonString = File.ReadAllText(dataFilePath);
|
// return Deserialize<HourlyData>(jsonString)!;
|
||||||
return Deserialize<HourlyData>(jsonString)!;
|
// }
|
||||||
}
|
// catch (Exception e)
|
||||||
catch (Exception e)
|
// {
|
||||||
{
|
// $"Failed to read config file {dataFilePath}, using default config\n{e}".WriteLine();
|
||||||
$"Failed to read config file {dataFilePath}, using default config\n{e}".WriteLine();
|
// return null;
|
||||||
return Default;
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static async Task<HourlyData> LoadAsync(String? path = null)
|
|
||||||
{
|
|
||||||
var dataFilePath = path ?? DefaultHDataPath;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var jsonString = await File.ReadAllTextAsync(dataFilePath);
|
|
||||||
return Deserialize<HourlyData>(jsonString)!;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Couldn't read config file {dataFilePath}, using default config");
|
|
||||||
e.Message.WriteLine();
|
|
||||||
return Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -82,6 +82,7 @@ internal static class Program
|
||||||
{
|
{
|
||||||
//Do not await
|
//Do not await
|
||||||
Aggregator.HourlyDataAggregationManager().ContinueWith(t=>t.Exception.WriteLine(), TaskContinuationOptions.OnlyOnFaulted).SupressAwaitWarning();
|
Aggregator.HourlyDataAggregationManager().ContinueWith(t=>t.Exception.WriteLine(), TaskContinuationOptions.OnlyOnFaulted).SupressAwaitWarning();
|
||||||
|
Aggregator.DailyDataAggregationManager().ContinueWith(t=>t.Exception.WriteLine(), TaskContinuationOptions.OnlyOnFaulted).SupressAwaitWarning();
|
||||||
MiddlewareAgent.InitializeCommunicationToMiddleware();
|
MiddlewareAgent.InitializeCommunicationToMiddleware();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue