Inserted select button to select firmware version.

This commit is contained in:
Noe 2024-04-30 14:07:50 +02:00
parent cee72bebe6
commit ccec20432b
15 changed files with 468 additions and 372 deletions

View File

@ -533,14 +533,14 @@ public class Controller : ControllerBase
} }
[HttpPost(nameof(UpdateFirmware))] [HttpPost(nameof(UpdateFirmware))]
public async Task<ActionResult> UpdateFirmware(Int64 batteryNode, Int64 installationId,Token authToken) public async Task<ActionResult> UpdateFirmware(Int64 batteryNode, Int64 installationId,String version,Token authToken)
{ {
var session = Db.GetSession(authToken); var session = Db.GetSession(authToken);
var installationToUpdate = Db.GetInstallationById(installationId); var installationToUpdate = Db.GetInstallationById(installationId);
if (installationToUpdate != null) if (installationToUpdate != null)
{ {
_ = session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode); _ = session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode,version);
} }
return Ok(); return Ok();

View File

@ -8,6 +8,7 @@ public class Installation : TreeNode
public String Region { get; set; } = ""; public String Region { get; set; } = "";
public String Country { get; set; } = ""; public String Country { get; set; } = "";
public String VpnIp { get; set; } = ""; public String VpnIp { get; set; } = "";
public String InstallationName { get; set; } = "";
public String S3Region { get; set; } = "sos-ch-dk-2"; public String S3Region { get; set; } = "sos-ch-dk-2";
public String S3Provider { get; set; } = "exo.io"; public String S3Provider { get; set; } = "exo.io";
@ -15,6 +16,7 @@ public class Installation : TreeNode
public String S3Key { get; set; } = ""; public String S3Key { get; set; } = "";
public String S3WriteSecret { get; set; } = ""; public String S3WriteSecret { get; set; } = "";
public String S3Secret { get; set; } = ""; public String S3Secret { get; set; } = "";
public int S3BucketId { get; set; } = 0;
public String ReadRoleId { get; set; } = ""; public String ReadRoleId { get; set; } = "";
public String WriteRoleId { get; set; } = ""; public String WriteRoleId { get; set; } = "";

View File

@ -131,7 +131,7 @@ public static class ExoCmd
if (response.StatusCode != HttpStatusCode.OK){ if (response.StatusCode != HttpStatusCode.OK){
Console.WriteLine("Fuck"); Console.WriteLine("Fuck");
} }
//Console.WriteLine($"Created Key for {installation.Name}"); //Console.WriteLine($"Created Key for {installation.InstallationName}");
var responseString = await response.Content.ReadAsStringAsync(); var responseString = await response.Content.ReadAsStringAsync();
var responseJson = JsonNode.Parse(responseString) ; var responseJson = JsonNode.Parse(responseString) ;
@ -143,10 +143,12 @@ public static class ExoCmd
{ {
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role"; const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
const String method = "iam-role"; const String method = "iam-role";
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.InstallationName:Db.Installations.Count(f => f.Product == 1) + installation.InstallationName;
var contentString = $$""" var contentString = $$"""
{ {
"name" : "{{installation.Id + installation.Name}}", "name" : "{{rolename}}",
"policy" : { "policy" : {
"default-service-strategy": "deny", "default-service-strategy": "deny",
"services": { "services": {
@ -243,10 +245,11 @@ public static class ExoCmd
{ {
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role"; const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
const String method = "iam-role"; const String method = "iam-role";
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.InstallationName:Db.Installations.Count(f => f.Product == 1) + installation.InstallationName;
var contentString = $$""" var contentString = $$"""
{ {
"name" : "WRITE{{installation.Id + installation.Name}}", "name" : "WRITE{{rolename}}",
"policy" : { "policy" : {
"default-service-strategy": "deny", "default-service-strategy": "deny",
"services": { "services": {

View File

@ -18,10 +18,10 @@ public static class InstallationMethods
{ {
if (installation.Product == 0) if (installation.Product == 0)
{ {
return $"{installation.Id}-{BucketNameSalt}"; return $"{installation.S3BucketId}-{BucketNameSalt}";
} }
return $"{installation.Id}-{SalidomoBucketNameSalt}"; return $"{installation.S3BucketId}-{SalidomoBucketNameSalt}";
} }

View File

@ -68,7 +68,7 @@ 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 RunScriptInBackground(this Session? session, String vpnIp, Int64 batteryNode,String version)
{ {
Console.WriteLine("-----------------------------------Start updating firmware-----------------------------------"); Console.WriteLine("-----------------------------------Start updating firmware-----------------------------------");
string scriptPath = "/home/ubuntu/backend/uploadBatteryFw/update_firmware.sh"; string scriptPath = "/home/ubuntu/backend/uploadBatteryFw/update_firmware.sh";
@ -77,7 +77,7 @@ public static class SessionMethods
{ {
Process process = new Process(); Process process = new Process();
process.StartInfo.FileName = "/bin/bash"; process.StartInfo.FileName = "/bin/bash";
process.StartInfo.Arguments = $"{scriptPath} {vpnIp} {batteryNode}"; process.StartInfo.Arguments = $"{scriptPath} {vpnIp} {batteryNode} {version}";
process.StartInfo.UseShellExecute = false; process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
@ -118,6 +118,8 @@ public static class SessionMethods
{ {
var user = session?.User; var user = session?.User;
//Salimax installation //Salimax installation
if (installation.Product==0) if (installation.Product==0)
{ {

View File

@ -16,6 +16,8 @@ public static partial class Db
public static Boolean Create(Installation installation) public static Boolean Create(Installation installation)
{ {
installation.S3BucketId = Installations.Count(f => f.Product == installation.Product)+1;
// SQLite wrapper is smart and *modifies* t's Id to the one generated (autoincrement) by the insertion // SQLite wrapper is smart and *modifies* t's Id to the one generated (autoincrement) by the insertion
return Insert(installation); return Insert(installation);
} }

View File

@ -108,7 +108,7 @@ public static partial class Db
Connection.CreateTable<Warning>(); Connection.CreateTable<Warning>();
}); });
UpdateKeys(); //UpdateKeys();
CleanupSessions().SupressAwaitWarning(); CleanupSessions().SupressAwaitWarning();
} }
@ -147,7 +147,19 @@ public static partial class Db
.Select(i => i.S3WriteKey) .Select(i => i.S3WriteKey)
.Distinct() .Distinct()
.ToList(); .ToList();
Console.WriteLine("VALID READ KEYS");
for (int i = 0; i < validReadKeys.Count; i++)
{
Console.WriteLine(validReadKeys[i]);
}
Console.WriteLine("VALID WRITE KEYS");
for (int i = 0; i < validReadKeys.Count; i++)
{
Console.WriteLine(validWriteKeys[i]);
}
const String provider = "exo.io"; const String provider = "exo.io";
@ -157,7 +169,7 @@ public static partial class Db
{ {
if (keyMetadata["key"].ToString()!="EXOa0b53cf10517307cec1bf00e" && !validReadKeys.Contains(keyMetadata["key"].ToString()) && !validWriteKeys.Contains(keyMetadata["key"].ToString())) if (keyMetadata["key"].ToString()!="EXOa0b53cf10517307cec1bf00e" && !validReadKeys.Contains(keyMetadata["key"].ToString()) && !validWriteKeys.Contains(keyMetadata["key"].ToString()))
{ {
await ExoCmd.RevokeReadKey(keyMetadata["key"].ToString()); //await ExoCmd.RevokeReadKey(keyMetadata["key"].ToString());
Console.WriteLine("Deleted key "+keyMetadata["key"]); Console.WriteLine("Deleted key "+keyMetadata["key"]);
} }

View File

@ -1,3 +1,4 @@
using Flurl.Http;
using Hellang.Middleware.ProblemDetails; using Hellang.Middleware.ProblemDetails;
using InnovEnergy.App.Backend.Database; using InnovEnergy.App.Backend.Database;
using InnovEnergy.App.Backend.Websockets; using InnovEnergy.App.Backend.Websockets;
@ -5,11 +6,13 @@ using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using Org.BouncyCastle.Math.EC;
namespace InnovEnergy.App.Backend; namespace InnovEnergy.App.Backend;
public static class Program public static class Program
{ {
public static void Main(String[] args) public static async Task Main(String[] args)
{ {
Watchdog.NotifyReady(); Watchdog.NotifyReady();
Db.Init(); Db.Init();
@ -18,7 +21,7 @@ public static class Program
RabbitMqManager.InitializeEnvironment(); RabbitMqManager.InitializeEnvironment();
RabbitMqManager.StartRabbitMqConsumer(); RabbitMqManager.StartRabbitMqConsumer();
WebsocketManager.MonitorInstallationTable(); WebsocketManager.MonitorInstallationTable();
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddProblemDetails(setup => builder.Services.AddProblemDetails(setup =>
{ {

View File

@ -58,7 +58,8 @@ public static class RabbitMqManager
{ {
Console.WriteLine("----------------------------------------------"); Console.WriteLine("----------------------------------------------");
Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status); Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status);
var installationId = receivedStatusMessage.InstallationId; int installationId = (int)Db.Installations.Where(f => f.Product == 0 && f.S3BucketId == receivedStatusMessage.InstallationId).Select(f => f.Id).FirstOrDefault();
//This is a heartbit message, just update the timestamp for this installation. //This is a heartbit message, just update the timestamp for this installation.
//There is no need to notify the corresponding front-ends. //There is no need to notify the corresponding front-ends.

View File

@ -32,21 +32,21 @@ interface BatteryViewProps {
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
installationId: number; installationId: number;
productNum: number; productNum: number;
connected: boolean;
} }
function BatteryView(props: BatteryViewProps) { function BatteryView(props: BatteryViewProps) {
if (props.values === null) { if (props.values === null && props.connected == true) {
return null; return null;
} }
const currentLocation = useLocation(); const currentLocation = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const sortedBatteryView = [...props.values.batteryView].sort( const sortedBatteryView =
(a, b) => b.BatteryId - a.BatteryId props.values != null
); ? [...props.values.batteryView].sort((a, b) => b.BatteryId - a.BatteryId)
: [];
const [loading, setLoading] = useState( const [loading, setLoading] = useState(sortedBatteryView.length == 0);
sortedBatteryView.length == 0 ? true : false
);
const handleMainStatsButton = () => { const handleMainStatsButton = () => {
navigate(routes.mainstats); navigate(routes.mainstats);
@ -70,7 +70,31 @@ function BatteryView(props: BatteryViewProps) {
return ( return (
<> <>
{loading && ( {!props.connected && (
<Container
maxWidth="xl"
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '70vh'
}}
>
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
<Typography
variant="body2"
style={{ color: 'black', fontWeight: 'bold' }}
mt={2}
>
Unable to communicate with the installation
</Typography>
<Typography variant="body2" style={{ color: 'black' }}>
Please wait or refresh the page
</Typography>
</Container>
)}
{loading && props.connected && (
<Container <Container
maxWidth="xl" maxWidth="xl"
sx={{ sx={{
@ -95,7 +119,7 @@ function BatteryView(props: BatteryViewProps) {
</Container> </Container>
)} )}
{!loading && ( {!loading && props.connected && (
<Container maxWidth="xl"> <Container maxWidth="xl">
<Grid container> <Grid container>
<Grid <Grid

View File

@ -5,8 +5,10 @@ import {
Card, Card,
Grid, Grid,
IconButton, IconButton,
MenuItem,
Modal, Modal,
Paper, Paper,
Select,
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
@ -18,7 +20,6 @@ import { Battery } from '../Log/graph.util';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; 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 axiosConfig from '../../../Resources/axiosConfig'; import axiosConfig from '../../../Resources/axiosConfig';
interface DetailedBatteryViewProps { interface DetailedBatteryViewProps {
@ -37,6 +38,10 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
const [openModalResultFirmwareUpdate, setOpenModalResultFirmwareUpdate] = const [openModalResultFirmwareUpdate, setOpenModalResultFirmwareUpdate] =
useState(false); useState(false);
const [selectedVersion, setSelectedVersion] = useState(
props.batteryData.FwVersion.value
);
const handleBatteryViewButton = () => { const handleBatteryViewButton = () => {
navigate(location.pathname.split('/').slice(0, -2).join('/')); navigate(location.pathname.split('/').slice(0, -2).join('/'));
}; };
@ -113,7 +118,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
.post( .post(
`/UpdateFirmware?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${ `/UpdateFirmware?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${
props.installationId props.installationId
}` }&version=${selectedVersion}`
) )
.catch((err) => { .catch((err) => {
if (err.response) { if (err.response) {
@ -264,7 +269,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
<IconButton <IconButton
aria-label="go back" aria-label="go back"
sx={{ sx={{
marginTop: '20px', marginTop: props.productNum != 0 ? '20px' : '0px',
backgroundColor: 'grey', backgroundColor: 'grey',
color: '#000000', color: '#000000',
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
@ -275,22 +280,38 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
</IconButton> </IconButton>
{props.productNum === 0 && ( {props.productNum === 0 && (
<Button <>
variant="contained" <Select
onClick={handleUpdateFirmware} value={selectedVersion}
sx={{ onChange={(event) => setSelectedVersion(event.target.value)}
marginTop: '20px', displayEmpty
marginLeft: '20px', variant="outlined"
backgroundColor: '#ffc04d', sx={{
color: '#000000', marginTop: '30px',
'&:hover': { bgcolor: '#f7b34d' } marginLeft: '20px',
}} height: '40px'
> }}
<FormattedMessage >
id="update_firmware" <MenuItem disabled value="">
defaultMessage="Update Firmware" Select Firmware Version
/> </MenuItem>
</Button> <MenuItem value="AF11">AF11</MenuItem>
<MenuItem value="AF0A">AF0A</MenuItem>
</Select>
<Button
variant="contained"
onClick={handleUpdateFirmware}
disabled={!selectedVersion} // Disable button if no version selected
sx={{
marginLeft: '20px',
backgroundColor: '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
Update Firmware
</Button>
</>
)} )}
</Grid> </Grid>
</Grid> </Grid>

View File

@ -1,11 +1,5 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { import { Card, CircularProgress, Grid, Typography } from '@mui/material';
Card,
CircularProgress,
Container,
Grid,
Typography
} from '@mui/material';
import { I_Installation } from 'src/interfaces/InstallationTypes'; import { I_Installation } from 'src/interfaces/InstallationTypes';
import { UserContext } from 'src/contexts/userContext'; import { UserContext } from 'src/contexts/userContext';
import AccessContextProvider from 'src/contexts/AccessContextProvider'; import AccessContextProvider from 'src/contexts/AccessContextProvider';
@ -49,10 +43,7 @@ function Installation(props: singleInstallationProps) {
failedToCommunicateWithInstallation, failedToCommunicateWithInstallation,
setFailedToCommunicateWithInstallation setFailedToCommunicateWithInstallation
] = useState(0); ] = useState(0);
const [ const [connected, setConnected] = useState(true);
openModalUnableToCommunicateWIthInstallation,
setOpenModalUnableToCommunicateWIthInstallation
] = useState(false);
if (props.current_installation == undefined) { if (props.current_installation == undefined) {
return null; return null;
@ -83,7 +74,7 @@ function Installation(props: singleInstallationProps) {
if (res != FetchResult.notAvailable && res != FetchResult.tryLater) { if (res != FetchResult.notAvailable && res != FetchResult.tryLater) {
setFailedToCommunicateWithInstallation(0); setFailedToCommunicateWithInstallation(0);
setOpenModalUnableToCommunicateWIthInstallation(false); setConnected(true);
setValues( setValues(
extractValues({ extractValues({
time: now, time: now,
@ -94,7 +85,7 @@ function Installation(props: singleInstallationProps) {
} else { } else {
setFailedToCommunicateWithInstallation((prevCount) => { setFailedToCommunicateWithInstallation((prevCount) => {
if (prevCount + 1 >= 3) { if (prevCount + 1 >= 3) {
setOpenModalUnableToCommunicateWIthInstallation(true); setConnected(false);
} }
return prevCount + 1; return prevCount + 1;
}); });
@ -125,7 +116,7 @@ function Installation(props: singleInstallationProps) {
useEffect(() => { useEffect(() => {
if (status === -1) { if (status === -1) {
setOpenModalUnableToCommunicateWIthInstallation(true); setConnected(false);
} }
}, [status]); }, [status]);
@ -160,10 +151,6 @@ function Installation(props: singleInstallationProps) {
} }
}, [currentTab, location]); }, [currentTab, location]);
const UnableToCommunicateModalHandleOk = () => {
setOpenModalUnableToCommunicateWIthInstallation(false);
};
return ( return (
<> <>
<Grid item xs={12} md={12}> <Grid item xs={12} md={12}>
@ -298,31 +285,6 @@ function Installation(props: singleInstallationProps) {
alignItems="stretch" alignItems="stretch"
spacing={0} spacing={0}
> >
{openModalUnableToCommunicateWIthInstallation && (
<Container
maxWidth="xl"
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '70vh'
}}
>
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
<Typography
variant="body2"
style={{ color: 'black', fontWeight: 'bold' }}
mt={2}
>
Unable to communicate with the installation
</Typography>
<Typography variant="body2" style={{ color: 'black' }}>
Please wait or refresh the page
</Typography>
</Container>
)}
<Routes> <Routes>
<Route <Route
path={routes.information} path={routes.information}
@ -343,6 +305,7 @@ function Installation(props: singleInstallationProps) {
s3Credentials={s3Credentials} s3Credentials={s3Credentials}
installationId={props.current_installation.id} installationId={props.current_installation.id}
productNum={props.current_installation.product} productNum={props.current_installation.product}
connected={connected}
></BatteryView> ></BatteryView>
} }
></Route> ></Route>
@ -353,7 +316,9 @@ function Installation(props: singleInstallationProps) {
<Route <Route
path={routes.live} path={routes.live}
element={<Topology values={values}></Topology>} element={
<Topology values={values} connected={connected}></Topology>
}
/> />
<Route <Route

View File

@ -13,8 +13,8 @@ import { FormattedMessage } from 'react-intl';
import { fetchData } from 'src/content/dashboards/Installations/fetchData'; import { fetchData } from 'src/content/dashboards/Installations/fetchData';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import routes from '../../../Resources/routes.json'; import routes from '../../../Resources/routes.json';
import BatteryView from '../BatteryView/BatteryView';
import InformationSalidomo from '../Information/InformationSalidomo'; import InformationSalidomo from '../Information/InformationSalidomo';
import BatteryView from "../BatteryView/BatteryView";
interface singleInstallationProps { interface singleInstallationProps {
current_installation?: I_Installation; current_installation?: I_Installation;
@ -31,6 +31,11 @@ function Installation(props: singleInstallationProps) {
const [currentTab, setCurrentTab] = useState<string>(undefined); const [currentTab, setCurrentTab] = useState<string>(undefined);
const [values, setValues] = useState<TopologyValues | null>(null); const [values, setValues] = useState<TopologyValues | null>(null);
const status = getStatus(props.current_installation.id); const status = getStatus(props.current_installation.id);
const [
failedToCommunicateWithInstallation,
setFailedToCommunicateWithInstallation
] = useState(0);
const [connected, setConnected] = useState(true);
if (props.current_installation == undefined) { if (props.current_installation == undefined) {
return null; return null;
@ -58,6 +63,8 @@ function Installation(props: singleInstallationProps) {
const res = await fetchData(now, s3Credentials); const res = await fetchData(now, s3Credentials);
if (res != FetchResult.notAvailable && res != FetchResult.tryLater) { if (res != FetchResult.notAvailable && res != FetchResult.tryLater) {
setConnected(true);
setFailedToCommunicateWithInstallation(0);
setValues( setValues(
extractValues({ extractValues({
time: now, time: now,
@ -66,6 +73,14 @@ function Installation(props: singleInstallationProps) {
); );
return true; return true;
} }
else {
setFailedToCommunicateWithInstallation((prevCount) => {
if (prevCount + 1 >= 3) {
setConnected(false);
}
return prevCount + 1;
});
}
} catch (err) { } catch (err) {
return false; return false;
} }
@ -120,6 +135,12 @@ function Installation(props: singleInstallationProps) {
}; };
} }
}, [currentTab, location]); }, [currentTab, location]);
useEffect(() => {
if (status === -1) {
setConnected(false);
}
}, [status]);
return ( return (
<> <>
@ -183,6 +204,7 @@ function Installation(props: singleInstallationProps) {
s3Credentials={s3Credentials} s3Credentials={s3Credentials}
installationId={props.current_installation.id} installationId={props.current_installation.id}
productNum={props.current_installation.product} productNum={props.current_installation.product}
connected={connected}
></BatteryView> ></BatteryView>
} }
></Route> ></Route>

View File

@ -1,5 +1,11 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Container, Grid, Switch, Typography } from '@mui/material'; import {
CircularProgress,
Container,
Grid,
Switch,
Typography
} from '@mui/material';
import TopologyColumn from './topologyColumn'; import TopologyColumn from './topologyColumn';
import { import {
getAmount, getAmount,
@ -9,14 +15,15 @@ import {
interface TopologyProps { interface TopologyProps {
values: TopologyValues; values: TopologyValues;
connected: boolean;
} }
function Topology(props: TopologyProps) { function Topology(props: TopologyProps) {
if (props.values === null) { if (props.values === null && props.connected == true) {
return null; return null;
} }
const highestConnectionValue =
const highestConnectionValue = getHighestConnectionValue(props.values); props.values != null ? getHighestConnectionValue(props.values) : 0;
const [showValues, setShowValues] = useState(false); const [showValues, setShowValues] = useState(false);
const handleSwitch = () => () => { const handleSwitch = () => () => {
@ -28,290 +35,322 @@ function Topology(props: TopologyProps) {
return ( return (
<Container maxWidth="xl" style={{ backgroundColor: 'white' }}> <Container maxWidth="xl" style={{ backgroundColor: 'white' }}>
<Grid container> <Grid container>
<Grid {!props.connected && (
item <Container
xs={12} maxWidth="xl"
md={12} sx={{
style={{ display: 'flex',
marginTop: '10px', flexDirection: 'column',
height: '20px', justifyContent: 'center',
display: 'flex', alignItems: 'center',
flexDirection: 'row', height: '70vh'
alignItems: 'right', }}
justifyContent: 'right' >
}} <CircularProgress size={60} style={{ color: '#ffc04d' }} />
> <Typography
<div> variant="body2"
<Typography sx={{ marginTop: '5px', marginRight: '20px' }}> style={{ color: 'black', fontWeight: 'bold' }}
Display Values mt={2}
>
Unable to communicate with the installation
</Typography> </Typography>
<Switch <Typography variant="body2" style={{ color: 'black' }}>
edge="start" Please wait or refresh the page
color="secondary" </Typography>
onChange={handleSwitch()} </Container>
sx={{ )}
'& .MuiSwitch-thumb': {
backgroundColor: 'orange' {props.connected && (
}, <>
marginLeft: '20px' <Grid
item
xs={12}
md={12}
style={{
marginTop: '10px',
height: '20px',
display: 'flex',
flexDirection: 'row',
alignItems: 'right',
justifyContent: 'right'
}} }}
/> >
</div> <div>
</Grid> <Typography sx={{ marginTop: '5px', marginRight: '20px' }}>
Display Values
</Typography>
<Switch
edge="start"
color="secondary"
onChange={handleSwitch()}
sx={{
'& .MuiSwitch-thumb': {
backgroundColor: 'orange'
},
marginLeft: '20px'
}}
/>
</div>
</Grid>
<Grid <Grid
item item
xs={12} xs={12}
md={12} md={12}
style={{ style={{
height: isMobile ? '550px' : '600px', height: isMobile ? '550px' : '600px',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center' justifyContent: 'center'
}} }}
> >
<TopologyColumn <TopologyColumn
centerBox={{ centerBox={{
title: 'Grid', title: 'Grid',
data: props.values.grid, data: props.values.grid,
connected: props.values.gridBox[0].value.toString() != 'Disabled' connected:
}} props.values.gridBox[0].value.toString() != 'Disabled'
centerConnection={{ }}
orientation: 'horizontal', centerConnection={{
data: props.values.gridToAcInConnection, orientation: 'horizontal',
amount: props.values.gridToAcInConnection data: props.values.gridToAcInConnection,
? getAmount( amount: props.values.gridToAcInConnection
highestConnectionValue, ? getAmount(
props.values.gridToAcInConnection highestConnectionValue,
) props.values.gridToAcInConnection
: 0, )
showValues: showValues : 0,
}} showValues: showValues
isLast={false} }}
isFirst={true} isLast={false}
/> isFirst={true}
<TopologyColumn />
topBox={{ <TopologyColumn
title: 'Pv Inverter', topBox={{
data: props.values.gridBusToPvOnGridbusConnection, title: 'Pv Inverter',
connected: data: props.values.gridBusToPvOnGridbusConnection,
props.values.pvOnAcGridBox[0].value.toString() != 'Disabled' connected:
}} props.values.pvOnAcGridBox[0].value.toString() != 'Disabled'
topConnection={{ }}
orientation: 'vertical', topConnection={{
position: 'top', orientation: 'vertical',
data: props.values.gridBusToPvOnGridbusConnection, position: 'top',
amount: props.values.gridBusToPvOnGridbusConnection data: props.values.gridBusToPvOnGridbusConnection,
? getAmount( amount: props.values.gridBusToPvOnGridbusConnection
highestConnectionValue, ? getAmount(
props.values.gridBusToPvOnGridbusConnection highestConnectionValue,
) props.values.gridBusToPvOnGridbusConnection
: 0, )
showValues: showValues : 0,
}} showValues: showValues
centerBox={{ }}
title: 'Grid Bus', centerBox={{
data: props.values.gridBus, title: 'Grid Bus',
connected: true data: props.values.gridBus,
}} connected: true
centerConnection={{ }}
orientation: 'horizontal', centerConnection={{
orientation: 'horizontal',
amount: props.values.gridBusToIslandBusConnection amount: props.values.gridBusToIslandBusConnection
? getAmount( ? getAmount(
highestConnectionValue, highestConnectionValue,
props.values.gridBusToIslandBusConnection props.values.gridBusToIslandBusConnection
) )
: 0, : 0,
data: props.values.gridBusToIslandBusConnection, data: props.values.gridBusToIslandBusConnection,
showValues: showValues showValues: showValues
}} }}
bottomBox={{ bottomBox={{
title: 'AC Loads', title: 'AC Loads',
data: props.values.gridBusToLoadOnGridBusConnection, data: props.values.gridBusToLoadOnGridBusConnection,
connected: connected:
props.values.loadOnAcGridBox[0].value.toString() != 'Disabled' props.values.loadOnAcGridBox[0].value.toString() !=
}} 'Disabled'
bottomConnection={{ }}
orientation: 'vertical', bottomConnection={{
position: 'bottom', orientation: 'vertical',
data: props.values.gridBusToLoadOnGridBusConnection, position: 'bottom',
amount: props.values.gridBusToLoadOnGridBusConnection data: props.values.gridBusToLoadOnGridBusConnection,
? getAmount( amount: props.values.gridBusToLoadOnGridBusConnection
highestConnectionValue, ? getAmount(
props.values.gridBusToLoadOnGridBusConnection highestConnectionValue,
) props.values.gridBusToLoadOnGridBusConnection
: 0, )
showValues: showValues : 0,
}} showValues: showValues
isLast={false} }}
isFirst={false} isLast={false}
/> isFirst={false}
<TopologyColumn />
topBox={{ <TopologyColumn
title: 'Pv Inverter', topBox={{
data: props.values.pvOnIslandBusToIslandBusConnection, title: 'Pv Inverter',
connected: data: props.values.pvOnIslandBusToIslandBusConnection,
props.values.pvOnIslandBusBox[0].value.toString() != 'Disabled' connected:
}} props.values.pvOnIslandBusBox[0].value.toString() !=
topConnection={{ 'Disabled'
orientation: 'vertical', }}
position: 'top', topConnection={{
data: props.values.pvOnIslandBusToIslandBusConnection, orientation: 'vertical',
amount: props.values.pvOnIslandBusToIslandBusConnection position: 'top',
? getAmount( data: props.values.pvOnIslandBusToIslandBusConnection,
highestConnectionValue, amount: props.values.pvOnIslandBusToIslandBusConnection
props.values.pvOnIslandBusToIslandBusConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.pvOnIslandBusToIslandBusConnection
showValues: showValues )
}} : 0,
centerBox={{ showValues: showValues
title: 'Island Bus', }}
data: props.values.islandBus, centerBox={{
connected: true title: 'Island Bus',
}} data: props.values.islandBus,
centerConnection={{ connected: true
orientation: 'horizontal', }}
data: props.values.islandBusToInverter, centerConnection={{
amount: props.values.islandBusToInverter orientation: 'horizontal',
? getAmount( data: props.values.islandBusToInverter,
highestConnectionValue, amount: props.values.islandBusToInverter
props.values.islandBusToInverter ? getAmount(
) highestConnectionValue,
: 0, props.values.islandBusToInverter
showValues: showValues )
}} : 0,
bottomBox={{ showValues: showValues
title: 'AC Loads', }}
data: props.values.islandBusToLoadOnIslandBusConnection, bottomBox={{
connected: title: 'AC Loads',
props.values.loadOnIslandBusBox[0].value.toString() != data: props.values.islandBusToLoadOnIslandBusConnection,
'Disabled' connected:
}} props.values.loadOnIslandBusBox[0].value.toString() !=
bottomConnection={{ 'Disabled'
orientation: 'vertical', }}
position: 'bottom', bottomConnection={{
data: props.values.islandBusToLoadOnIslandBusConnection, orientation: 'vertical',
amount: props.values.islandBusToLoadOnIslandBusConnection position: 'bottom',
? getAmount( data: props.values.islandBusToLoadOnIslandBusConnection,
highestConnectionValue, amount: props.values.islandBusToLoadOnIslandBusConnection
props.values.islandBusToLoadOnIslandBusConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.islandBusToLoadOnIslandBusConnection
showValues: showValues )
}} : 0,
isLast={false} showValues: showValues
isFirst={false} }}
/> isLast={false}
<TopologyColumn isFirst={false}
centerBox={{ />
title: 'AC-DC', <TopologyColumn
data: props.values.inverter, centerBox={{
connected: true title: 'AC-DC',
}} data: props.values.inverter,
centerConnection={{ connected: true
orientation: 'horizontal', }}
data: props.values.inverterToDcBus, centerConnection={{
amount: props.values.inverterToDcBus orientation: 'horizontal',
? getAmount( data: props.values.inverterToDcBus,
highestConnectionValue, amount: props.values.inverterToDcBus
props.values.inverterToDcBus ? getAmount(
) highestConnectionValue,
: 0, props.values.inverterToDcBus
showValues: showValues )
}} : 0,
isLast={false} showValues: showValues
isFirst={false} }}
/> isLast={false}
<TopologyColumn isFirst={false}
topBox={{ />
title: 'Pv DC-DC', <TopologyColumn
data: props.values.pvOnDcBusToDcBusConnection, topBox={{
connected: title: 'Pv DC-DC',
props.values.pvOnDcBox[0].value.toString() != 'Disabled' data: props.values.pvOnDcBusToDcBusConnection,
}} connected:
topConnection={{ props.values.pvOnDcBox[0].value.toString() != 'Disabled'
orientation: 'vertical', }}
position: 'top', topConnection={{
data: props.values.pvOnDcBusToDcBusConnection, orientation: 'vertical',
amount: props.values.pvOnDcBusToDcBusConnection position: 'top',
? getAmount( data: props.values.pvOnDcBusToDcBusConnection,
highestConnectionValue, amount: props.values.pvOnDcBusToDcBusConnection
props.values.pvOnDcBusToDcBusConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.pvOnDcBusToDcBusConnection
showValues: showValues )
}} : 0,
centerBox={{ showValues: showValues
title: 'DC Link', }}
data: props.values.dcBus, centerBox={{
connected: true title: 'DC Link',
}} data: props.values.dcBus,
centerConnection={{ connected: true
orientation: 'horizontal', }}
data: props.values.dcBusToDcDcConnection, centerConnection={{
amount: props.values.dcBusToDcDcConnection orientation: 'horizontal',
? getAmount( data: props.values.dcBusToDcDcConnection,
highestConnectionValue, amount: props.values.dcBusToDcDcConnection
props.values.dcBusToDcDcConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.dcBusToDcDcConnection
showValues: showValues )
}} : 0,
bottomBox={{ showValues: showValues
title: 'DC Loads', }}
data: props.values.dcBusToLoadOnDcConnection, bottomBox={{
connected: title: 'DC Loads',
props.values.loadOnDcBox[0].value.toString() != 'Disabled' data: props.values.dcBusToLoadOnDcConnection,
}} connected:
bottomConnection={{ props.values.loadOnDcBox[0].value.toString() != 'Disabled'
orientation: 'vertical', }}
position: 'bottom', bottomConnection={{
data: props.values.dcBusToLoadOnDcConnection, orientation: 'vertical',
amount: props.values.dcBusToLoadOnDcConnection position: 'bottom',
? getAmount( data: props.values.dcBusToLoadOnDcConnection,
highestConnectionValue, amount: props.values.dcBusToLoadOnDcConnection
props.values.dcBusToLoadOnDcConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.dcBusToLoadOnDcConnection
showValues: showValues )
}} : 0,
isLast={false} showValues: showValues
isFirst={false} }}
/> isLast={false}
<TopologyColumn isFirst={false}
centerBox={{ />
title: 'DC-DC', <TopologyColumn
data: props.values.dcDc, centerBox={{
connected: true title: 'DC-DC',
}} data: props.values.dcDc,
centerConnection={{ connected: true
orientation: 'horizontal', }}
data: props.values.dcDCToBatteryConnection, centerConnection={{
amount: props.values.dcDCToBatteryConnection orientation: 'horizontal',
? getAmount( data: props.values.dcDCToBatteryConnection,
highestConnectionValue, amount: props.values.dcDCToBatteryConnection
props.values.dcDCToBatteryConnection ? getAmount(
) highestConnectionValue,
: 0, props.values.dcDCToBatteryConnection
showValues: showValues )
}} : 0,
isLast={false} showValues: showValues
isFirst={false} }}
/> isLast={false}
<TopologyColumn isFirst={false}
centerBox={{ />
title: 'Battery', <TopologyColumn
data: props.values.battery, centerBox={{
connected: title: 'Battery',
props.values.batteryBox[0].value.toString() != 'Disabled' data: props.values.battery,
}} connected:
isLast={true} props.values.batteryBox[0].value.toString() != 'Disabled'
isFirst={false} }}
/> isLast={true}
</Grid> isFirst={false}
/>
</Grid>
</>
)}
</Grid> </Grid>
</Container> </Container>
); );

View File

@ -86,7 +86,7 @@ export const transformInputToBatteryViewData = async (
const categories = ['Soc', 'Temperature', 'Power', 'Voltage', 'Current']; const categories = ['Soc', 'Temperature', 'Power', 'Voltage', 'Current'];
const pathCategories = [ const pathCategories = [
'Soc', 'Soc',
'Temperatures/Cells/Center', 'Temperatures/Cells/Average',
'Dc/Power', 'Dc/Power',
'Dc/Voltage', 'Dc/Voltage',
'Dc/Current' 'Dc/Current'