diff --git a/typescript/frontend-marios2/src/content/dashboards/BatteryView/BatteryView.tsx b/typescript/frontend-marios2/src/content/dashboards/BatteryView/BatteryView.tsx index 89fcf724b..4139096d5 100644 --- a/typescript/frontend-marios2/src/content/dashboards/BatteryView/BatteryView.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/BatteryView/BatteryView.tsx @@ -242,7 +242,7 @@ function BatteryView(props: BatteryViewProps) { > {battery.Warnings.value === '' ? ( 'None' - ) : battery.Warnings.value.toString().split(';').length > + ) : battery.Warnings.value.toString().split('-').length > 1 ? ( {battery.Alarms.value === '' ? ( 'None' - ) : battery.Alarms.value.toString().split(';').length > + ) : battery.Alarms.value.toString().split('-').length > 1 ? ( + + {'Node ' + props.batteryData.BatteryId} + +
{ if ( Object.hasOwnProperty.call(chartData[category].data, devicePath) && diff --git a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx index 40298e60b..2ce5bef64 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx @@ -18,7 +18,6 @@ import { import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import Button from '@mui/material/Button'; -import { DateField } from '@mui/x-date-pickers/DateField'; import axiosConfig from '../../../Resources/axiosConfig'; import { Close as CloseIcon } from '@mui/icons-material'; import MenuItem from '@mui/material/MenuItem'; @@ -57,6 +56,8 @@ function Configuration(props: ConfigurationProps) { const [loading, setLoading] = useState(false); const [error, setError] = useState(false); const [updated, setUpdated] = useState(false); + const [dateSelectionError, setDateSelectionError] = useState(''); + const [isErrorDateModalOpen, setErrorDateModalOpen] = useState(false); const [openForcedCalibrationCharge, setOpenForcedCalibrationCharge] = useState(false); const [ @@ -65,19 +66,13 @@ function Configuration(props: ConfigurationProps) { ] = useState( props.values.calibrationChargeForced[0].value.toString() ); - const [isDateModalOpen, setIsDateModalOpen] = useState(false); - const [calibrationChargeDate, setCalibrationChargeDate] = useState(); - const [isErrorDateModalOpen, setErrorDateModalOpen] = useState(false); - const [dateSelectionError, setDateSelectionError] = useState(''); - const [dateFieldOpen, setDateFieldOpen] = useState(false); - const [formValues, setFormValues] = useState({ minimumSoC: props.values.minimumSoC[0].value, gridSetPoint: (props.values.gridSetPoint[0].value as number) / 1000, forceCalibrationCharge: forcedCalibrationChargeOptions.indexOf( props.values.calibrationChargeForced[0].value.toString() ), - calibrationChargeDate: Date(props.values.calibrationChargeDate[0].value) + calibrationChargeDate: null }); const handleSubmit = async (e) => { @@ -97,30 +92,24 @@ function Configuration(props: ConfigurationProps) { } }; - const handleCancel = () => { - setIsDateModalOpen(false); - }; const handleOkOnErrorDateModal = () => { setErrorDateModalOpen(false); - setIsDateModalOpen(true); }; - const handleConfirm = () => { - setIsDateModalOpen(false); - - if (calibrationChargeDate.isBefore(dayjs())) { - setDateSelectionError('You must use a future date'); + const handleConfirm = (newDate) => { + if (newDate.isBefore(dayjs())) { + setDateSelectionError('You must specify a future date'); setErrorDateModalOpen(true); return; } - setDateFieldOpen(true); + setFormValues({ + ...formValues, + ['calibrationChargeDate']: newDate.toDate() + }); }; const handleSelectedCalibrationChargeChange = (event) => { - if (event.target.value != 'ChargePermanently') { - setIsDateModalOpen(true); - } setSelectedForcedCalibrationChargeOption(event.target.value); setFormValues({ @@ -181,6 +170,47 @@ function Configuration(props: ConfigurationProps) { alignItems="stretch" spacing={3} > + {isErrorDateModalOpen && ( + {}}> + + + {dateSelectionError} + + + + + + )}
- {(dateFieldOpen || formValues.forceCalibrationCharge != 2) && ( + {formValues.forceCalibrationCharge != 2 && (
-
)} - {isErrorDateModalOpen && ( - {}}> - - - {dateSelectionError} - - - - - - )} - - {isDateModalOpen && ( - - {}}> - - - setCalibrationChargeDate(newDate) - } - sx={{ - marginTop: 2 - }} - /> - -
- - - -
-
-
-
- )} -
)} - {error && ( - - An error has occurred - setError(false)} // Set error state to false on click - sx={{ marginLeft: '4px' }} - > - - - - )} + {updated && ( key: [{unit:'',value:''},{unit:'',value:''},...] +//battery_view: [ {"Battery_id": 2,'FwVersion': {'unit':,'value':}}, +// {"Battery_id": 4,'FwVersion': {'unit':,'value':}} +//] +//For batteries, we follow a different approach. We define a key battery_view that is of type Battery[] + export const extractValues = ( timeSeriesData: DataPoint ): TopologyValues | null => { const extractedValues: TopologyValues = {} as TopologyValues; for (const topologyKey of Object.keys(topologyPaths)) { + //Each topologykey may have more than one paths (for example inverter) const paths = topologyPaths[topologyKey]; let topologyValues: { unit: string; value: string | number }[] = []; if (topologyKey === 'batteryView') { extractedValues[topologyKey] = []; - const battery_ids_from_csv = timeSeriesData.value[ + const node_ids_from_csv = timeSeriesData.value[ '/Config/Devices/BatteryNodes' ].value .toString() @@ -322,7 +338,11 @@ export const extractValues = ( while (pathIndex < paths.length) { let battery = {}; let existingKeys = 0; - battery[BatteryKeys[0]] = battery_ids_from_csv[battery_index]; + + //We prepare a battery object for each node. We extract the nodes from the '/Config/Devices/BatteryNodes' path. For example, nodes can be [2,4,5,6] (one is missing) + //BatteryKeys[0] is the battery id. We set the battery id to the corresponding node id. + battery[BatteryKeys[0]] = node_ids_from_csv[battery_index]; + //Then, search all the remaining battery keys for (let i = 1; i < BatteryKeys.length; i++) { const path = paths[pathIndex]; if (timeSeriesData.value.hasOwnProperty(path)) { diff --git a/typescript/frontend-marios2/src/interfaces/Chart.tsx b/typescript/frontend-marios2/src/interfaces/Chart.tsx index 804c0d475..d253827e7 100644 --- a/typescript/frontend-marios2/src/interfaces/Chart.tsx +++ b/typescript/frontend-marios2/src/interfaces/Chart.tsx @@ -61,6 +61,17 @@ export interface BatteryOverviewInterface { Current: chartInfoInterface; } +// We use this function in order to retrieve data for main stats. +//The data is of the following form: +//'Soc' : {name:'Soc',data:[ +// 'Node1': {name:'Node1', data: [[timestamp,value],[timestamp,value]]}, +// 'Node2': {name:'Node2', data: [[timestamp,value],[timestamp,value]]}, +// ]}, +//'Temperature' : {name:'Temperature',data:[ +// 'Node1': {name:'Node1', data: [[timestamp,value],[timestamp,value]]}, +// 'Node2': {name:'Node2', data: [[timestamp,value],[timestamp,value]]}, +// ]} + export const transformInputToBatteryViewData = async ( s3Credentials: I_S3Credentials, startTimestamp: UnixTime, @@ -94,18 +105,7 @@ export const transformInputToBatteryViewData = async ( '/Battery/Devices/10/' ]; - const pathsToSave = [ - 'Battery1', - 'Battery2', - 'Battery3', - 'Battery4', - 'Battery5', - 'Battery6', - 'Battery7', - 'Battery8', - 'Battery9', - 'Battery10' - ]; + const pathsToSave = []; const chartData: BatteryDataInterface = { Soc: { name: 'State Of Charge', data: [] }, @@ -123,20 +123,7 @@ export const transformInputToBatteryViewData = async ( Current: { magnitude: 0, unit: '', min: 0, max: 0 } }; - categories.forEach((category) => { - chartData[category].data = []; - pathsToSave.forEach((path) => { - chartData[category].data[path] = { name: path, data: [] }; - }); - - chartOverview[category] = { - magnitude: 0, - unit: '', - min: MAX_NUMBER, - max: -MAX_NUMBER - }; - }); - + let initialiation = true; let adjustedTimestampArray = []; let startTimestampToNum = Number(startTimestamp); @@ -160,6 +147,7 @@ export const transformInputToBatteryViewData = async ( adjustedTimestampArray.push(adjustedTimestamp); } + //Wait until fetching all the data const results = await Promise.all(timestampPromises); for (let i = 0; i < results.length; i++) { @@ -170,6 +158,32 @@ export const transformInputToBatteryViewData = async ( ) { // Handle not available or try later case } else { + const battery_nodes = result['/Config/Devices/BatteryNodes'].value + .toString() + .split(','); + + //Initialize the chartData structure based on the node names extracted from the first result + if (initialiation) { + initialiation = false; + + battery_nodes.forEach((node) => { + pathsToSave.push('Node' + node); + }); + categories.forEach((category) => { + chartData[category].data = []; + pathsToSave.forEach((path) => { + chartData[category].data[path] = { name: path, data: [] }; + }); + + chartOverview[category] = { + magnitude: 0, + unit: '', + min: MAX_NUMBER, + max: -MAX_NUMBER + }; + }); + } + for ( let category_index = 0; category_index < pathCategories.length;