using InnovEnergy.Lib.Utils; using static System.Double; namespace InnovEnergy.App.SaliMax.AggregationService; public static class Aggregator { public static async Task HourlyDataAggregationManager() { var currentDateTime = DateTime.Now; var nextRoundedHour = currentDateTime.AddHours(1).AddMinutes(-currentDateTime.Minute).AddSeconds(-currentDateTime.Second); // Calculate the time until the next rounded hour var timeUntilNextHour = nextRoundedHour - currentDateTime; // Output the current and next rounded hour times Console.WriteLine("------------------------------------------HourlyDataAggregationManager-------------------------------------------"); 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 " + timeUntilNextHour.TotalMinutes + " minutes..."); Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); // Wait until the next rounded hour await Task.Delay(timeUntilNextHour); while (true) { try { AggregatedData hourlyAggregatedData = CreateAverage("LogDirectory",DateTime.Now.AddHours(-1).ToUnixTime(),DateTime.Now.ToUnixTime()); hourlyAggregatedData.Save("HourlyData"); } catch (Exception e) { Console.WriteLine("An error has occured when calculating hourly aggregated data, exception is:\n" + e); } await Task.Delay(TimeSpan.FromHours(1)); } } public static async Task DailyDataAggregationManager() { 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.FromDays(1)); } } private static AggregatedData CreateAverage(String myDirectory, Int64 afterTimestamp, Int64 beforeTimestamp) { // Get all CSV files in the specified directory var csvFiles = Directory.GetFiles(myDirectory, "*.csv"); var socAverage = new List(); var pvPowerAverage = new List(); var batteryPowerAverage = new List(); Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); Console.WriteLine("File timestamp should start after "+ afterTimestamp); foreach (var csvFile in csvFiles) { if (csvFile == "LogDirectory/log.csv") { continue; } if (IsFileWithinTimeRange(csvFile, afterTimestamp, beforeTimestamp)) { using var reader = new StreamReader(csvFile); while (!reader.EndOfStream) { var line = reader.ReadLine(); var lines = line?.Split(';'); // Assuming there are always three columns (variable name and its value) if (lines is { Length: 3 }) { var variableName = lines[0].Trim(); if (TryParse(lines[1].Trim(), out var value)) { switch (variableName) { case "/Battery/Soc" or "/AvgSoc": socAverage.Add(value); break; case "/PvOnDc/Dc/Power" or "/AvgPvPower": pvPowerAverage.Add(value); break; case "/Battery/Dc/Power" or "/BatteryPowerAverage": batteryPowerAverage.Add(value); break; // Add more cases as needed default: // Code to execute when variableName doesn't match any condition break; } } else { //Handle cases where variableValue is not a valid number // Console.WriteLine( // $"Invalid numeric value for variable {variableName}:{lines[1].Trim()}"); } } else { // Handle invalid column format //Console.WriteLine("Invalid format in column"); } } } } AggregatedData aggregatedData = new AggregatedData { AvgSoc = socAverage.Any() ? socAverage.Average() : 0.0, AvgPvPower = pvPowerAverage.Any() ? pvPowerAverage.Average() : 0.0, BatteryPowerAverage = batteryPowerAverage.Any() ? batteryPowerAverage.Average() : 0.0 }; // Print the stored CSV data for verification Console.WriteLine($"SOC: {aggregatedData.AvgSoc}"); Console.WriteLine($"PvPower: {aggregatedData.AvgPvPower}"); Console.WriteLine($"Battery: {aggregatedData.BatteryPowerAverage}"); Console.WriteLine("CSV data reading and storage completed."); Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); return aggregatedData; } // Custom method to check if a string is numeric private static Boolean GetVariable(String value, String path) { return value == path; } private static Boolean IsFileWithinTimeRange(string filePath, long startTime, long endTime) { var fileTimestamp = long.TryParse(Path.GetFileNameWithoutExtension(filePath).Replace("log_", ""), out var fileTimestamp1) ? fileTimestamp1 : -1; return fileTimestamp >= startTime && fileTimestamp < endTime; } }