Add Hourly-Data-Aggregation function
This commit is contained in:
parent
69602e6bd6
commit
7bc70f49f6
|
@ -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()
|
||||||
|
@ -635,83 +635,125 @@ 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))
|
|
||||||
{
|
|
||||||
// Read the CSV file and store data in dictionary
|
|
||||||
Dictionary<string, string> csvData = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
while (!reader.EndOfStream)
|
|
||||||
{
|
|
||||||
var line = reader.ReadLine();
|
|
||||||
var values = line?.Split(';');
|
|
||||||
|
|
||||||
// Assuming there are always three columns (variable name and its value)
|
if (csvFile == "LogDirectory/log.csv")
|
||||||
if (values is { Length: 3 })
|
{
|
||||||
|
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();
|
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
|
||||||
|
@ -736,12 +778,5 @@ internal static class Program
|
||||||
status.Config.GridSetPoint = config.GridSetPoint*1000;
|
status.Config.GridSetPoint = config.GridSetPoint*1000;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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',
|
||||||
|
|
|
@ -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}>
|
||||||
|
|
Loading…
Reference in New Issue