diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index 873b8faa7..904346a73 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -92,12 +92,13 @@ internal static class Program public static async Task Main(String[] args) { + //Do not await + HourlyDataAggregationManager(); + InitializeCommunicationToMiddleware(); while (true) { - //CreateAverage(); try { - InitializeCommunicationToMiddleware(); await Run(); } catch (Exception e) @@ -105,7 +106,6 @@ internal static class Program e.LogError(); } } - // ReSharper disable once FunctionNeverReturns } private static void InitializeCommunicationToMiddleware() @@ -635,83 +635,125 @@ internal static class Program return true; } - - private static void CreateAverage() + + + private static async Task HourlyDataAggregationManager() { - string myDirectory = "LogDirectoryNew"; - List> csvDataList = new List>(); + DateTime currentDateTime = DateTime.Now; + DateTime nextRoundedHour = currentDateTime.AddHours(1).AddMinutes(-currentDateTime.Minute).AddSeconds(-currentDateTime.Second); + + // Calculate the time until the next rounded hour + TimeSpan timeUntilNextHour = nextRoundedHour - currentDateTime; + + // 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 " + timeUntilNextHour.TotalMinutes + " minutes..."); + + // Wait until the next rounded hour + await Task.Delay(timeUntilNextHour); + + while (true) + { + try + { + CreateHourlyAverage(); + } + catch (Exception e) + { + Console.WriteLine("An error has occured when calculating hourly aggregated data, exception is:\n" + e); + } + await Task.Delay(TimeSpan.FromHours(1)); + } + } + + private static void CreateHourlyAverage() + { + string myDirectory = "LogDirectory"; // Get all CSV files in the specified directory string[] csvFiles = Directory.GetFiles(myDirectory, "*.csv"); - - List socList = new List(); - List pvPowerList = new List(); - List batteryPowerList = new List(); - + + Int64 currentTimestamp = DateTime.Now.ToUnixTime(); + Double socAverage=0; + Double pvPowerAverage=0; + Double batteryPowerAverage=0; + Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); + Console.WriteLine("File timestamp should start after "+DateTime.Now.AddHours(-1)); foreach (var csvFile in csvFiles) { - using (var reader = new StreamReader(csvFile)) - { - // Read the CSV file and store data in dictionary - Dictionary csvData = new Dictionary(); - - while (!reader.EndOfStream) - { - var line = reader.ReadLine(); - var values = line?.Split(';'); - // Assuming there are always three columns (variable name and its value) - if (values is { Length: 3 }) + if (csvFile == "LogDirectory/log.csv") + { + continue; + } + Int64 fileTimestamp = Int64.Parse(Path.GetFileNameWithoutExtension(csvFile).Replace("log_", "")); + Int64 oneHourBefore = DateTime.Now.AddHours(-1).ToUnixTime(); + + + if (fileTimestamp >= oneHourBefore && fileTimestamp <= currentTimestamp) + { + Console.WriteLine("Check file created at "+DateTimeOffset.FromUnixTimeSeconds(fileTimestamp).DateTime); + using (var reader = new StreamReader(csvFile)) + { + while (!reader.EndOfStream) { - String variableName = values[0].Trim(); - String variableValue = values[1].Trim(); - - // Check if variableValue is a valid number - if (IsSoc(variableName)) + var line = reader.ReadLine(); + var values = line?.Split(';'); + + // Assuming there are always three columns (variable name and its value) + if (values is { Length: 3 }) { - // Add to the dictionary only if variableValue is a number - socList.Add(double.TryParse(variableValue, out double v)? v: 0); - } - if (IsPvPower(variableName)) - { - // Add to the dictionary only if variableValue is a number - pvPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); - } - if (IsBatteryPower(variableName)) - { - // Add to the dictionary only if variableValue is a number - batteryPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); + String variableName = values[0].Trim(); + String variableValue = values[1].Trim(); + + // Check if variableValue is a valid number + if (IsSoc(variableName)) + { + if (socAverage == 0){socAverage = double.TryParse(variableValue, out double v) ? v : 0;} + else{socAverage = (socAverage + (double.TryParse(variableValue, out double v) ? v : 0)) / 2;} + } + + if (IsPvPower(variableName)) + { + if (pvPowerAverage == 0){pvPowerAverage = double.TryParse(variableValue, out double v) ? v : 0;} + else{pvPowerAverage = (pvPowerAverage + (double.TryParse(variableValue, out double v) ? v : 0)) / 2;} + } + + if (IsBatteryPower(variableName)) + { + if (batteryPowerAverage == 0){batteryPowerAverage = double.TryParse(variableValue, out double v) ? v : 0;} + else{batteryPowerAverage = (batteryPowerAverage + (double.TryParse(variableValue, out double v) ? v : 0)) / 2;} + } + else + { + // Handle cases where variableValue is not a valid number + // Console.WriteLine($"Invalid numeric value for variable {variableName}: {variableValue}"); + } } else { - // Handle cases where variableValue is not a valid number - // Console.WriteLine($"Invalid numeric value for variable {variableName}: {variableValue}"); + // Handle invalid CSV format + //Console.WriteLine($"Invalid format in file: {csvFile}"); + //break; } } - else - { - // Handle invalid CSV format - //Console.WriteLine($"Invalid format in file: {csvFile}"); - //break; - } } } } - - double socAverage = CalculateAverage(socList); - double pvPowerAverage = CalculateAverage(pvPowerList); - double batteryPowerAverage = CalculateAverage(batteryPowerList); - // Print the stored CSV data for verification Console.WriteLine($"SOC: {socAverage}"); Console.WriteLine($"PvPower: {pvPowerAverage}"); Console.WriteLine($"Battery: {batteryPowerAverage}"); - Console.WriteLine("----------"); - Console.WriteLine("CSV data reading and storage completed."); + //Create a new file to folder "Hourly Aggregated Data and push it to S3" + Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); + } // Custom method to check if a string is numeric @@ -736,12 +778,5 @@ internal static class Program status.Config.GridSetPoint = config.GridSetPoint*1000; status.Config.ForceCalibrationCharge = config.ForceCalibrationCharge; } - - // Method to calculate average for a variableValue in a dictionary - static double CalculateAverage( List data) - { - // Calculate and return the moving average - double movingAverage = data.Average(); - return movingAverage; - } + } \ No newline at end of file diff --git a/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx b/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx index e47198b1b..c142bf34c 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx @@ -21,6 +21,7 @@ export const getChartOptions = (chartInfo: chartInfoInterface): ApexOptions => { // Return the formatted date and time based on the provided options return ` ${hour}:${minute}`; }; + const chartOptions: ApexOptions = { chart: { id: 'area-datetime', diff --git a/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx b/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx index f246ac3e3..48b5b54ca 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx @@ -25,6 +25,7 @@ import { chartDataInterface, overviewInterface } from 'src/interfaces/Chart'; import { fetchData } from 'src/content/dashboards/Installations/fetchData'; import Button from '@mui/material/Button'; import { FormattedMessage } from 'react-intl'; +import { ApexOptions } from 'apexcharts'; const prefixes = ['', 'k', 'M', 'G', 'T']; const MAX_NUMBER = 9999999; @@ -314,6 +315,80 @@ function Overview(props: OverviewProps) { times$.next(times); }; + const series = [ + { + name: 'Inflation', + data: [2.3, 3.1, 4.0, 10.1, 4.0, 3.6, 3.2, 2.3, 1.4, 0.8, 0.5, 0.2] + } + ]; + + const state: ApexOptions = { + chart: { + height: 350, + type: 'bar' + }, + plotOptions: { + bar: { + borderRadius: 10, + dataLabels: { + position: 'top' // top, center, bottom + } + } + }, + dataLabels: { + enabled: true, + formatter: function (val) { + return val + '%'; + }, + offsetY: -20, + style: { + fontSize: '12px', + colors: ['#304758'] + } + }, + + xaxis: { + categories: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec' + ], + position: 'bottom', + axisBorder: { + show: false + }, + axisTicks: { + show: false + }, + tooltip: { + enabled: true + } + }, + yaxis: { + axisBorder: { + show: false + }, + axisTicks: { + show: false + }, + labels: { + show: false, + formatter: function (val) { + return val + '%'; + } + } + } + }; + const renderGraphs = () => { return ( @@ -399,19 +474,27 @@ function Overview(props: OverviewProps) { }} > + + + {/**/}