Innovenergy_trunk/csharp/App/SaliMax/src/AggregationService/Aggregator.cs

243 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using InnovEnergy.App.SaliMax.Ess;
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
{
var currentTime = DateTime.Now;
AggregatedData dailyAggregatedData = CreateAverage("HourlyData",currentTime.AddDays(-1).ToUnixTime(),currentTime.ToUnixTime());
dailyAggregatedData.Save("DailyData");
if (await dailyAggregatedData.PushToS3())
{
DeleteHourlyData("HourlyData",currentTime.ToUnixTime());
dailyAggregatedData.DeleteDailyData("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 void DeleteHourlyData(String myDirectory, Int64 beforeTimestamp)
{
var csvFiles = Directory.GetFiles(myDirectory, "*.csv");
Console.WriteLine("Delete data before"+beforeTimestamp);
foreach (var csvFile in csvFiles)
{
if (IsFileWithinTimeRange(csvFile, 0, beforeTimestamp))
{
File.Delete(csvFile);
Console.WriteLine($"Deleted hourly data file: {csvFile}");
}
}
}
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 batterySoc = new List<Double>();
var batteryAvgSoc = new List<Double>(); // this is only used for the daily data.
var pvPowerAverage = new List<Double>();
var gridPowerImport = new List<Double>();
var gridPowerExport = new List<Double>();
var batteryDischargePower = new List<Double>();
var batteryChargePower = new List<Double>();
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 "/MinSoc" or "/MaxSoc":
batterySoc.Add(value);
break;
case "/PvOnDc/DcWh" or "/SumPvPower":
pvPowerAverage.Add(value);
break;
case "/Battery/Dc/Power" or "/SumDischargingBatteryPower" or "/SumChargingBatteryPower":
//Average Power (Watts)= Sum of Power Readings/Number of Readings
//Then, you can use the average power in the energy formula:
//
//Energy (kWh)= (Average Power / 3600) × Time (seconds)
//
// Dividing the Average power readings by 3600 converts the result from watt-seconds to kilowatt-hours.
if (value < 0)
{
batteryDischargePower.Add(value);
}
else
{
batteryChargePower.Add(value);
}
break;
case "/GridMeter/ActivePowerExportT2" or "/SumGridExportPower":
// we are using different register to check which value from the grid meter we need to use
gridPowerExport.Add(value);
break;
case "/GridMeter/ActivePowerImportT2" or "/SumGridImportPower":
gridPowerImport.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
{
MaxSoc = batterySoc.Any() ? batterySoc.Max() : 0.0,
MinSoc = batterySoc.Any() ? batterySoc.Min() : 0.0,
SumDischargingBatteryPower = batteryDischargePower.Any() ? batteryDischargePower.Average(): 0.0,
SumChargingBatteryPower = batteryChargePower.Any() ? batteryChargePower.Average() : 0.0,
SumGridExportPower = gridPowerExport.Any() ? gridPowerExport.Average() : 0.0,
SumGridImportPower = gridPowerImport.Any() ? gridPowerImport.Average() : 0.0,
SumPvPower = pvPowerAverage.Any() ? pvPowerAverage.Average() : 0.0,
};
// Print the stored CSV data for verification
Console.WriteLine($"Max SOC: {aggregatedData.MaxSoc}");
Console.WriteLine($"Min SOC: {aggregatedData.MinSoc}");
Console.WriteLine($"ChargingBatteryPower: {aggregatedData.SumDischargingBatteryPower}");
Console.WriteLine($"DischargingBatteryBattery: {aggregatedData.SumChargingBatteryPower}");
Console.WriteLine($"SumGridExportPower: {aggregatedData.SumGridExportPower}");
Console.WriteLine($"SumGridImportPower: {aggregatedData.SumGridImportPower}");
Console.WriteLine($"Min SOC: {aggregatedData.MinSoc}");
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;
}
}