Compare commits

..

No commits in common. "8646790824becb3aa1ffb762865fce2cacf4ee1d" and "775c7a1785afa93f06a8d3a8fd5c4ad52c042edb" have entirely different histories.

6 changed files with 410 additions and 327 deletions

View File

@ -17,8 +17,6 @@ dotnet publish \
echo -e "\n============================ Deploy ============================\n"
ip_addresses=("10.2.3.115" "10.2.3.104" "10.2.4.33" "10.2.4.32" "10.2.4.36" "10.2.4.35" "10.2.4.154" "10.2.4.113" "10.2.4.29")
#ip_addresses=("10.2.4.154" "10.2.4.29")
for ip_address in "${ip_addresses[@]}"; do
rsync -v \

View File

@ -1,5 +1,3 @@
using System.IO.Compression;
using System.Text;
using System.Text.Json;
using Flurl.Http;
using InnovEnergy.App.SaliMax.Devices;
@ -70,37 +68,7 @@ public class AggregatedData
var s3Path = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + ".csv";
var request = _S3Config.CreatePutRequest(s3Path);
// Compress CSV data to a byte array
byte[] compressedBytes;
using (var memoryStream = new MemoryStream())
{
//Create a zip directory and put the compressed file inside
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var entry = archive.CreateEntry("data.csv", CompressionLevel.SmallestSize); // Add CSV data to the ZIP archive
using (var entryStream = entry.Open())
using (var writer = new StreamWriter(entryStream))
{
writer.Write(csv);
}
}
compressedBytes = memoryStream.ToArray();
}
// Encode the compressed byte array as a Base64 string
string base64String = Convert.ToBase64String(compressedBytes);
// Create StringContent from Base64 string
var stringContent = new StringContent(base64String, Encoding.UTF8, "application/base64");
// Upload the compressed data (ZIP archive) to S3
var response = await request.PutAsync(stringContent);
//
// var request = _S3Config.CreatePutRequest(s3Path);
// var response = await request.PutAsync(new StringContent(csv));
var response = await request.PutAsync(new StringContent(csv));
if (response.StatusCode != 200)
{

View File

@ -31,21 +31,6 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
const currentLocation = useLocation();
const sortedInstallations = [...props.installations].sort((a, b) => {
// Compare the status field of each installation and sort them based on the status.
//Installations with alarms go first
let a_status = getStatus(a.id);
let b_status = getStatus(b.id);
if (a_status > b_status) {
return -1;
}
if (a_status < b_status) {
return 1;
}
return 0;
});
const handleSelectOneInstallation = (installationID: number): void => {
if (selectedInstallation != installationID) {
setSelectedInstallation(installationID);
@ -115,7 +100,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
</TableRow>
</TableHead>
<TableBody>
{sortedInstallations.map((installation) => {
{props.installations.map((installation) => {
const isInstallationSelected =
installation.s3BucketId === selectedInstallation;

View File

@ -58,16 +58,8 @@ export const fetchData = (
if (r.status === 404) {
return Promise.resolve(FetchResult.notAvailable);
} else if (r.status === 200) {
const csvtext = await r.text(); // Assuming the server returns the Base64 encoded ZIP file as text
//const response = await fetch(url); // Fetch the resource from the server
const contentEncoding = r.headers.get('content-type');
if (contentEncoding != 'application/base64; charset=utf-8') {
return parseCsv(csvtext);
}
const byteArray = Uint8Array.from(atob(csvtext), (c) =>
const base64String = await r.text(); // Assuming the server returns the Base64 encoded ZIP file as text
const byteArray = Uint8Array.from(atob(base64String), (c) =>
c.charCodeAt(0)
);
@ -75,7 +67,6 @@ export const fetchData = (
const zip = await JSZip.loadAsync(byteArray);
// Assuming the CSV file is named "data.csv" inside the ZIP archive
const csvContent = await zip.file('data.csv').async('text');
return parseCsv(csvContent);
} else {
return Promise.resolve(FetchResult.notAvailable);

View File

@ -45,10 +45,14 @@ function Overview(props: OverviewProps) {
const { currentUser } = context;
const [dailyData, setDailyData] = useState(true);
const [aggregatedData, setAggregatedData] = useState(false);
const [weeklyData, setWeeklyData] = useState(false);
const [weeklybalance, setWeeklyBalance] = useState([]);
const [monthlybalance, setMonthlyBalance] = useState([]);
const [monthlyData, setMonthlyData] = useState(false);
const [loading, setLoading] = useState(true);
const [chartState, setChartState] = useState(0);
const [aggregatedChartState, setAggregatedChartState] = useState(0);
const [monthlyDateList, setMonthlyDateList] = useState([]);
const [weeklyDateList, setWeeklyDateList] = useState([]);
const [isDateModalOpen, setIsDateModalOpen] = useState(false);
const [isErrorDateModalOpen, setErrorDateModalOpen] = useState(false);
const [dateSelectionError, setDateSelectionError] = useState('');
@ -60,18 +64,19 @@ function Overview(props: OverviewProps) {
}[]
>([]);
const [aggregatedDataArray, setAggregatedDataArray] = useState<
{
chartData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
datelist: any[];
netbalance: any[];
}[]
>([]);
const [startDate, setStartDate] = useState(dayjs().add(-1, 'day'));
const [endDate, setEndDate] = useState(dayjs());
const [weeklyDataArray, setWeeklyDataArray] = useState<{
chartData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
}>({ chartData: null, chartOverview: null });
const [monthlyDataArray, setMonthlyDataArray] = useState<{
chartData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
}>({ chartData: null, chartOverview: null });
useEffect(() => {
const resultPromise: Promise<{
chartData: chartDataInterface;
@ -130,19 +135,17 @@ function Overview(props: OverviewProps) {
const handle24HourData = () => {
setDailyData(true);
setAggregatedData(false);
setWeeklyData(false);
setMonthlyData(false);
setChartState(0);
};
const handleWeekData = () => {
setDailyData(false);
setAggregatedData(true);
setAggregatedChartState(0);
setWeeklyData(true);
setMonthlyData(false);
if (
aggregatedDataArray[aggregatedChartState] &&
aggregatedDataArray[aggregatedChartState].chartData != null
) {
if (weeklyDataArray.chartData != null) {
return;
}
setLoading(true);
@ -150,15 +153,15 @@ function Overview(props: OverviewProps) {
const resultPromise: Promise<{
chartAggregatedData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
}> = transformInputToAggregatedData(
props.s3Credentials,
dayjs().subtract(1, 'week'),
dayjs()
);
}> = transformInputToAggregatedData(props.s3Credentials, 'weekly');
resultPromise
.then((result) => {
setWeeklyDataArray({
chartData: result.chartAggregatedData,
chartOverview: result.chartOverview
});
const powerDifference = [];
for (
let i = 0;
@ -171,16 +174,8 @@ function Overview(props: OverviewProps) {
);
}
setAggregatedDataArray((prevData) =>
prevData.concat({
chartData: result.chartAggregatedData,
chartOverview: result.chartOverview,
datelist: computeLast7Days(),
netbalance: powerDifference
})
);
setAggregatedChartState(aggregatedDataArray.length);
setWeeklyBalance(powerDifference);
setWeeklyDateList(computeLast7Days());
setLoading(false);
})
.catch((error) => {
@ -217,8 +212,6 @@ function Overview(props: OverviewProps) {
}
setLoading(true);
if (dailyData) {
const resultPromise: Promise<{
chartData: chartDataInterface;
chartOverview: overviewInterface;
@ -243,24 +236,43 @@ function Overview(props: OverviewProps) {
.catch((error) => {
console.error('Error:', error);
});
} else {
setDailyData(false);
setAggregatedData(true);
};
const handleGoBack = () => {
if (chartState > 0) {
setChartState(chartState - 1);
}
};
const handleGoForward = () => {
if (chartState + 1 < dailyDataArray.length) {
setChartState(chartState + 1);
}
};
const handleMonthData = () => {
setDailyData(false);
setWeeklyData(false);
setMonthlyData(true);
if (monthlyDataArray.chartData != null) {
return;
}
setLoading(true);
const resultPromise: Promise<{
chartAggregatedData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
dateList: string[];
}> = transformInputToAggregatedData(
props.s3Credentials,
startDate,
endDate
);
}> = transformInputToAggregatedData(props.s3Credentials, 'monthly');
resultPromise
.then((result) => {
setMonthlyDataArray({
chartData: result.chartAggregatedData,
chartOverview: result.chartOverview
});
const powerDifference = [];
for (
@ -274,43 +286,14 @@ function Overview(props: OverviewProps) {
);
}
setAggregatedDataArray((prevData) =>
prevData.concat({
chartData: result.chartAggregatedData,
chartOverview: result.chartOverview,
datelist: result.dateList,
netbalance: powerDifference
})
);
setMonthlyBalance(powerDifference);
setAggregatedChartState(aggregatedDataArray.length);
setMonthlyDateList(result.dateList);
setLoading(false);
})
.catch((error) => {
console.error('Error:', error);
});
}
};
const handleGoBack = () => {
if (dailyData && chartState > 0) {
setChartState(chartState - 1);
}
if (aggregatedData && aggregatedChartState > 0) {
setAggregatedChartState(aggregatedChartState - 1);
}
};
const handleGoForward = () => {
if (dailyData && chartState + 1 < dailyDataArray.length) {
setChartState(chartState + 1);
}
if (
aggregatedData &&
aggregatedChartState + 1 < aggregatedDataArray.length
) {
setAggregatedChartState(aggregatedChartState + 1);
}
};
const renderGraphs = () => {
@ -455,14 +438,29 @@ function Overview(props: OverviewProps) {
sx={{
marginTop: '20px',
marginLeft: '10px',
backgroundColor: aggregatedData ? '#808080' : '#ffc04d',
backgroundColor: weeklyData ? '#808080' : '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage id="lastweek" defaultMessage="Last week" />
</Button>
{/*<Button*/}
{/* variant="contained"*/}
{/* onClick={handleMonthData}*/}
{/* disabled={loading}*/}
{/* sx={{*/}
{/* marginTop: '20px',*/}
{/* marginLeft: '10px',*/}
{/* backgroundColor: monthlyData ? '#808080' : '#ffc04d',*/}
{/* color: '#000000',*/}
{/* '&:hover': { bgcolor: '#f7b34d' }*/}
{/* }}*/}
{/*>*/}
{/* <FormattedMessage id="lastmonth" defaultMessage="Last Month" />*/}
{/*</Button>*/}
{dailyData && (
<>
<Button
variant="contained"
onClick={handleSetDate}
@ -477,8 +475,10 @@ function Overview(props: OverviewProps) {
>
<FormattedMessage id="lastmonth" defaultMessage="Set Date" />
</Button>
</>
)}
</Grid>
{dailyData && (
<Grid
container
justifyContent="flex-end"
@ -489,9 +489,7 @@ function Overview(props: OverviewProps) {
>
<Button
variant="contained"
disabled={
dailyData ? !(chartState > 0) : !(aggregatedChartState > 0)
}
disabled={!(chartState > 0)}
onClick={handleGoBack}
sx={{
marginTop: '20px',
@ -506,11 +504,7 @@ function Overview(props: OverviewProps) {
<Button
variant="contained"
disabled={
dailyData
? !(chartState < dailyDataArray.length - 1)
: !(aggregatedChartState < aggregatedDataArray.length - 1)
}
disabled={!(chartState < dailyDataArray.length - 1)}
onClick={handleGoForward}
sx={{
marginTop: '20px',
@ -523,6 +517,7 @@ function Overview(props: OverviewProps) {
<FormattedMessage id="goback" defaultMessage="Zoom in" />
</Button>
</Grid>
)}
{loading && (
<Container
@ -624,7 +619,7 @@ function Overview(props: OverviewProps) {
</Grid>
)}
{aggregatedData && (
{(weeklyData || monthlyData) && (
<Grid
container
direction="row"
@ -665,32 +660,29 @@ function Overview(props: OverviewProps) {
></Box>
</Box>
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.overview,
weeklyDataArray.chartOverview.overview,
'overview',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
true
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.gridImportPower,
...weeklyDataArray.chartData.gridImportPower,
color: '#b30000',
type: 'bar'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.gridExportPower,
...weeklyDataArray.chartData.gridExportPower,
color: '#ff3333',
type: 'bar'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.pvProduction,
...weeklyDataArray.chartData.pvProduction,
type: 'bar',
color: '#ff9900'
},
@ -698,13 +690,51 @@ function Overview(props: OverviewProps) {
name: 'Net Energy',
color: '#ff3333',
type: 'line',
data: aggregatedDataArray[aggregatedChartState]
.netbalance
data: weeklybalance
}
]}
height={400}
type={'bar'}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.overview,
'overview',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.gridImportPower,
color: '#b30000',
type: 'bar'
},
{
...monthlyDataArray.chartData.gridExportPower,
color: '#ff3333',
type: 'bar'
},
{
...monthlyDataArray.chartData.pvProduction,
color: '#ff9900',
type: 'bar'
},
{
name: 'Net Energy',
type: 'line',
data: monthlybalance,
color: '#666666'
}
]}
height={400}
type={'bar'}
/>
)}
</Card>
</Grid>
</Grid>
@ -776,26 +806,48 @@ function Overview(props: OverviewProps) {
/>
)}
{aggregatedData && (
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.soc,
weeklyDataArray.chartOverview.soc,
'weekly',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
true
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.minsoc,
...weeklyDataArray.chartData.minsoc,
color: '#69d2e7'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.maxsoc,
...weeklyDataArray.chartData.maxsoc,
color: '#008FFB'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.soc,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.minsoc,
color: '#69d2e7'
},
{
...monthlyDataArray.chartData.maxsoc,
color: '#008FFB'
}
]}
@ -866,31 +918,27 @@ function Overview(props: OverviewProps) {
/>
)}
{aggregatedData && currentUser.userType == UserType.admin && (
{weeklyData && currentUser.userType == UserType.admin && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.dcPower,
weeklyDataArray.chartOverview.dcPower,
'weekly',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
false
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.dcChargingPower,
...weeklyDataArray.chartData.dcChargingPower,
color: '#008FFB'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.heatingPower,
...weeklyDataArray.chartData.heatingPower,
color: '#ff9900'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.dcDischargingPower,
...weeklyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
@ -899,27 +947,80 @@ function Overview(props: OverviewProps) {
/>
)}
{aggregatedData && currentUser.userType == UserType.client && (
{weeklyData && currentUser.userType == UserType.client && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.dcPowerWithoutHeating,
weeklyDataArray.chartOverview.dcPowerWithoutHeating,
'weekly',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
true
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.dcChargingPower,
...weeklyDataArray.chartData.dcChargingPower,
color: '#008FFB'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.dcDischargingPower,
...weeklyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && currentUser.userType == UserType.admin && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.dcPower,
'monthly',
monthlyDateList,
false
)
}}
series={[
{
...monthlyDataArray.chartData.dcChargingPower,
color: '#008FFB'
},
{
...weeklyDataArray.chartData.heatingPower,
color: '#ff9900'
},
{
...monthlyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && currentUser.userType == UserType.client && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview
.dcPowerWithoutHeating,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.dcChargingPower,
color: '#008FFB'
},
{
...monthlyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
@ -1127,21 +1228,40 @@ function Overview(props: OverviewProps) {
/>
)}
{aggregatedData && (
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.pvProduction,
weeklyDataArray.chartOverview.pvProduction,
'weekly',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
true
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.pvProduction,
...weeklyDataArray.chartData.pvProduction,
color: '#ff9900'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.pvProduction,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.pvProduction,
color: '#ff9900'
}
]}
@ -1210,27 +1330,49 @@ function Overview(props: OverviewProps) {
height={400}
/>
)}
{aggregatedData && (
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
aggregatedDataArray[aggregatedChartState]
.chartOverview.gridPower,
weeklyDataArray.chartOverview.gridPower,
'weekly',
aggregatedDataArray[aggregatedChartState].datelist,
weeklyDateList,
true
)
}}
series={[
{
...aggregatedDataArray[aggregatedChartState]
.chartData.gridImportPower,
...weeklyDataArray.chartData.gridImportPower,
color: '#b30000'
},
{
...aggregatedDataArray[aggregatedChartState]
.chartData.gridExportPower,
...weeklyDataArray.chartData.gridExportPower,
color: '#ff3333'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.gridPower,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.gridImportPower,
color: '#b30000'
},
{
...monthlyDataArray.chartData.gridExportPower,
color: '#ff3333'
}
]}

View File

@ -424,8 +424,7 @@ export const transformInputToDailyData = async (
export const transformInputToAggregatedData = async (
s3Credentials: I_S3Credentials,
start_date: dayjs.Dayjs,
end_date: dayjs.Dayjs
type: string
): Promise<{
chartAggregatedData: chartAggregatedDataInterface;
chartOverview: overviewInterface;
@ -436,11 +435,11 @@ export const transformInputToAggregatedData = async (
const MAX_NUMBER = 9999999;
const dateList = [];
//let currentDate = dayjs();
let currentDay = start_date;
// type === 'weekly'
// ? currentDate.subtract(1, 'week')
// : currentDate.subtract(1, 'month');
let currentDate = dayjs();
let currentDay =
type === 'weekly'
? currentDate.subtract(1, 'week')
: currentDate.subtract(1, 'month');
const pathsToSearch = [
'/MinSoc',
@ -498,7 +497,7 @@ export const transformInputToAggregatedData = async (
const timestampPromises = [];
while (currentDay.isBefore(end_date)) {
while (currentDay.isBefore(currentDate)) {
timestampPromises.push(
fetchDailyData(currentDay.format('YYYY-MM-DD'), s3Credentials)
);
@ -506,7 +505,7 @@ export const transformInputToAggregatedData = async (
}
const results = await Promise.all(timestampPromises);
currentDay = start_date;
currentDay = currentDate.subtract(1, 'month');
for (let i = 0; i < results.length; i++) {
const result = results[i];