Compare commits

..

No commits in common. "2851e34e47d88d651d58ce7ad7a1c0a2b097cec2" and "3a3f2fe1b81e83cfc2c623175524f7aa43adec12" have entirely different histories.

8 changed files with 320 additions and 548 deletions

View File

@ -514,16 +514,18 @@ public class Controller : ControllerBase
} }
[HttpPost(nameof(UpdateFirmware))] [HttpPost(nameof(UpdateFirmware))]
public async Task<ActionResult> UpdateFirmware(Int64 batteryNode, Int64 installationId,Token authToken) public ActionResult UpdateFirmware(Int64 batteryNode, Int64 installationId,Token authToken)
{ {
var session = Db.GetSession(authToken); var session = Db.GetSession(authToken);
var installationToUpdate = Db.GetInstallationById(installationId); var installationToUpdate = Db.GetInstallationById(installationId);
Console.WriteLine("Inside firmware function controller,batteryNode="+batteryNode+ "and installation is "+installationId); Console.WriteLine("Inside firmware function controller,batteryNode="+batteryNode+ "and installation is "+installationId);
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
if (installationToUpdate != null) if (installationToUpdate != null)
{ {
_ = session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode); session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode);
} }
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
return Ok(); return Ok();
} }

View File

@ -2,7 +2,6 @@ using System.Diagnostics;
using InnovEnergy.App.Backend.Database; using InnovEnergy.App.Backend.Database;
using InnovEnergy.App.Backend.Relations; using InnovEnergy.App.Backend.Relations;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using Org.BouncyCastle.Asn1.X509;
namespace InnovEnergy.App.Backend.DataTypes.Methods; namespace InnovEnergy.App.Backend.DataTypes.Methods;
@ -68,9 +67,8 @@ public static class SessionMethods
.Apply(Db.Update); .Apply(Db.Update);
} }
public static async Task RunScriptInBackground(this Session? session, String vpnIp, Int64 batteryNode) public static async Task<Boolean> RunScriptInBackground(this Session? session, String vpnIp, Int64 batteryNode)
{ {
Console.WriteLine("11111111111111111111111111111111111111111111111111111111111111");
string scriptPath = "/home/ubuntu/backend/uploadBatteryFw/update_firmware.sh"; string scriptPath = "/home/ubuntu/backend/uploadBatteryFw/update_firmware.sh";
await Task.Run(() => await Task.Run(() =>
@ -82,11 +80,11 @@ public static class SessionMethods
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
process.Start(); process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit(); // This can be removed if you don't need to wait for the process to finish process.WaitForExit(); // This can be removed if you don't need to wait for the process to finish
Console.WriteLine(output);
}); });
Console.WriteLine("222222222222222222222222222222222222222222222222222222222222222");
return true;
} }

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React from 'react';
import { import {
Container, Container,
Grid, Grid,
@ -8,8 +8,7 @@ import {
TableCell, TableCell,
TableContainer, TableContainer,
TableHead, TableHead,
TableRow, TableRow
Typography
} from '@mui/material'; } from '@mui/material';
import { TopologyValues } from '../Log/graph.util'; import { TopologyValues } from '../Log/graph.util';
import { import {
@ -25,12 +24,10 @@ import { I_S3Credentials } from '../../../interfaces/S3Types';
import routes from '../../../Resources/routes.json'; import routes from '../../../Resources/routes.json';
import MainStats from './MainStats'; import MainStats from './MainStats';
import DetailedBatteryView from './DetailedBatteryView'; import DetailedBatteryView from './DetailedBatteryView';
import CircularProgress from '@mui/material/CircularProgress';
interface BatteryViewProps { interface BatteryViewProps {
values: TopologyValues; values: TopologyValues;
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
installationId: number;
} }
function BatteryView(props: BatteryViewProps) { function BatteryView(props: BatteryViewProps) {
@ -43,10 +40,6 @@ function BatteryView(props: BatteryViewProps) {
(a, b) => b.BatteryId - a.BatteryId (a, b) => b.BatteryId - a.BatteryId
); );
const [loading, setLoading] = useState(
sortedBatteryView.length == 0 ? true : false
);
const handleMainStatsButton = () => { const handleMainStatsButton = () => {
navigate(routes.mainstats); navigate(routes.mainstats);
}; };
@ -59,116 +52,15 @@ function BatteryView(props: BatteryViewProps) {
} }
}; };
useEffect(() => {
if (sortedBatteryView.length == 0) {
setLoading(true);
} else {
setLoading(false);
}
}, [sortedBatteryView]);
return ( return (
<> <>
{loading && ( <Container maxWidth="xl">
<Container <Grid container>
maxWidth="xl" <Grid
sx={{ item
display: 'flex', xs={6}
flexDirection: 'column', md={6}
justifyContent: 'center',
alignItems: 'center',
height: '70vh'
}}
>
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
<Typography
variant="body2"
style={{ color: 'black', fontWeight: 'bold' }}
mt={2}
>
Battery service is not available at the moment
</Typography>
<Typography variant="body2" style={{ color: 'black' }}>
Please wait or refresh the page
</Typography>
</Container>
)}
{!loading && (
<Container maxWidth="xl">
<Grid container>
<Grid
item
xs={6}
md={6}
sx={{
display:
!currentLocation.pathname.includes('detailed_view') &&
!currentLocation.pathname.includes('mainstats')
? 'block'
: 'none'
}}
>
<Button
variant="contained"
sx={{
marginTop: '20px',
backgroundColor: '#808080',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage
id="battery_view"
defaultMessage="Battery View"
/>
</Button>
<Button
variant="contained"
onClick={handleMainStatsButton}
sx={{
marginTop: '20px',
marginLeft: '20px',
backgroundColor: '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage id="main_stats" defaultMessage="Main Stats" />
</Button>
</Grid>
</Grid>
<Grid container>
<Routes>
<Route
path={routes.mainstats + '*'}
element={
<MainStats s3Credentials={props.s3Credentials}></MainStats>
}
/>
{props.values.batteryView.map((battery) => (
<Route
key={routes.detailed_view + battery.BatteryId}
path={routes.detailed_view + battery.BatteryId}
element={
<DetailedBatteryView
s3Credentials={props.s3Credentials}
batteryData={findBatteryData(battery.BatteryId)}
installationId={props.installationId}
></DetailedBatteryView>
}
/>
))}
</Routes>
</Grid>
<TableContainer
component={Paper}
sx={{ sx={{
marginTop: '20px',
marginBottom: '20px',
display: display:
!currentLocation.pathname.includes('detailed_view') && !currentLocation.pathname.includes('detailed_view') &&
!currentLocation.pathname.includes('mainstats') !currentLocation.pathname.includes('mainstats')
@ -176,175 +68,237 @@ function BatteryView(props: BatteryViewProps) {
: 'none' : 'none'
}} }}
> >
<Table sx={{ minWidth: 650 }} aria-label="simple table"> <Button
<TableHead> variant="contained"
<TableRow> sx={{
<TableCell align="center">Battery</TableCell> marginTop: '20px',
<TableCell align="center">Firmware</TableCell> backgroundColor: '#808080',
<TableCell align="center">Power</TableCell> color: '#000000',
<TableCell align="center">Voltage</TableCell> '&:hover': { bgcolor: '#f7b34d' }
<TableCell align="center">SoC</TableCell> }}
<TableCell align="center">Temperature</TableCell> >
<TableCell align="center">Warnings</TableCell> <FormattedMessage
<TableCell align="center">Alarms</TableCell> id="battery_view"
</TableRow> defaultMessage="Battery View"
</TableHead> />
<TableBody> </Button>
{sortedBatteryView.map((battery) => (
<TableRow <Button
key={battery.BatteryId} variant="contained"
style={{ onClick={handleMainStatsButton}
height: '10px' sx={{
marginTop: '20px',
marginLeft: '20px',
backgroundColor: '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage id="main_stats" defaultMessage="Main Stats" />
</Button>
</Grid>
</Grid>
<Grid container>
<Routes>
<Route
path={routes.mainstats + '*'}
element={
<MainStats s3Credentials={props.s3Credentials}></MainStats>
}
/>
{props.values.batteryView.map((battery) => (
<Route
key={routes.detailed_view + battery.BatteryId}
path={routes.detailed_view + battery.BatteryId}
element={
<DetailedBatteryView
s3Credentials={props.s3Credentials}
batteryData={findBatteryData(battery.BatteryId)}
></DetailedBatteryView>
}
/>
))}
</Routes>
</Grid>
<TableContainer
component={Paper}
sx={{
marginTop: '20px',
marginBottom: '20px',
display:
!currentLocation.pathname.includes('detailed_view') &&
!currentLocation.pathname.includes('mainstats')
? 'block'
: 'none'
}}
>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="center">Battery</TableCell>
<TableCell align="center">Firmware</TableCell>
<TableCell align="center">Power</TableCell>
<TableCell align="center">Voltage</TableCell>
<TableCell align="center">SoC</TableCell>
<TableCell align="center">Temperature</TableCell>
<TableCell align="center">Warnings</TableCell>
<TableCell align="center">Alarms</TableCell>
</TableRow>
</TableHead>
<TableBody>
{sortedBatteryView.map((battery) => (
<TableRow
key={battery.BatteryId}
style={{
height: '10px'
}}
>
<TableCell
component="th"
scope="row"
align="center"
sx={{ fontWeight: 'bold' }}
>
<Link
style={{ color: 'black' }}
to={routes.detailed_view + battery.BatteryId.toString()}
>
{'Node ' + battery.BatteryId}
</Link>
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center'
}} }}
> >
<TableCell {battery.FwVersion.value}
component="th" </TableCell>
scope="row" <TableCell
align="center" sx={{
sx={{ fontWeight: 'bold' }} width: '10%',
> textAlign: 'center'
}}
>
{battery.Power.value + ' ' + battery.Power.unit}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.Voltage.value < 44 || battery.Voltage.value > 57
? '#FF033E'
: '#32CD32',
color: battery.Voltage.value === '' ? 'white' : 'inherit'
}}
>
{battery.Voltage.value + ' ' + battery.Voltage.unit}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.Soc.value < 20
? '#FF033E'
: battery.Soc.value < 50
? '#ffbf00'
: '#32CD32',
color: battery.Soc.value === '' ? 'white' : 'inherit'
}}
>
{battery.Soc.value + ' ' + battery.Soc.unit}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.AverageTemperature.value > 270
? '#FF033E'
: '#32CD32 '
}}
>
{battery.AverageTemperature.value +
' ' +
battery.AverageTemperature.unit}
</TableCell>
<TableCell
style={{
width: '20%',
textAlign: 'center',
padding: '8px',
fontWeight:
battery.Warnings.value !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Warnings.value === '' ? 'inherit' : '#ff9900',
color: battery.Warnings.value != '' ? 'black' : 'inherit'
}}
>
{battery.Warnings.value === '' ? (
'None'
) : battery.Warnings.value.toString().split('-').length >
1 ? (
<Link <Link
style={{ color: 'black' }} style={{ color: 'black' }}
to={routes.detailed_view + battery.BatteryId.toString()} to={
currentLocation.pathname.substring(
0,
currentLocation.pathname.lastIndexOf('/') + 1
) +
routes.log +
'?open=warning'
}
> >
{'Node ' + battery.BatteryId} Multiple Warnings
</Link> </Link>
</TableCell> ) : (
<TableCell battery.Warnings.value
sx={{ )}
width: '10%', </TableCell>
textAlign: 'center' <TableCell
}} sx={{
> width: '20%',
{battery.FwVersion.value} textAlign: 'center',
</TableCell> fontWeight:
<TableCell battery.Alarms.value !== '' ? 'bold' : 'inherit',
sx={{ backgroundColor:
width: '10%', battery.Alarms.value === '' ? 'inherit' : '#FF033E',
textAlign: 'center' color: battery.Alarms.value != '' ? 'black' : 'inherit'
}} }}
> >
{battery.Power.value + ' ' + battery.Power.unit} {battery.Alarms.value === '' ? (
</TableCell> 'None'
<TableCell ) : battery.Alarms.value.toString().split('-').length >
sx={{ 1 ? (
width: '10%', <Link
textAlign: 'center', style={{ color: 'black' }}
to={
backgroundColor: currentLocation.pathname.substring(
battery.Voltage.value < 44 || 0,
battery.Voltage.value > 57 currentLocation.pathname.lastIndexOf('/') + 1
? '#FF033E' ) +
: '#32CD32', routes.log +
color: '?open=error'
battery.Voltage.value === '' ? 'white' : 'inherit' }
}} >
> Multiple Alarms
{battery.Voltage.value + ' ' + battery.Voltage.unit} </Link>
</TableCell> ) : (
<TableCell battery.Alarms.value
sx={{ )}
width: '10%', </TableCell>
textAlign: 'center', </TableRow>
backgroundColor: ))}
battery.Soc.value < 20 </TableBody>
? '#FF033E' </Table>
: battery.Soc.value < 50 </TableContainer>
? '#ffbf00' </Container>
: '#32CD32',
color: battery.Soc.value === '' ? 'white' : 'inherit'
}}
>
{battery.Soc.value + ' ' + battery.Soc.unit}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.AverageTemperature.value > 270
? '#FF033E'
: '#32CD32 '
}}
>
{battery.AverageTemperature.value +
' ' +
battery.AverageTemperature.unit}
</TableCell>
<TableCell
style={{
width: '20%',
textAlign: 'center',
padding: '8px',
fontWeight:
battery.Warnings.value !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Warnings.value === '' ? 'inherit' : '#ff9900',
color:
battery.Warnings.value != '' ? 'black' : 'inherit'
}}
>
{battery.Warnings.value === '' ? (
'None'
) : battery.Warnings.value.toString().split('-').length >
1 ? (
<Link
style={{ color: 'black' }}
to={
currentLocation.pathname.substring(
0,
currentLocation.pathname.lastIndexOf('/') + 1
) +
routes.log +
'?open=warning'
}
>
Multiple Warnings
</Link>
) : (
battery.Warnings.value
)}
</TableCell>
<TableCell
sx={{
width: '20%',
textAlign: 'center',
fontWeight:
battery.Alarms.value !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Alarms.value === '' ? 'inherit' : '#FF033E',
color: battery.Alarms.value != '' ? 'black' : 'inherit'
}}
>
{battery.Alarms.value === '' ? (
'None'
) : battery.Alarms.value.toString().split('-').length >
1 ? (
<Link
style={{ color: 'black' }}
to={
currentLocation.pathname.substring(
0,
currentLocation.pathname.lastIndexOf('/') + 1
) +
routes.log +
'?open=error'
}
>
Multiple Alarms
</Link>
) : (
battery.Alarms.value
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Container>
)}
</> </>
); );
} }

View File

@ -1,11 +1,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { I_S3Credentials } from '../../../interfaces/S3Types'; import { I_S3Credentials } from '../../../interfaces/S3Types';
import { import {
Box,
Card, Card,
Grid, Grid,
IconButton,
Modal,
Paper, Paper,
Table, Table,
TableBody, TableBody,
@ -15,16 +12,14 @@ import {
Typography Typography
} from '@mui/material'; } from '@mui/material';
import { Battery } from '../Log/graph.util'; import { Battery } from '../Log/graph.util';
import { useNavigate } from 'react-router-dom';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import axiosConfig from '../../../Resources/axiosConfig'; import { useNavigate } from 'react-router-dom';
import routes from '../../../Resources/routes.json';
interface DetailedBatteryViewProps { interface DetailedBatteryViewProps {
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
batteryData: Battery; batteryData: Battery;
installationId: number;
} }
function DetailedBatteryView(props: DetailedBatteryViewProps) { function DetailedBatteryView(props: DetailedBatteryViewProps) {
@ -32,20 +27,16 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
return null; return null;
} }
const navigate = useNavigate(); const navigate = useNavigate();
const [openModalFirmwareUpdate, setOpenModalFirmwareUpdate] = useState(false);
const [openModalResultFirmwareUpdate, setOpenModalResultFirmwareUpdate] =
useState(false);
const handleBatteryViewButton = () => { const handleBatteryViewButton = () => {
navigate(location.pathname.split('/').slice(0, -2).join('/')); navigate(location.pathname.split('/').slice(0, -2).join('/'));
}; };
const handleMainStatsButton = () => {
const handleUpdateFirmware = () => { navigate(
setOpenModalFirmwareUpdate(true); location.pathname.split('/').slice(0, -2).join('/') +
}; '/' +
routes.mainstats
const firmwareModalResultHandleOk = () => { );
navigate(location.pathname.split('/').slice(0, -2).join('/'));
}; };
const [GreenisBlinking, setGreenisBlinking] = useState( const [GreenisBlinking, setGreenisBlinking] = useState(
@ -105,177 +96,26 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
backgroundColor: '#bfbfbf' backgroundColor: '#bfbfbf'
}; };
const FirmwareModalHandleProceed = async (e) => {
setOpenModalFirmwareUpdate(false);
const res = await axiosConfig
.post(
`/UpdateFirmware?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${
props.installationId
}`
)
.catch((err) => {
if (err.response) {
// setError(true);
// setLoading(false);
}
});
//if (res) {
setOpenModalResultFirmwareUpdate(true);
//}
};
const FirmwareModalHandleCancel = () => {
setOpenModalFirmwareUpdate(false);
};
return ( return (
<> <>
{openModalResultFirmwareUpdate && (
<Modal
open={openModalResultFirmwareUpdate}
aria-labelledby="error-modal"
aria-describedby="error-modal-description"
>
<Box
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 420,
bgcolor: 'background.paper',
borderRadius: 4,
boxShadow: 24,
p: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<Typography
variant="body1"
gutterBottom
sx={{ fontWeight: 'bold' }}
>
The firmware is getting updated. Please wait...
</Typography>
<div
style={{
display: 'flex',
alignItems: 'center',
marginTop: 10
}}
>
<Button
sx={{
marginTop: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={firmwareModalResultHandleOk}
>
Ok
</Button>
</div>
</Box>
</Modal>
)}
{openModalFirmwareUpdate && (
<Modal
open={openModalFirmwareUpdate}
onClose={FirmwareModalHandleCancel}
aria-labelledby="error-modal"
aria-describedby="error-modal-description"
>
<Box
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 420,
bgcolor: 'background.paper',
borderRadius: 4,
boxShadow: 24,
p: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<Typography
variant="body1"
gutterBottom
sx={{ fontWeight: 'bold' }}
>
Do you really want to update the firmware?
</Typography>
<Typography variant="body1" gutterBottom>
This action requires the battery service to be stopped.
</Typography>
<div
style={{
display: 'flex',
alignItems: 'center',
marginTop: 10
}}
>
<Button
sx={{
marginTop: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={FirmwareModalHandleProceed}
>
Proceed
</Button>
<Button
sx={{
marginTop: 2,
marginLeft: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={FirmwareModalHandleCancel}
>
Cancel
</Button>
</div>
</Box>
</Modal>
)}
<Grid container> <Grid container>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
<IconButton <Button
aria-label="go back" variant="contained"
onClick={handleBatteryViewButton}
sx={{ sx={{
marginTop: '20px', marginTop: '20px',
backgroundColor: 'grey', backgroundColor: '#ffc04d',
color: '#000000', color: '#000000',
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
}} }}
onClick={handleBatteryViewButton}
> >
<ArrowBackIcon /> <FormattedMessage id="main_stats" defaultMessage="Battery View" />
</IconButton> </Button>
<Button <Button
variant="contained" variant="contained"
onClick={handleUpdateFirmware} onClick={handleMainStatsButton}
sx={{ sx={{
marginTop: '20px', marginTop: '20px',
marginLeft: '20px', marginLeft: '20px',
@ -284,10 +124,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
}} }}
> >
<FormattedMessage <FormattedMessage id="main_stats" defaultMessage="Main Stats" />
id="update_firmware"
defaultMessage="Update Firmware"
/>
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -1,12 +1,4 @@
import { import { Box, Card, Container, Grid, Modal, Typography } from '@mui/material';
Box,
Card,
Container,
Grid,
IconButton,
Modal,
Typography
} from '@mui/material';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { I_S3Credentials } from '../../../interfaces/S3Types'; import { I_S3Credentials } from '../../../interfaces/S3Types';
@ -24,7 +16,6 @@ import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
interface MainStatsProps { interface MainStatsProps {
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
@ -393,18 +384,31 @@ function MainStats(props: MainStatsProps) {
{!loading && ( {!loading && (
<> <>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
<IconButton <Button
aria-label="go back" variant="contained"
onClick={handleBatteryViewButton}
sx={{ sx={{
marginTop: '20px', marginTop: '20px',
backgroundColor: 'grey', backgroundColor: '#ffc04d',
color: '#000000', color: '#000000',
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
}} }}
onClick={handleBatteryViewButton}
> >
<ArrowBackIcon /> <FormattedMessage id="main_stats" defaultMessage="Battery View" />
</IconButton> </Button>
<Button
variant="contained"
sx={{
marginTop: '20px',
marginLeft: '20px',
backgroundColor: '#808080',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage id="main_stats" defaultMessage="Main Stats" />
</Button>
<Button <Button
variant="contained" variant="contained"

View File

@ -35,13 +35,7 @@ function Configuration(props: ConfigurationProps) {
return null; return null;
} }
const CalibrationChargeOptions = [ const forcedCalibrationChargeOptions = [
'Repetitive Calibration',
'Additional Calibration',
'Force Calibration Now'
];
const CalibrationChargeOptionsController = [
'RepetitivelyEvery', 'RepetitivelyEvery',
'AdditionallyOnce', 'AdditionallyOnce',
'ChargePermanently' 'ChargePermanently'
@ -70,55 +64,31 @@ function Configuration(props: ConfigurationProps) {
selectedForcedCalibrationChargeOption, selectedForcedCalibrationChargeOption,
setSelectedForcedCalibrationChargeOption setSelectedForcedCalibrationChargeOption
] = useState<string>( ] = useState<string>(
CalibrationChargeOptions[ props.values.calibrationChargeForced[0].value.toString()
CalibrationChargeOptionsController.indexOf(
props.values.calibrationChargeState[0].value.toString()
)
]
); );
const [formValues, setFormValues] = useState<ConfigurationValues>({ const [formValues, setFormValues] = useState<ConfigurationValues>({
minimumSoC: props.values.minimumSoC[0].value, minimumSoC: props.values.minimumSoC[0].value,
gridSetPoint: (props.values.gridSetPoint[0].value as number) / 1000, gridSetPoint: (props.values.gridSetPoint[0].value as number) / 1000,
CalibrationChargeState: CalibrationChargeOptionsController.indexOf( forceCalibrationCharge: forcedCalibrationChargeOptions.indexOf(
props.values.calibrationChargeState[0].value.toString() props.values.calibrationChargeForced[0].value.toString()
), ),
calibrationChargeDate: calibrationChargeDate: null
CalibrationChargeOptionsController.indexOf(
props.values.calibrationChargeState[0].value.toString()
) == 0
? dayjs(props.values.repetitiveCalibrationChargeDate[0].value).toDate()
: dayjs(props.values.additionalCalibrationChargeDate[0].value).toDate()
}); });
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
if ( setLoading(true);
props.values.mode[0].value === 'CalibrationCharge' && const res = await axiosConfig
formValues.CalibrationChargeState == 0 .post(`/EditInstallationConfig?installationId=${props.id}`, formValues)
) { .catch((err) => {
setDateSelectionError( if (err.response) {
'You cannot change the date while the installation is in Calibration Charge Mode' setError(true);
); setLoading(false);
setErrorDateModalOpen(true); }
return; });
} else if (dayjs(formValues.calibrationChargeDate).isBefore(dayjs())) {
setDateSelectionError('You must specify a future date');
setErrorDateModalOpen(true);
return;
} else {
setLoading(true);
const res = await axiosConfig
.post(`/EditInstallationConfig?installationId=${props.id}`, formValues)
.catch((err) => {
if (err.response) {
setError(true);
setLoading(false);
}
});
if (res) { if (res) {
setUpdated(true); setUpdated(true);
setLoading(false); setLoading(false);
}
} }
}; };
@ -127,6 +97,12 @@ function Configuration(props: ConfigurationProps) {
}; };
const handleConfirm = (newDate) => { const handleConfirm = (newDate) => {
if (newDate.isBefore(dayjs())) {
setDateSelectionError('You must specify a future date');
setErrorDateModalOpen(true);
return;
}
setFormValues({ setFormValues({
...formValues, ...formValues,
['calibrationChargeDate']: newDate.toDate() ['calibrationChargeDate']: newDate.toDate()
@ -138,17 +114,9 @@ function Configuration(props: ConfigurationProps) {
setFormValues({ setFormValues({
...formValues, ...formValues,
['CalibrationChargeState']: CalibrationChargeOptions.indexOf( ['forceCalibrationCharge']: forcedCalibrationChargeOptions.indexOf(
event.target.value event.target.value
), )
['calibrationChargeDate']:
CalibrationChargeOptions.indexOf(event.target.value) == 0
? dayjs(
props.values.repetitiveCalibrationChargeDate[0].value
).toDate()
: dayjs(
props.values.additionalCalibrationChargeDate[0].value
).toDate()
}); });
}; };
@ -290,7 +258,7 @@ function Configuration(props: ConfigurationProps) {
> >
<FormattedMessage <FormattedMessage
id="forced_calibration_charge" id="forced_calibration_charge"
defaultMessage="Calibration Charge State" defaultMessage="Forced Calibration Charge"
/> />
</InputLabel> </InputLabel>
<Select <Select
@ -300,7 +268,7 @@ function Configuration(props: ConfigurationProps) {
onClose={handleCloseForcedCalibrationCharge} onClose={handleCloseForcedCalibrationCharge}
onOpen={handleOpenForcedCalibrationCharge} onOpen={handleOpenForcedCalibrationCharge}
> >
{CalibrationChargeOptions.map((option) => ( {forcedCalibrationChargeOptions.map((option) => (
<MenuItem key={option} value={option}> <MenuItem key={option} value={option}>
{option} {option}
</MenuItem> </MenuItem>
@ -308,12 +276,22 @@ function Configuration(props: ConfigurationProps) {
</Select> </Select>
</FormControl> </FormControl>
</div> </div>
{formValues.CalibrationChargeState != 2 && ( {formValues.forceCalibrationCharge != 2 && (
<div> <div>
<LocalizationProvider dateAdapter={AdapterDayjs}> <LocalizationProvider dateAdapter={AdapterDayjs}>
<DateTimePicker <DateTimePicker
label="Select Next Calibration Charge Date" label="Select Next Calibration Charge Date"
value={dayjs(formValues.calibrationChargeDate)} value={
formValues.forceCalibrationCharge == 0
? dayjs(
props.values.repetitiveCalibrationChargeDate[0]
.value
)
: dayjs(
props.values.additionalCalibrationChargeDate[0]
.value
)
}
onChange={handleConfirm} onChange={handleConfirm}
sx={{ sx={{
marginTop: 2 marginTop: 2

View File

@ -278,7 +278,6 @@ function Installation(props: singleInstallationProps) {
<BatteryView <BatteryView
values={values} values={values}
s3Credentials={s3Credentials} s3Credentials={s3Credentials}
installationId={props.current_installation.id}
></BatteryView> ></BatteryView>
} }
></Route> ></Route>

View File

@ -31,7 +31,7 @@ export interface I_BoxDataValue {
export type ConfigurationValues = { export type ConfigurationValues = {
minimumSoC: string | number; minimumSoC: string | number;
gridSetPoint: number; gridSetPoint: number;
CalibrationChargeState: number; forceCalibrationCharge: number;
calibrationChargeDate: Date | null; calibrationChargeDate: Date | null;
}; };
@ -157,7 +157,7 @@ export type TopologyValues = {
gridSetPoint: I_BoxDataValue[]; gridSetPoint: I_BoxDataValue[];
maximumDischargePower: I_BoxDataValue[]; maximumDischargePower: I_BoxDataValue[];
DcDcNum: I_BoxDataValue[]; DcDcNum: I_BoxDataValue[];
calibrationChargeState: I_BoxDataValue[]; calibrationChargeForced: I_BoxDataValue[];
mode: I_BoxDataValue[]; mode: I_BoxDataValue[];
repetitiveCalibrationChargeDate: I_BoxDataValue[]; repetitiveCalibrationChargeDate: I_BoxDataValue[];
additionalCalibrationChargeDate: I_BoxDataValue[]; additionalCalibrationChargeDate: I_BoxDataValue[];
@ -296,7 +296,7 @@ export const topologyPaths: TopologyPaths = {
gridSetPoint: ['/Config/GridSetPoint'], gridSetPoint: ['/Config/GridSetPoint'],
maximumDischargePower: ['/Config/MaxBatteryDischargingCurrent'], maximumDischargePower: ['/Config/MaxBatteryDischargingCurrent'],
DcDcNum: ['/DcDc/SystemControl/NumberOfConnectedSlaves'], DcDcNum: ['/DcDc/SystemControl/NumberOfConnectedSlaves'],
calibrationChargeState: ['/Config/ForceCalibrationChargeState'], calibrationChargeForced: ['/Config/ForceCalibrationChargeState'],
mode: ['/EssControl/Mode'], mode: ['/EssControl/Mode'],
repetitiveCalibrationChargeDate: [ repetitiveCalibrationChargeDate: [
'/Config/DayAndTimeForRepetitiveCalibration' '/Config/DayAndTimeForRepetitiveCalibration'