created Live View on monitor for SodistoreHome

This commit is contained in:
Yinyin Liu 2025-11-08 13:52:06 +01:00
parent 7b4f4481a3
commit 6a90884a3c
5 changed files with 319 additions and 32 deletions

View File

@ -457,6 +457,7 @@ export interface JSONRecordData {
BatteryOperatingMode: string;
BatteryType: number;
ChargeCutoffSoc: number;
ConsumptionPower:number;
ControlPermession: number;
DischargeCutoffSoc: number;
EmsCommunicationFailureTime: number;
@ -495,6 +496,7 @@ export interface JSONRecordData {
SystemOperatingMode: string;
TotalEnergyToGrid: number;
TotalEnergyToUser: number;
TotalPvPower: number;
VppProtocolVerNumber: number;
};
@ -1040,7 +1042,12 @@ export const getHighestConnectionValue = (values: JSONRecordData) => {
'PvOnDc.Dc.Power',
'DcDc.Dc.Link.Power',
'LoadOnDc.Power',
'Battery.Dc.Power'
'Battery.Dc.Power',
'AcDcGrowatt.MeterPower',
'AcDcGrowatt.TotalPvPower',
'AcDcGrowatt.BatteriesRecords.Power',
'AcDcGrowatt.BatteriesRecords.TotalChargeEnergy',
'AcDcGrowatt.ConsumptionPower'
];
// Helper function to safely get a value from a nested path

View File

@ -25,6 +25,7 @@ import { fetchDataJson } from '../Installations/fetchData';
import { FetchResult } from '../../../dataCache/dataCache';
import BatteryViewSodioHome from '../BatteryView/BatteryViewSodioHome';
import SodistoreHomeConfiguration from './SodistoreHomeConfiguration';
import TopologySodistoreHome from '../Topology/TopologySodistoreHome';
interface singleInstallationProps {
current_installation?: I_Installation;
@ -434,12 +435,11 @@ function SodioHomeInstallation(props: singleInstallationProps) {
<Route
path={routes.live}
element={
<div></div>
// <Topology
// values={values}
// connected={connected}
// loading={loading}
// ></Topology>
<TopologySodistoreHome
values={values}
connected={connected}
loading={loading}
></TopologySodistoreHome>
}
/>

View File

@ -96,10 +96,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
const singleInstallationTabs =
currentUser.userType == UserType.admin
? [
// {
// value: 'live',
// label: <FormattedMessage id="live" defaultMessage="Live" />
// },
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
{
value: 'batteryview',
label: (
@ -155,10 +155,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
}
]
: [
// {
// value: 'live',
// label: <FormattedMessage id="live" defaultMessage="Live" />
// },
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
// {
// value: 'overview',
// label: <FormattedMessage id="overview" defaultMessage="Overview" />
@ -186,10 +186,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
value: 'tree',
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
},
// {
// value: 'live',
// label: <FormattedMessage id="live" defaultMessage="Live" />
// },
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
{
value: 'batteryview',
label: (
@ -256,10 +256,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
value: 'tree',
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
},
// {
// value: 'live',
// label: <FormattedMessage id="live" defaultMessage="Live" />
// },
{
value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" />
},
{
value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" />

View File

@ -0,0 +1,264 @@
import React, { useContext, useState } from 'react';
import {
CircularProgress,
Container,
Grid,
Switch,
Typography
} from '@mui/material';
import TopologyColumn from './topologyColumn';
import {
getAmount,
getHighestConnectionValue,
JSONRecordData
} from '../Log/graph.util';
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
interface TopologySodistoreHomeProps {
values: JSONRecordData;
connected: boolean;
loading: boolean;
}
function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
if (props.values === null && props.connected == true) {
return null;
}
const highestConnectionValue =
props.values != null ? getHighestConnectionValue(props.values) : 0;
const { product, setProduct } = useContext(ProductIdContext);
const [showValues, setShowValues] = useState(false);
const handleSwitch = () => () => {
setShowValues(!showValues);
};
const isMobile = window.innerWidth <= 1490;
return (
<Container maxWidth="xl" style={{ backgroundColor: 'white' }}>
<Grid container>
{!props.connected && !props.loading && (
<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>
)}
{props.connected && (
<>
<Grid
item
xs={12}
md={12}
style={{
marginTop: '10px',
height: '20px',
display: 'flex',
flexDirection: 'row',
alignItems: 'right',
justifyContent: 'right'
}}
>
<div>
<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
item
xs={12}
md={12}
style={{
height: isMobile ? '550px' : '600px',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
}}
>
<TopologyColumn
centerBox={{
title: 'Grid',
data: props.values?.AcDcGrowatt
? [
{
value: props.values.AcDcGrowatt.MeterPower,
unit: 'W'
}
]
: undefined,
connected:
true
}}
centerConnection={{
orientation: 'horizontal',
data: props.values?.AcDcGrowatt
? {
value: props.values.AcDcGrowatt.MeterPower,
unit: 'W'
}
: undefined,
amount: props.values?.AcDcGrowatt
? getAmount(
highestConnectionValue,
props.values.AcDcGrowatt.MeterPower
)
: 0,
showValues: showValues
}}
isLast={false}
isFirst={true}
/>
{/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/}
<TopologyColumn
topBox={{
title: 'PV',
data: props.values?.AcDcGrowatt
? [
{
value: props.values.AcDcGrowatt.TotalPvPower,
unit: 'W'
}
]
: undefined,
connected:true
}}
topConnection={{
orientation: 'vertical',
position: 'top',
data: props.values?.AcDcGrowatt
? {
value: props.values.AcDcGrowatt.TotalPvPower,
unit: 'W'
}
: undefined,
amount: props.values?.AcDcGrowatt
? getAmount(highestConnectionValue, props.values.AcDcGrowatt.TotalPvPower)
: 0,
showValues: showValues
}}
centerBox={{
title: 'Inverter',
data: props.values?.AcDcGrowatt
? [
{
value: 0,
unit: 'W'
}
]
: undefined,
connected: true
}}
centerConnection={{
orientation: 'horizontal',
data: props.values?.AcDcGrowatt.BatteriesRecords
? {
value: props.values.AcDcGrowatt.BatteriesRecords.Power,
unit: 'W'
}
: undefined,
amount: props.values?.AcDcGrowatt.BatteriesRecords
? getAmount(
highestConnectionValue,
props.values.AcDcGrowatt.BatteriesRecords.Power,
)
: 0,
showValues: showValues
}}
bottomBox={{
title: 'Loads',
data: props.values?.AcDcGrowatt
? [
{
value: props.values.AcDcGrowatt.ConsumptionPower,
unit: 'W'
}
]
: undefined,
connected:true
}}
bottomConnection={{
orientation: 'vertical',
position: 'bottom',
data: props.values?.AcDcGrowatt
? {
value: props.values.AcDcGrowatt.ConsumptionPower,
unit: 'W'
}
: undefined,
amount: props.values?.AcDcGrowatt
? getAmount(
highestConnectionValue,
props.values.AcDcGrowatt.ConsumptionPower
)
: 0,
showValues: showValues
}}
isLast={false}
isFirst={false}
/>
{/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/}
<TopologyColumn
centerBox={{
title: 'Battery',
data: props.values.AcDcGrowatt.BatteriesRecords
? [
{
value: props.values.AcDcGrowatt.BatteriesRecords.AverageSoc,
unit: '%'
},
{
value: props.values.AcDcGrowatt.BatteriesRecords.Power,
unit: 'W'
}
]
: undefined,
connected: true
}}
isLast={true}
isFirst={false}
/>
</Grid>
</>
)}
</Grid>
</Container>
);
}
export default TopologySodistoreHome;

View File

@ -39,8 +39,8 @@ function formatPower(value, unit) {
const roundedValue = value.toFixed(1);
//Filter all values less than 100 Watts
if (magnitude === 0 && value < 100 && unit === 'W') {
//Filter all values less than 1 Watts(why?)
if (magnitude === 0 && value < 1 && unit === 'W') {
//console.log('DROP THIS VALUE ' + value);
return 0;
}
@ -72,8 +72,12 @@ function TopologyBox(props: TopologyBoxProps) {
: props.title === 'AC Loads' ||
props.title === 'DC Loads' ||
props.title === 'Pv Inverter' ||
props.title === 'Pv DC-DC'
props.title === 'Pv DC-DC' ||
props.title === 'PV' ||
props.title === 'Loads'
? '100px'
: props.title === 'Inverter'
? '150px'
: '150px',
backgroundColor: !props.data
? 'darkgrey'
@ -134,6 +138,17 @@ function TopologyBox(props: TopologyBoxProps) {
/>
)}
{props.data && props.title === 'Inverter' && (
<img
src={inverterImage}
style={{
width: '40px',
height: '40px',
color: 'orange'
}}
/>
)}
{props.data && props.title === 'DC Link' && (
<PowerInputIcon
style={{
@ -183,7 +198,8 @@ function TopologyBox(props: TopologyBoxProps) {
marginTop: '4px'
}}
>
{(props.title === 'Pv Inverter' ||
{(props.title === 'PV' ||
props.title === 'Pv Inverter' ||
props.title === 'Pv DC-DC') && (
<SolarPowerIcon
style={{
@ -207,7 +223,7 @@ function TopologyBox(props: TopologyBoxProps) {
}}
></BatteryCharging60Icon>
)}
{(props.title === 'AC Loads' || props.title === 'DC Loads') && (
{(props.title === 'AC Loads' || props.title === 'DC Loads' ||props.title === 'Loads') && (
<OutletIcon
style={{
fontSize: 30,