334 lines
15 KiB
C#
334 lines
15 KiB
C#
using InnovEnergy.App.SodiStoreMax.Ess;
|
||
using InnovEnergy.Lib.Utils;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using static System.Double;
|
||
|
||
namespace InnovEnergy.App.SodiStoreMax.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 = CreateHourlyData("JsonLogDirectory",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 = CreateDailyData("HourlyData",currentTime.AddDays(-1).ToUnixTime(),currentTime.ToUnixTime());
|
||
dailyAggregatedData.Save("DailyData");
|
||
if (await dailyAggregatedData.PushToS3())
|
||
{
|
||
DeleteHourlyData("HourlyData",currentTime.ToUnixTime());
|
||
//AggregatedData.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 jsonFiles = Directory.GetFiles(myDirectory, "*.json");
|
||
//Console.WriteLine("Delete data before"+beforeTimestamp);
|
||
foreach (var jsonFile in jsonFiles)
|
||
{
|
||
if (IsFileWithinTimeRange(jsonFile, 0, beforeTimestamp))
|
||
{
|
||
File.Delete(jsonFile);
|
||
//Console.WriteLine($"Deleted hourly data file: {jsonFile}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private static AggregatedData CreateHourlyData(String myDirectory, Int64 afterTimestamp, Int64 beforeTimestamp)
|
||
{
|
||
// Get all json files in the specified directory
|
||
var jsonFiles = Directory.GetFiles(myDirectory, "*.json");
|
||
var batterySoc = new List<Double>();
|
||
var pvPowerSum = new List<Double>();
|
||
var gridPowerImport = new List<Double>();
|
||
var gridPowerExport = new List<Double>();
|
||
var batteryDischargePower = new List<Double>();
|
||
var batteryChargePower = new List<Double>();
|
||
|
||
foreach (var jsonFile in jsonFiles)
|
||
{
|
||
if (jsonFile == "JsonLogDirectory/log.json")
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (IsFileWithinTimeRange(jsonFile, afterTimestamp, beforeTimestamp))
|
||
{
|
||
try
|
||
|
||
{
|
||
// Read and parse JSON
|
||
|
||
var jsonData = File.ReadAllText(jsonFile);
|
||
|
||
// Step 2: Find the first '{' character and trim everything before it
|
||
int startIndex = jsonData.IndexOf('{');
|
||
if (startIndex != -1)
|
||
{
|
||
jsonData = jsonData.Substring(startIndex); // Trim everything before '{'
|
||
}
|
||
|
||
var jsonObject = JObject.Parse(jsonData);
|
||
|
||
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Soc"] != null)
|
||
{
|
||
batterySoc.Add((double)jsonObject["Battery"]["Soc"]);
|
||
}
|
||
if (jsonObject["PvOnDc"] != null && jsonObject["PvOnDc"]["DcWh"] != null)
|
||
{
|
||
pvPowerSum.Add((double)jsonObject["PvOnDc"]["DcWh"]);
|
||
}
|
||
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Power"] != null)
|
||
{
|
||
double batteryPower = (double)jsonObject["Battery"]["Power"];
|
||
if (batteryPower < 0)
|
||
batteryDischargePower.Add(batteryPower);
|
||
else
|
||
batteryChargePower.Add(batteryPower);
|
||
}
|
||
if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerExportT3"] != null)
|
||
{
|
||
gridPowerExport.Add((double)jsonObject["GridMeter"]["ActivePowerExportT3"]);
|
||
}
|
||
if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerImportT3"] != null)
|
||
{
|
||
gridPowerImport.Add((double)jsonObject["GridMeter"]["ActivePowerImportT3"]);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Console.WriteLine($"Failed to parse JSON file {jsonFile}: {e.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
//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 (1 seconds)
|
||
//
|
||
// Dividing the Average power readings by 3600 converts the result from watt-seconds to kilowatt-hours.
|
||
|
||
//Console.WriteLine("MAX IS "+gridPowerExport.Max());
|
||
// Console.WriteLine("MIN IS "+gridPowerExport.Min());
|
||
|
||
var dischargingEnergy = (batteryDischargePower.Any() ? batteryDischargePower.Average() : 0.0) / 3600;
|
||
var chargingEnergy = (batteryChargePower.Any() ? batteryChargePower.Average() : 0.0) / 3600;
|
||
|
||
var dMaxSoc = batterySoc.Any() ? batterySoc.Max() : 0.0;
|
||
var dMinSoc = batterySoc.Any() ? batterySoc.Min() : 0.0;
|
||
var dSumGridExportPower = gridPowerExport.Any() ? gridPowerExport.Max() - gridPowerExport.Min(): 0.0;
|
||
var dSumGridImportPower = gridPowerImport.Any() ? gridPowerImport.Max() - gridPowerImport.Min(): 0.0;
|
||
var dSumPvPower = pvPowerSum.Any() ? pvPowerSum.Max() : 0.0;
|
||
|
||
|
||
AggregatedData aggregatedData = new AggregatedData
|
||
{
|
||
MaxSoc = dMaxSoc,
|
||
MinSoc = dMinSoc,
|
||
DischargingBatteryPower = dischargingEnergy,
|
||
ChargingBatteryPower = chargingEnergy,
|
||
GridExportPower = dSumGridExportPower,
|
||
GridImportPower = dSumGridImportPower,
|
||
PvPower = dSumPvPower,
|
||
HeatingPower = 0
|
||
};
|
||
|
||
// Print the stored JSON data for verification
|
||
Console.WriteLine($"Max SOC: {aggregatedData.MaxSoc}");
|
||
Console.WriteLine($"Min SOC: {aggregatedData.MinSoc}");
|
||
|
||
Console.WriteLine($"DischargingBatteryBattery: {aggregatedData.DischargingBatteryPower}");
|
||
Console.WriteLine($"ChargingBatteryPower: {aggregatedData.ChargingBatteryPower}");
|
||
|
||
Console.WriteLine($"SumGridExportPower: {aggregatedData.GridExportPower}");
|
||
Console.WriteLine($"SumGridImportPower: {aggregatedData.GridImportPower}");
|
||
|
||
Console.WriteLine($"Min SOC: {aggregatedData.MinSoc}");
|
||
|
||
|
||
Console.WriteLine("JSON data reading and storage completed.");
|
||
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||
|
||
return aggregatedData;
|
||
}
|
||
|
||
private static AggregatedData CreateDailyData(String myDirectory, Int64 afterTimestamp, Int64 beforeTimestamp)
|
||
{
|
||
// Get all JSON files in the specified directory
|
||
var jsonFiles = Directory.GetFiles(myDirectory, "*.json");
|
||
var batterySoc = new List<Double>();
|
||
var pvPower = new List<Double>();
|
||
var gridPowerImport = new List<Double>();
|
||
var gridPowerExport = new List<Double>();
|
||
var batteryDischargePower = new List<Double>();
|
||
var batteryChargePower = new List<Double>();
|
||
var heatingPowerAvg = new List<Double>();
|
||
|
||
foreach (var jsonFile in jsonFiles)
|
||
{
|
||
if (jsonFile == "JsonLogDirectory/log.json")
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (IsFileWithinTimeRange(jsonFile, afterTimestamp, beforeTimestamp))
|
||
{
|
||
|
||
try
|
||
{
|
||
var jsonData = File.ReadAllText(jsonFile);
|
||
|
||
// Parse JSON into a Dictionary
|
||
var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, Double>>(jsonData);
|
||
|
||
// Process values
|
||
foreach (var (variableName, value) in jsonDict)
|
||
{
|
||
switch (variableName)
|
||
{
|
||
case "MinSoc":
|
||
case "MaxSoc":
|
||
batterySoc.Add(value);
|
||
break;
|
||
|
||
case "PvPower":
|
||
pvPower.Add(value);
|
||
break;
|
||
|
||
case "DischargingBatteryPower":
|
||
batteryDischargePower.Add(value);
|
||
break;
|
||
|
||
case "ChargingBatteryPower":
|
||
batteryChargePower.Add(value);
|
||
break;
|
||
|
||
case "GridExportPower":
|
||
gridPowerExport.Add(value);
|
||
break;
|
||
|
||
case "GridImportPower":
|
||
gridPowerImport.Add(value);
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Console.WriteLine($"Failed to parse JSON file {jsonFile}: {e.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
AggregatedData aggregatedData = new AggregatedData
|
||
{
|
||
MaxSoc = batterySoc.Any() ? batterySoc.Max() : 0.0,
|
||
MinSoc = batterySoc.Any() ? batterySoc.Min() : 0.0,
|
||
DischargingBatteryPower = batteryDischargePower.Any() ? batteryDischargePower.Average(): 0.0,
|
||
ChargingBatteryPower = batteryChargePower.Any() ? batteryChargePower.Average() : 0.0,
|
||
GridExportPower = gridPowerExport.Any() ? gridPowerExport.Sum() : 0.0,
|
||
GridImportPower = gridPowerImport.Any() ? gridPowerImport.Sum() : 0.0,
|
||
PvPower = pvPower.Any() ? pvPower.Last() : 0.0,
|
||
HeatingPower = heatingPowerAvg.Any() ? heatingPowerAvg.Average() : 0.0,
|
||
};
|
||
|
||
// Print the stored JSON data for verification
|
||
Console.WriteLine($"Pv Power: {aggregatedData.PvPower}");
|
||
Console.WriteLine($"Heating Power: {aggregatedData.HeatingPower}");
|
||
Console.WriteLine($"Max SOC: {aggregatedData.MaxSoc}");
|
||
Console.WriteLine($"Min SOC: {aggregatedData.MinSoc}");
|
||
|
||
Console.WriteLine($"ChargingBatteryPower: {aggregatedData.DischargingBatteryPower}");
|
||
Console.WriteLine($"DischargingBatteryBattery: {aggregatedData.ChargingBatteryPower}");
|
||
|
||
Console.WriteLine($"SumGridExportPower: {aggregatedData.GridExportPower}");
|
||
Console.WriteLine($"SumGridImportPower: {aggregatedData.GridImportPower}");
|
||
|
||
|
||
|
||
Console.WriteLine("JSON 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;
|
||
}
|
||
} |