Add Hourly-Data-Aggregation function

This commit is contained in:
Noe 2023-12-11 17:15:26 +01:00
parent 69602e6bd6
commit 7bc70f49f6
3 changed files with 192 additions and 73 deletions

View File

@ -92,12 +92,13 @@ internal static class Program
public static async Task Main(String[] args) public static async Task Main(String[] args)
{ {
//Do not await
HourlyDataAggregationManager();
InitializeCommunicationToMiddleware();
while (true) while (true)
{ {
//CreateAverage();
try try
{ {
InitializeCommunicationToMiddleware();
await Run(); await Run();
} }
catch (Exception e) catch (Exception e)
@ -105,7 +106,6 @@ internal static class Program
e.LogError(); e.LogError();
} }
} }
// ReSharper disable once FunctionNeverReturns
} }
private static void InitializeCommunicationToMiddleware() private static void InitializeCommunicationToMiddleware()
@ -636,82 +636,124 @@ internal static class Program
return true; return true;
} }
private static void CreateAverage()
private static async Task HourlyDataAggregationManager()
{ {
string myDirectory = "LogDirectoryNew"; DateTime currentDateTime = DateTime.Now;
List<Dictionary<string, string>> csvDataList = new List<Dictionary<string, string>>(); 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 // Get all CSV files in the specified directory
string[] csvFiles = Directory.GetFiles(myDirectory, "*.csv"); string[] csvFiles = Directory.GetFiles(myDirectory, "*.csv");
List<Double> socList = new List<Double>(); Int64 currentTimestamp = DateTime.Now.ToUnixTime();
List<Double> pvPowerList = new List<Double>(); Double socAverage=0;
List<Double> batteryPowerList = new List<Double>(); Double pvPowerAverage=0;
Double batteryPowerAverage=0;
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
Console.WriteLine("File timestamp should start after "+DateTime.Now.AddHours(-1));
foreach (var csvFile in csvFiles) foreach (var csvFile in csvFiles)
{ {
using (var reader = new StreamReader(csvFile))
if (csvFile == "LogDirectory/log.csv")
{ {
// Read the CSV file and store data in dictionary continue;
Dictionary<string, string> csvData = new Dictionary<string, string>(); }
Int64 fileTimestamp = Int64.Parse(Path.GetFileNameWithoutExtension(csvFile).Replace("log_", ""));
Int64 oneHourBefore = DateTime.Now.AddHours(-1).ToUnixTime();
while (!reader.EndOfStream)
if (fileTimestamp >= oneHourBefore && fileTimestamp <= currentTimestamp)
{
Console.WriteLine("Check file created at "+DateTimeOffset.FromUnixTimeSeconds(fileTimestamp).DateTime);
using (var reader = new StreamReader(csvFile))
{ {
var line = reader.ReadLine(); while (!reader.EndOfStream)
var values = line?.Split(';');
// Assuming there are always three columns (variable name and its value)
if (values is { Length: 3 })
{ {
String variableName = values[0].Trim(); var line = reader.ReadLine();
String variableValue = values[1].Trim(); var values = line?.Split(';');
// Check if variableValue is a valid number // Assuming there are always three columns (variable name and its value)
if (IsSoc(variableName)) if (values is { Length: 3 })
{ {
// Add to the dictionary only if variableValue is a number String variableName = values[0].Trim();
socList.Add(double.TryParse(variableValue, out double v)? v: 0); String variableValue = values[1].Trim();
}
if (IsPvPower(variableName)) // Check if variableValue is a valid number
{ if (IsSoc(variableName))
// Add to the dictionary only if variableValue is a number {
pvPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); 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 (IsBatteryPower(variableName)) }
{
// Add to the dictionary only if variableValue is a number if (IsPvPower(variableName))
batteryPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); {
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 else
{ {
// Handle cases where variableValue is not a valid number // Handle invalid CSV format
// Console.WriteLine($"Invalid numeric value for variable {variableName}: {variableValue}"); //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 // Print the stored CSV data for verification
Console.WriteLine($"SOC: {socAverage}"); Console.WriteLine($"SOC: {socAverage}");
Console.WriteLine($"PvPower: {pvPowerAverage}"); Console.WriteLine($"PvPower: {pvPowerAverage}");
Console.WriteLine($"Battery: {batteryPowerAverage}"); Console.WriteLine($"Battery: {batteryPowerAverage}");
Console.WriteLine("----------");
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("-----------------------------------------------------------------------------------------------------------------");
} }
// Custom method to check if a string is numeric // Custom method to check if a string is numeric
@ -737,11 +779,4 @@ internal static class Program
status.Config.ForceCalibrationCharge = config.ForceCalibrationCharge; status.Config.ForceCalibrationCharge = config.ForceCalibrationCharge;
} }
// Method to calculate average for a variableValue in a dictionary
static double CalculateAverage( List<Double> data)
{
// Calculate and return the moving average
double movingAverage = data.Average();
return movingAverage;
}
} }

View File

@ -21,6 +21,7 @@ export const getChartOptions = (chartInfo: chartInfoInterface): ApexOptions => {
// Return the formatted date and time based on the provided options // Return the formatted date and time based on the provided options
return ` ${hour}:${minute}`; return ` ${hour}:${minute}`;
}; };
const chartOptions: ApexOptions = { const chartOptions: ApexOptions = {
chart: { chart: {
id: 'area-datetime', id: 'area-datetime',

View File

@ -25,6 +25,7 @@ import { chartDataInterface, overviewInterface } from 'src/interfaces/Chart';
import { fetchData } from 'src/content/dashboards/Installations/fetchData'; import { fetchData } from 'src/content/dashboards/Installations/fetchData';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { ApexOptions } from 'apexcharts';
const prefixes = ['', 'k', 'M', 'G', 'T']; const prefixes = ['', 'k', 'M', 'G', 'T'];
const MAX_NUMBER = 9999999; const MAX_NUMBER = 9999999;
@ -314,6 +315,80 @@ function Overview(props: OverviewProps) {
times$.next(times); 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 = () => { const renderGraphs = () => {
return ( return (
<Container maxWidth="xl"> <Container maxWidth="xl">
@ -399,19 +474,27 @@ function Overview(props: OverviewProps) {
}} }}
></Box> ></Box>
</Box> </Box>
<ReactApexChart <ReactApexChart
options={{ options={state}
...getChartOptions(chartOverview.soc), series={series}
chart: { type="bar"
events: {
beforeZoom: handleBeforeZoom
}
}
}}
series={chartData.soc}
type="area"
height={350} height={350}
/> />
{/*<ReactApexChart*/}
{/* options={{*/}
{/* ...getChartOptions(chartOverview.soc),*/}
{/* chart: {*/}
{/* events: {*/}
{/* beforeZoom: handleBeforeZoom*/}
{/* }*/}
{/* }*/}
{/* }}*/}
{/* series={chartData.soc}*/}
{/* type="area"*/}
{/* height={350}*/}
{/*/>*/}
</Card> </Card>
</Grid> </Grid>
<Grid item md={6} xs={12}> <Grid item md={6} xs={12}>