added Main Stats on Battery View page for SodistoreHome
This commit is contained in:
parent
1b6d5a5916
commit
ed1efbddeb
|
|
@ -12,13 +12,14 @@ import {
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { JSONRecordData } from '../Log/graph.util';
|
import { JSONRecordData } from '../Log/graph.util';
|
||||||
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
import { Link, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { I_S3Credentials } from '../../../interfaces/S3Types';
|
import { I_S3Credentials } from '../../../interfaces/S3Types';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||||
|
import MainStatsSodioHome from './MainStatsSodioHome';
|
||||||
|
|
||||||
interface BatteryViewSodioHomeProps {
|
interface BatteryViewSodioHomeProps {
|
||||||
values: JSONRecordData;
|
values: JSONRecordData;
|
||||||
|
|
@ -164,54 +165,20 @@ function BatteryViewSodioHome(props: BatteryViewSodioHomeProps) {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/*<Grid container>*/}
|
<Grid container>
|
||||||
{/* <Routes>*/}
|
<Routes>
|
||||||
{/* <Route*/}
|
<Route
|
||||||
{/* path={routes.mainstats + '/*'}*/}
|
path={routes.mainstats + '/*'}
|
||||||
{/* element={*/}
|
element={
|
||||||
{/* <MainStats*/}
|
<MainStatsSodioHome
|
||||||
{/* s3Credentials={props.s3Credentials}*/}
|
s3Credentials={props.s3Credentials}
|
||||||
{/* id={props.installationId}*/}
|
id={props.installationId}
|
||||||
{/* ></MainStats>*/}
|
batteryClusterNumber={props.installation.batteryClusterNumber}
|
||||||
{/* }*/}
|
></MainStatsSodioHome>
|
||||||
{/* />*/}
|
}
|
||||||
{/* {product === 0*/}
|
/>
|
||||||
{/* ? Object.entries(props.values.Battery.Devices).map(*/}
|
</Routes>
|
||||||
{/* ([BatteryId, battery]) => (*/}
|
</Grid>
|
||||||
{/* <Route*/}
|
|
||||||
{/* key={routes.detailed_view + BatteryId}*/}
|
|
||||||
{/* path={routes.detailed_view + BatteryId}*/}
|
|
||||||
{/* element={*/}
|
|
||||||
{/* <DetailedBatteryView*/}
|
|
||||||
{/* batteryId={Number(BatteryId)}*/}
|
|
||||||
{/* s3Credentials={props.s3Credentials}*/}
|
|
||||||
{/* batteryData={battery}*/}
|
|
||||||
{/* installationId={props.installationId}*/}
|
|
||||||
{/* productNum={product}*/}
|
|
||||||
{/* ></DetailedBatteryView>*/}
|
|
||||||
{/* }*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* )*/}
|
|
||||||
{/* )*/}
|
|
||||||
{/* : Object.entries(props.values.Battery.Devices).map(*/}
|
|
||||||
{/* ([BatteryId, battery]) => (*/}
|
|
||||||
{/* <Route*/}
|
|
||||||
{/* key={routes.detailed_view + BatteryId}*/}
|
|
||||||
{/* path={routes.detailed_view + BatteryId}*/}
|
|
||||||
{/* element={*/}
|
|
||||||
{/* <DetailedBatteryViewSodistore*/}
|
|
||||||
{/* batteryId={Number(BatteryId)}*/}
|
|
||||||
{/* s3Credentials={props.s3Credentials}*/}
|
|
||||||
{/* batteryData={battery}*/}
|
|
||||||
{/* installationId={props.installationId}*/}
|
|
||||||
{/* productNum={product}*/}
|
|
||||||
{/* ></DetailedBatteryViewSodistore>*/}
|
|
||||||
{/* }*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* )*/}
|
|
||||||
{/* )}*/}
|
|
||||||
{/* </Routes>*/}
|
|
||||||
{/*</Grid>*/}
|
|
||||||
|
|
||||||
<TableContainer
|
<TableContainer
|
||||||
component={Paper}
|
component={Paper}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,818 @@
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
Container,
|
||||||
|
Grid,
|
||||||
|
IconButton,
|
||||||
|
Modal,
|
||||||
|
TextField,
|
||||||
|
Typography
|
||||||
|
} from '@mui/material';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { I_S3Credentials } from '../../../interfaces/S3Types';
|
||||||
|
import ReactApexChart from 'react-apexcharts';
|
||||||
|
import { getChartOptions } from '../Overview/chartOptions';
|
||||||
|
import {
|
||||||
|
BatteryDataInterface,
|
||||||
|
BatteryOverviewInterface,
|
||||||
|
transformInputToBatteryViewDataJson
|
||||||
|
} from '../../../interfaces/Chart';
|
||||||
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import { TimeSpan, UnixTime } from '../../../dataCache/time';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||||
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||||
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
|
|
||||||
|
interface MainStatsSodioHomeProps {
|
||||||
|
s3Credentials: I_S3Credentials;
|
||||||
|
id: number;
|
||||||
|
batteryClusterNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MainStatsSodioHome(props: MainStatsSodioHomeProps) {
|
||||||
|
const [chartState, setChartState] = useState(0);
|
||||||
|
const [batteryViewDataArray, setBatteryViewDataArray] = useState<
|
||||||
|
{
|
||||||
|
chartData: BatteryDataInterface;
|
||||||
|
chartOverview: BatteryOverviewInterface;
|
||||||
|
}[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [isDateModalOpen, setIsDateModalOpen] = useState(false);
|
||||||
|
const [dateOpen, setDateOpen] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [startDate, setStartDate] = useState(dayjs().add(-1, 'day'));
|
||||||
|
const [endDate, setEndDate] = useState(dayjs());
|
||||||
|
const [isErrorDateModalOpen, setErrorDateModalOpen] = useState(false);
|
||||||
|
const [dateSelectionError, setDateSelectionError] = useState('');
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
const blueColors = [
|
||||||
|
'#99CCFF',
|
||||||
|
'#80BFFF',
|
||||||
|
'#6699CC',
|
||||||
|
'#4D99FF',
|
||||||
|
'#2670E6',
|
||||||
|
'#3366CC',
|
||||||
|
'#1A4D99',
|
||||||
|
'#133366',
|
||||||
|
'#0D274D',
|
||||||
|
'#081A33'
|
||||||
|
];
|
||||||
|
const redColors = [
|
||||||
|
'#ff9090',
|
||||||
|
'#ff7070',
|
||||||
|
'#ff3f3f',
|
||||||
|
'#ff1e1e',
|
||||||
|
'#ff0606',
|
||||||
|
'#fc0000',
|
||||||
|
'#f40000',
|
||||||
|
'#d40000',
|
||||||
|
'#a30000',
|
||||||
|
'#7a0000'
|
||||||
|
];
|
||||||
|
const orangeColors = [
|
||||||
|
'#ffdb99',
|
||||||
|
'#ffc968',
|
||||||
|
'#ffb837',
|
||||||
|
'#ffac16',
|
||||||
|
'#ffa706',
|
||||||
|
'#FF8C00',
|
||||||
|
'#d48900',
|
||||||
|
'#CC7A00',
|
||||||
|
'#a36900',
|
||||||
|
'#993D00'
|
||||||
|
];
|
||||||
|
const greenColors = [
|
||||||
|
'#90EE90',
|
||||||
|
'#77DD77',
|
||||||
|
'#5ECE5E',
|
||||||
|
'#45BF45',
|
||||||
|
'#32CD32',
|
||||||
|
'#28A428',
|
||||||
|
'#1E7B1E',
|
||||||
|
'#145214',
|
||||||
|
'#0A390A',
|
||||||
|
'#052905'
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const resultPromise: Promise<{
|
||||||
|
chartData: BatteryDataInterface;
|
||||||
|
chartOverview: BatteryOverviewInterface;
|
||||||
|
}> = transformInputToBatteryViewDataJson(
|
||||||
|
props.s3Credentials,
|
||||||
|
props.id,
|
||||||
|
2,
|
||||||
|
UnixTime.fromTicks(new Date().getTime() / 1000).earlier(
|
||||||
|
TimeSpan.fromDays(1)
|
||||||
|
),
|
||||||
|
UnixTime.fromTicks(new Date().getTime() / 1000),
|
||||||
|
props.batteryClusterNumber
|
||||||
|
);
|
||||||
|
|
||||||
|
resultPromise
|
||||||
|
.then((result) => {
|
||||||
|
setBatteryViewDataArray((prevData) =>
|
||||||
|
prevData.concat({
|
||||||
|
chartData: result.chartData,
|
||||||
|
chartOverview: result.chartOverview
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [isZooming, setIsZooming] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isZooming) {
|
||||||
|
setLoading(true);
|
||||||
|
} else if (!isZooming && batteryViewDataArray.length > 0) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [isZooming, batteryViewDataArray]);
|
||||||
|
|
||||||
|
function generateSeries(chartData, category, color) {
|
||||||
|
const series = [];
|
||||||
|
const pathsToSearch = [];
|
||||||
|
for (let i = 0; i < props.batteryClusterNumber; i++) {
|
||||||
|
pathsToSearch.push('Node' + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
pathsToSearch.forEach((devicePath) => {
|
||||||
|
if (
|
||||||
|
Object.hasOwnProperty.call(chartData[category].data, devicePath) &&
|
||||||
|
chartData[category].data[devicePath].data.length != 0
|
||||||
|
) {
|
||||||
|
series.push({
|
||||||
|
...chartData[category].data[devicePath],
|
||||||
|
color:
|
||||||
|
color === 'blue'
|
||||||
|
? blueColors[i]
|
||||||
|
: color === 'red'
|
||||||
|
? redColors[i]
|
||||||
|
: color === 'green'
|
||||||
|
? greenColors[i]
|
||||||
|
: orangeColors[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setIsDateModalOpen(false);
|
||||||
|
setDateOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
setIsDateModalOpen(false);
|
||||||
|
setDateOpen(false);
|
||||||
|
|
||||||
|
if (endDate.isAfter(dayjs())) {
|
||||||
|
setDateSelectionError('You cannot ask for future data');
|
||||||
|
setErrorDateModalOpen(true);
|
||||||
|
return;
|
||||||
|
} else if (startDate.isAfter(endDate)) {
|
||||||
|
setDateSelectionError('End date must precede start date');
|
||||||
|
setErrorDateModalOpen(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
const resultPromise: Promise<{
|
||||||
|
chartData: BatteryDataInterface;
|
||||||
|
chartOverview: BatteryOverviewInterface;
|
||||||
|
}> = transformInputToBatteryViewDataJson(
|
||||||
|
props.s3Credentials,
|
||||||
|
props.id,
|
||||||
|
2,
|
||||||
|
UnixTime.fromTicks(startDate.unix()),
|
||||||
|
UnixTime.fromTicks(endDate.unix()),
|
||||||
|
props.batteryClusterNumber
|
||||||
|
);
|
||||||
|
|
||||||
|
resultPromise
|
||||||
|
.then((result) => {
|
||||||
|
setBatteryViewDataArray((prevData) =>
|
||||||
|
prevData.concat({
|
||||||
|
chartData: result.chartData,
|
||||||
|
chartOverview: result.chartOverview
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
setChartState(batteryViewDataArray.length);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleSetDate = () => {
|
||||||
|
setDateOpen(true);
|
||||||
|
setIsDateModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBatteryViewButton = () => {
|
||||||
|
navigate(
|
||||||
|
location.pathname.split('/').slice(0, -2).join('/') + '/batteryview'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGoBack = () => {
|
||||||
|
if (chartState > 0) {
|
||||||
|
setChartState(chartState - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGoForward = () => {
|
||||||
|
if (chartState + 1 < batteryViewDataArray.length) {
|
||||||
|
setChartState(chartState + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOkOnErrorDateModal = () => {
|
||||||
|
setErrorDateModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startZoom = () => {
|
||||||
|
setIsZooming(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBeforeZoom = (chartContext, { xaxis }) => {
|
||||||
|
const startX = parseInt(xaxis.min) / 1000;
|
||||||
|
const endX = parseInt(xaxis.max) / 1000;
|
||||||
|
|
||||||
|
const resultPromise: Promise<{
|
||||||
|
chartData: BatteryDataInterface;
|
||||||
|
chartOverview: BatteryOverviewInterface;
|
||||||
|
}> = transformInputToBatteryViewDataJson(
|
||||||
|
props.s3Credentials,
|
||||||
|
props.id,
|
||||||
|
2,
|
||||||
|
UnixTime.fromTicks(startX).earlier(TimeSpan.fromHours(2)),
|
||||||
|
UnixTime.fromTicks(endX).earlier(TimeSpan.fromHours(2)),
|
||||||
|
props.batteryClusterNumber
|
||||||
|
);
|
||||||
|
|
||||||
|
resultPromise
|
||||||
|
.then((result) => {
|
||||||
|
setBatteryViewDataArray((prevData) =>
|
||||||
|
prevData.concat({
|
||||||
|
chartData: result.chartData,
|
||||||
|
chartOverview: result.chartOverview
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setIsZooming(false);
|
||||||
|
setChartState(batteryViewDataArray.length);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{loading && (
|
||||||
|
<Container
|
||||||
|
maxWidth="xl"
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '100vh'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
|
||||||
|
<Typography variant="body2" style={{ color: 'black' }} mt={2}>
|
||||||
|
Fetching data...
|
||||||
|
</Typography>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
{isErrorDateModalOpen && (
|
||||||
|
<Modal open={isErrorDateModalOpen} onClose={() => {}}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
borderRadius: 4,
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
gutterBottom
|
||||||
|
sx={{ fontWeight: 'bold' }}
|
||||||
|
>
|
||||||
|
{dateSelectionError}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#ffc04d',
|
||||||
|
color: '#111111',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={handleOkOnErrorDateModal}
|
||||||
|
>
|
||||||
|
Ok
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
{isDateModalOpen && (
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||||
|
<Modal open={isDateModalOpen} onClose={() => {}}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
borderRadius: 4,
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DateTimePicker
|
||||||
|
label="Select Start Date"
|
||||||
|
value={startDate}
|
||||||
|
onChange={(newDate: Dayjs | null) => {
|
||||||
|
if (newDate) {
|
||||||
|
setStartDate(newDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DateTimePicker
|
||||||
|
label="Select End Date"
|
||||||
|
value={endDate}
|
||||||
|
onChange={(newDate: Dayjs | null) => {
|
||||||
|
if (newDate) {
|
||||||
|
setEndDate(newDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: 10
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#ffc04d',
|
||||||
|
color: '#111111',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={handleConfirm}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
marginLeft: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#ffc04d',
|
||||||
|
color: '#111111',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={handleCancel}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
</LocalizationProvider>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && (
|
||||||
|
<>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="go back"
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
backgroundColor: 'grey',
|
||||||
|
color: '#000000',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={handleBatteryViewButton}
|
||||||
|
>
|
||||||
|
<ArrowBackIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleSetDate}
|
||||||
|
disabled={loading}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
marginLeft: '20px',
|
||||||
|
backgroundColor: dateOpen ? '#808080' : '#ffc04d',
|
||||||
|
color: '#000000',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="set_date" defaultMessage="Set Date" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
justifyContent="flex-end"
|
||||||
|
alignItems="center"
|
||||||
|
item
|
||||||
|
xs={6}
|
||||||
|
md={6}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disabled={!(chartState > 0)}
|
||||||
|
onClick={handleGoBack}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
backgroundColor: '#ffc04d',
|
||||||
|
color: '#000000',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="goback" defaultMessage="Zoom out" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disabled={!(chartState < batteryViewDataArray.length - 1)}
|
||||||
|
onClick={handleGoForward}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
backgroundColor: '#ffc04d',
|
||||||
|
color: '#000000',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="goback" defaultMessage="Zoom in" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
direction="row"
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="stretch"
|
||||||
|
spacing={3}
|
||||||
|
>
|
||||||
|
{/* Battery SOC Chart */}
|
||||||
|
<Grid item md={12} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '30px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginLeft: '20px' }}>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="battery_soc"
|
||||||
|
defaultMessage="Battery SOC (State Of Charge)"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
batteryViewDataArray[chartState].chartOverview.Soc,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={generateSeries(
|
||||||
|
batteryViewDataArray[chartState].chartData,
|
||||||
|
'Soc',
|
||||||
|
'blue'
|
||||||
|
)}
|
||||||
|
type="line"
|
||||||
|
height={420}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Battery Power Chart */}
|
||||||
|
<Grid item md={12} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginLeft: '20px' }}>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="battery_power"
|
||||||
|
defaultMessage="Battery Power"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
batteryViewDataArray[chartState].chartOverview.Power,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={generateSeries(
|
||||||
|
batteryViewDataArray[chartState].chartData,
|
||||||
|
'Power',
|
||||||
|
'red'
|
||||||
|
)}
|
||||||
|
type="line"
|
||||||
|
height={420}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Battery Voltage Chart */}
|
||||||
|
<Grid item md={12} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginLeft: '20px' }}>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="battery_voltage"
|
||||||
|
defaultMessage="Battery Voltage"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
batteryViewDataArray[chartState].chartOverview.Voltage,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={generateSeries(
|
||||||
|
batteryViewDataArray[chartState].chartData,
|
||||||
|
'Voltage',
|
||||||
|
'orange'
|
||||||
|
)}
|
||||||
|
type="line"
|
||||||
|
height={420}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Battery Current Chart */}
|
||||||
|
<Grid item md={12} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginLeft: '20px' }}>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="battery_current"
|
||||||
|
defaultMessage="Battery Current"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
batteryViewDataArray[chartState].chartOverview.Current,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={generateSeries(
|
||||||
|
batteryViewDataArray[chartState].chartData,
|
||||||
|
'Current',
|
||||||
|
'orange'
|
||||||
|
)}
|
||||||
|
type="line"
|
||||||
|
height={420}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Battery SoH Chart */}
|
||||||
|
<Grid item md={12} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginLeft: '20px' }}>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="battery_soh"
|
||||||
|
defaultMessage="Battery SOH (State Of Health)"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
batteryViewDataArray[chartState].chartOverview.Soh,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={generateSeries(
|
||||||
|
batteryViewDataArray[chartState].chartData,
|
||||||
|
'Soh',
|
||||||
|
'green'
|
||||||
|
)}
|
||||||
|
type="line"
|
||||||
|
height={420}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MainStatsSodioHome;
|
||||||
|
|
@ -60,6 +60,7 @@ export interface BatteryDataInterface {
|
||||||
Power: { name: string; data: [] };
|
Power: { name: string; data: [] };
|
||||||
Voltage: { name: string; data: [] };
|
Voltage: { name: string; data: [] };
|
||||||
Current: { name: string; data: [] };
|
Current: { name: string; data: [] };
|
||||||
|
Soh?: { name: string; data: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatteryOverviewInterface {
|
export interface BatteryOverviewInterface {
|
||||||
|
|
@ -68,6 +69,7 @@ export interface BatteryOverviewInterface {
|
||||||
Power: chartInfoInterface;
|
Power: chartInfoInterface;
|
||||||
Voltage: chartInfoInterface;
|
Voltage: chartInfoInterface;
|
||||||
Current: chartInfoInterface;
|
Current: chartInfoInterface;
|
||||||
|
Soh?: chartInfoInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const transformInputToBatteryViewDataJson = async (
|
export const transformInputToBatteryViewDataJson = async (
|
||||||
|
|
@ -75,14 +77,18 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
id: number,
|
id: number,
|
||||||
product: number,
|
product: number,
|
||||||
start_time?: UnixTime,
|
start_time?: UnixTime,
|
||||||
end_time?: UnixTime
|
end_time?: UnixTime,
|
||||||
|
batteryClusterNumber?: number
|
||||||
): Promise<{
|
): Promise<{
|
||||||
chartData: BatteryDataInterface;
|
chartData: BatteryDataInterface;
|
||||||
chartOverview: BatteryOverviewInterface;
|
chartOverview: BatteryOverviewInterface;
|
||||||
}> => {
|
}> => {
|
||||||
const prefixes = ['', 'k', 'M', 'G', 'T'];
|
const prefixes = ['', 'k', 'M', 'G', 'T'];
|
||||||
const MAX_NUMBER = 9999999;
|
const MAX_NUMBER = 9999999;
|
||||||
const categories = ['Soc', 'Temperature', 'Power', 'Voltage', 'Current'];
|
const isSodioHome = product === 2;
|
||||||
|
const categories = isSodioHome
|
||||||
|
? ['Soc', 'Power', 'Voltage', 'Current', 'Soh']
|
||||||
|
: ['Soc', 'Temperature', 'Power', 'Voltage', 'Current'];
|
||||||
const pathCategories =
|
const pathCategories =
|
||||||
product === 3
|
product === 3
|
||||||
? [
|
? [
|
||||||
|
|
@ -120,7 +126,8 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
Temperature: { name: 'Temperature', data: [] },
|
Temperature: { name: 'Temperature', data: [] },
|
||||||
Power: { name: 'Power', data: [] },
|
Power: { name: 'Power', data: [] },
|
||||||
Voltage: { name: 'Voltage', data: [] },
|
Voltage: { name: 'Voltage', data: [] },
|
||||||
Current: { name: 'Current', data: [] }
|
Current: { name: 'Current', data: [] },
|
||||||
|
...(isSodioHome && { Soh: { name: 'State Of Health', data: [] } })
|
||||||
};
|
};
|
||||||
|
|
||||||
const chartOverview: BatteryOverviewInterface = {
|
const chartOverview: BatteryOverviewInterface = {
|
||||||
|
|
@ -128,7 +135,8 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
Temperature: { magnitude: 0, unit: '', min: 0, max: 0 },
|
Temperature: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
Power: { magnitude: 0, unit: '', min: 0, max: 0 },
|
Power: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
Voltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
Voltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
Current: { magnitude: 0, unit: '', min: 0, max: 0 }
|
Current: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
|
...(isSodioHome && { Soh: { magnitude: 0, unit: '', min: 0, max: 0 } })
|
||||||
};
|
};
|
||||||
|
|
||||||
let initialiation = true;
|
let initialiation = true;
|
||||||
|
|
@ -159,7 +167,7 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
const adjustedTimestamp =
|
const adjustedTimestamp =
|
||||||
product == 0 || product == 3
|
product == 0 || product == 2 || product == 3
|
||||||
? new Date(timestampArray[i] * 1000)
|
? new Date(timestampArray[i] * 1000)
|
||||||
: new Date(timestampArray[i] * 100000);
|
: new Date(timestampArray[i] * 100000);
|
||||||
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
||||||
|
|
@ -181,79 +189,144 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
];
|
];
|
||||||
|
|
||||||
const result = results[i][timestamp];
|
const result = results[i][timestamp];
|
||||||
//console.log(result);
|
|
||||||
const battery_nodes =
|
|
||||||
result.Config.Devices.BatteryNodes.toString().split(',');
|
|
||||||
|
|
||||||
//Initialize the chartData structure based on the node names extracted from the first result
|
if (isSodioHome) {
|
||||||
let old_length = pathsToSave.length;
|
// SodistoreHome: extract battery data from InverterRecord
|
||||||
|
const inv = (result as any)?.InverterRecord;
|
||||||
|
if (!inv) continue;
|
||||||
|
|
||||||
if (battery_nodes.length > old_length) {
|
const numBatteries = batteryClusterNumber || 1;
|
||||||
battery_nodes.forEach((node) => {
|
let old_length = pathsToSave.length;
|
||||||
const node_number =
|
|
||||||
product == 3 ? Number(node) + 1 : Number(node) - 1;
|
|
||||||
if (!pathsToSave.includes('Node' + node_number)) {
|
|
||||||
pathsToSave.push('Node' + node_number);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log(pathsToSave);
|
if (numBatteries > old_length) {
|
||||||
|
for (let b = old_length; b < numBatteries; b++) {
|
||||||
if (initialiation) {
|
const nodeName = 'Node' + b;
|
||||||
initialiation = false;
|
if (!pathsToSave.includes(nodeName)) {
|
||||||
categories.forEach((category) => {
|
pathsToSave.push(nodeName);
|
||||||
chartData[category].data = [];
|
|
||||||
chartOverview[category] = {
|
|
||||||
magnitude: 0,
|
|
||||||
unit: '',
|
|
||||||
min: MAX_NUMBER,
|
|
||||||
max: -MAX_NUMBER
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (battery_nodes.length > old_length) {
|
|
||||||
categories.forEach((category) => {
|
|
||||||
pathsToSave.forEach((path) => {
|
|
||||||
if (pathsToSave.indexOf(path) >= old_length) {
|
|
||||||
chartData[category].data[path] = { name: path, data: [] };
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (
|
if (initialiation) {
|
||||||
let category_index = 0;
|
initialiation = false;
|
||||||
category_index < pathCategories.length;
|
categories.forEach((category) => {
|
||||||
category_index++
|
chartData[category].data = [];
|
||||||
) {
|
chartOverview[category] = {
|
||||||
let category = categories[category_index];
|
magnitude: 0,
|
||||||
|
unit: '',
|
||||||
|
min: MAX_NUMBER,
|
||||||
|
max: -MAX_NUMBER
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numBatteries > old_length) {
|
||||||
|
categories.forEach((category) => {
|
||||||
|
pathsToSave.forEach((path) => {
|
||||||
|
if (pathsToSave.indexOf(path) >= old_length) {
|
||||||
|
chartData[category].data[path] = { name: path, data: [] };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map category names to InverterRecord field suffixes
|
||||||
|
const categoryFieldMap = {
|
||||||
|
Soc: 'Soc',
|
||||||
|
Power: 'Power',
|
||||||
|
Voltage: 'Voltage',
|
||||||
|
Current: 'Current',
|
||||||
|
Soh: 'Soh'
|
||||||
|
};
|
||||||
|
|
||||||
for (let j = 0; j < pathsToSave.length; j++) {
|
for (let j = 0; j < pathsToSave.length; j++) {
|
||||||
let path = pathsToSearch[j] + pathCategories[category_index];
|
const batteryIndex = j + 1; // Battery1, Battery2, ...
|
||||||
|
categories.forEach((category) => {
|
||||||
|
const fieldName = `Battery${batteryIndex}${categoryFieldMap[category]}`;
|
||||||
|
const value = inv[fieldName];
|
||||||
|
|
||||||
if (get(result, path) !== undefined) {
|
if (value !== undefined && value !== null) {
|
||||||
const value = path
|
if (value < chartOverview[category].min) {
|
||||||
.split('.')
|
chartOverview[category].min = value;
|
||||||
.reduce((o, key) => (o ? o[key] : undefined), result);
|
}
|
||||||
|
if (value > chartOverview[category].max) {
|
||||||
if (value < chartOverview[category].min) {
|
chartOverview[category].max = value;
|
||||||
chartOverview[category].min = value;
|
}
|
||||||
|
chartData[category].data[pathsToSave[j]].data.push([
|
||||||
|
adjustedTimestampArray[i],
|
||||||
|
value
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// SaliMax, Salidomo, SodistoreMax: existing logic
|
||||||
|
const battery_nodes =
|
||||||
|
result.Config.Devices.BatteryNodes.toString().split(',');
|
||||||
|
|
||||||
if (value > chartOverview[category].max) {
|
//Initialize the chartData structure based on the node names extracted from the first result
|
||||||
chartOverview[category].max = value;
|
let old_length = pathsToSave.length;
|
||||||
|
|
||||||
|
if (battery_nodes.length > old_length) {
|
||||||
|
battery_nodes.forEach((node) => {
|
||||||
|
const node_number =
|
||||||
|
product == 3 ? Number(node) + 1 : Number(node) - 1;
|
||||||
|
if (!pathsToSave.includes('Node' + node_number)) {
|
||||||
|
pathsToSave.push('Node' + node_number);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialiation) {
|
||||||
|
initialiation = false;
|
||||||
|
categories.forEach((category) => {
|
||||||
|
chartData[category].data = [];
|
||||||
|
chartOverview[category] = {
|
||||||
|
magnitude: 0,
|
||||||
|
unit: '',
|
||||||
|
min: MAX_NUMBER,
|
||||||
|
max: -MAX_NUMBER
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battery_nodes.length > old_length) {
|
||||||
|
categories.forEach((category) => {
|
||||||
|
pathsToSave.forEach((path) => {
|
||||||
|
if (pathsToSave.indexOf(path) >= old_length) {
|
||||||
|
chartData[category].data[path] = { name: path, data: [] };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (
|
||||||
|
let category_index = 0;
|
||||||
|
category_index < pathCategories.length;
|
||||||
|
category_index++
|
||||||
|
) {
|
||||||
|
let category = categories[category_index];
|
||||||
|
|
||||||
|
for (let j = 0; j < pathsToSave.length; j++) {
|
||||||
|
let path = pathsToSearch[j] + pathCategories[category_index];
|
||||||
|
|
||||||
|
if (get(result, path) !== undefined) {
|
||||||
|
const value = path
|
||||||
|
.split('.')
|
||||||
|
.reduce((o, key) => (o ? o[key] : undefined), result);
|
||||||
|
|
||||||
|
if (value < chartOverview[category].min) {
|
||||||
|
chartOverview[category].min = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > chartOverview[category].max) {
|
||||||
|
chartOverview[category].max = value;
|
||||||
|
}
|
||||||
|
chartData[category].data[pathsToSave[j]].data.push([
|
||||||
|
adjustedTimestampArray[i],
|
||||||
|
value
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
chartData[category].data[pathsToSave[j]].data.push([
|
|
||||||
adjustedTimestampArray[i],
|
|
||||||
value
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
// chartData[category].data[pathsToSave[j]].data.push([
|
|
||||||
// adjustedTimestampArray[i],
|
|
||||||
// null
|
|
||||||
// ]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -280,16 +353,20 @@ export const transformInputToBatteryViewDataJson = async (
|
||||||
chartOverview.Soc.unit = '(%)';
|
chartOverview.Soc.unit = '(%)';
|
||||||
chartOverview.Soc.min = 0;
|
chartOverview.Soc.min = 0;
|
||||||
chartOverview.Soc.max = 100;
|
chartOverview.Soc.max = 100;
|
||||||
chartOverview.Temperature.unit = '(°C)';
|
if (!isSodioHome) {
|
||||||
|
chartOverview.Temperature.unit = '(°C)';
|
||||||
|
}
|
||||||
chartOverview.Power.unit =
|
chartOverview.Power.unit =
|
||||||
'(' + prefixes[chartOverview['Power'].magnitude] + 'W' + ')';
|
'(' + prefixes[chartOverview['Power'].magnitude] + 'W' + ')';
|
||||||
chartOverview.Voltage.unit =
|
chartOverview.Voltage.unit =
|
||||||
'(' + prefixes[chartOverview['Voltage'].magnitude] + 'V' + ')';
|
'(' + prefixes[chartOverview['Voltage'].magnitude] + 'V' + ')';
|
||||||
|
|
||||||
chartOverview.Current.unit =
|
chartOverview.Current.unit =
|
||||||
'(' + prefixes[chartOverview['Current'].magnitude] + 'A' + ')';
|
'(' + prefixes[chartOverview['Current'].magnitude] + 'A' + ')';
|
||||||
|
if (isSodioHome) {
|
||||||
// console.log(chartData);
|
chartOverview.Soh.unit = '(%)';
|
||||||
|
chartOverview.Soh.min = 0;
|
||||||
|
chartOverview.Soh.max = 100;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chartData: chartData,
|
chartData: chartData,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue