diff --git a/csharp/App/Backend/Database/Create.cs b/csharp/App/Backend/Database/Create.cs index 14825c49f..d1b50e107 100644 --- a/csharp/App/Backend/Database/Create.cs +++ b/csharp/App/Backend/Database/Create.cs @@ -109,7 +109,7 @@ public static partial class Db } else { - Console.WriteLine("---------------Added the new Error to the database-----------------"); + Console.WriteLine("---------------Added the new Warning to the database-----------------"); Create(newWarning); } } diff --git a/csharp/App/Backend/Websockets/AlarmOrWarning.cs b/csharp/App/Backend/Websockets/AlarmOrWarning.cs index 4c4d2c31a..6f737032b 100644 --- a/csharp/App/Backend/Websockets/AlarmOrWarning.cs +++ b/csharp/App/Backend/Websockets/AlarmOrWarning.cs @@ -8,4 +8,4 @@ public class AlarmOrWarning public required String Time { get; set; } public required String Description { get; set; } public required String CreatedBy { get; set; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/csharp/App/Backend/Websockets/RabbitMQManager.cs b/csharp/App/Backend/Websockets/RabbitMQManager.cs index 0ca03cdb5..dcefab264 100644 --- a/csharp/App/Backend/Websockets/RabbitMQManager.cs +++ b/csharp/App/Backend/Websockets/RabbitMQManager.cs @@ -50,6 +50,8 @@ public static class RabbitMqManager var message = Encoding.UTF8.GetString(body); //A message can be an alarm, a warning or a heartbit StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize(message); + + lock (WebsocketManager.InstallationConnections) { @@ -73,6 +75,7 @@ public static class RabbitMqManager //Traverse the Warnings list, and store each of them to the database if (receivedStatusMessage.Warnings != null) { + foreach (var warning in receivedStatusMessage.Warnings) { Warning newWarning = new Warning @@ -85,6 +88,7 @@ public static class RabbitMqManager Seen = false }; //Create a new warning and add it to the database + Console.WriteLine("Add a warning for installation "+installationId); Db.HandleWarning(newWarning, installationId); } } @@ -93,7 +97,7 @@ public static class RabbitMqManager //Traverse the Alarm list, and store each of them to the database if (receivedStatusMessage.Alarms != null) { - Console.WriteLine("Add an alarm for installation "+installationId); + foreach (var alarm in receivedStatusMessage.Alarms) { Error newError = new Error @@ -104,7 +108,7 @@ public static class RabbitMqManager Time = alarm.Time, DeviceCreatedTheMessage = alarm.CreatedBy, Seen = false - }; + }; Console.WriteLine("Add an alarm for installation "+installationId); //Create a new error and add it to the database Db.HandleError(newError, installationId); } @@ -139,6 +143,7 @@ public static class RabbitMqManager } } + } }; Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer); diff --git a/csharp/App/Backend/Websockets/StatusMessage.cs b/csharp/App/Backend/Websockets/StatusMessage.cs index 0a4a707bd..73009a3a9 100644 --- a/csharp/App/Backend/Websockets/StatusMessage.cs +++ b/csharp/App/Backend/Websockets/StatusMessage.cs @@ -4,7 +4,8 @@ namespace InnovEnergy.App.Backend.Websockets; public class StatusMessage { public required Int32 InstallationId { get; set; } - public required int Status { get; set; } + public required Int32 Product { get; set; } + public required Int32 Status { get; set; } public required MessageType Type { get; set; } public List? Warnings { get; set; } public List? Alarms { get; set; } diff --git a/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs b/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs index 15169c2b2..6b24a74cf 100644 --- a/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs +++ b/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs @@ -5,6 +5,7 @@ namespace InnovEnergy.App.SaliMax.DataTypes; public class StatusMessage { public required Int32 InstallationId { get; set; } + public required Int32 Product { get; set; } public required SalimaxAlarmState Status { get; set; } public required MessageType Type { get; set; } public List? Warnings { get; set; } diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index ee0a76355..c51db600d 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -1,4 +1,4 @@ -#undef Amax +#define Amax #undef GridLimit using System.IO.Compression; diff --git a/csharp/App/VrmGrabber/db.sqlite b/csharp/App/VrmGrabber/db.sqlite index 4847f0a8b..29961ffce 100644 Binary files a/csharp/App/VrmGrabber/db.sqlite and b/csharp/App/VrmGrabber/db.sqlite differ diff --git a/typescript/frontend-marios2/src/content/dashboards/BatteryView/MainStats.tsx b/typescript/frontend-marios2/src/content/dashboards/BatteryView/MainStats.tsx index 3744c5799..7861a57c8 100644 --- a/typescript/frontend-marios2/src/content/dashboards/BatteryView/MainStats.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/BatteryView/MainStats.tsx @@ -114,6 +114,16 @@ function MainStats(props: MainStatsProps) { }); }, []); + 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 = [ @@ -223,11 +233,14 @@ function MainStats(props: MainStatsProps) { setErrorDateModalOpen(false); }; + const startZoom = () => { + setIsZooming(true); + }; + const handleBeforeZoom = (chartContext, { xaxis }) => { const startX = parseInt(xaxis.min) / 1000; const endX = parseInt(xaxis.max) / 1000; - setLoading(true); const resultPromise: Promise<{ chartData: BatteryDataInterface; chartOverview: BatteryOverviewInterface; @@ -246,7 +259,7 @@ function MainStats(props: MainStatsProps) { }) ); - setLoading(false); + setIsZooming(false); setChartState(batteryViewDataArray.length); }) .catch((error) => { @@ -509,7 +522,10 @@ function MainStats(props: MainStatsProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -568,7 +584,10 @@ function MainStats(props: MainStatsProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -626,7 +645,10 @@ function MainStats(props: MainStatsProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -684,7 +706,10 @@ function MainStats(props: MainStatsProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -742,7 +767,10 @@ function MainStats(props: MainStatsProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} diff --git a/typescript/frontend-marios2/src/content/dashboards/Information/InformationSalidomo.tsx b/typescript/frontend-marios2/src/content/dashboards/Information/InformationSalidomo.tsx index fa4edbd13..4e4ba1481 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Information/InformationSalidomo.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Information/InformationSalidomo.tsx @@ -288,6 +288,26 @@ function InformationSalidomo(props: InformationSalidomoProps) { /> +
+ +
+ +
+ +
+
{ let path = location.pathname.split('/'); @@ -50,7 +50,11 @@ function InstallationTabs() { }, [location]); useEffect(() => { - if (!socket && salimaxInstallations.length > 0) { + if (salimaxInstallations && salimaxInstallations.length > 0) { + if (socket) { + closeSocket(); + } + openSocket(salimaxInstallations); } }, [salimaxInstallations]); diff --git a/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx b/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx index 4b96a1343..8881c7f1e 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Overview/overview.tsx @@ -71,6 +71,15 @@ function Overview(props: OverviewProps) { const [startDate, setStartDate] = useState(dayjs().add(-1, 'day')); const [endDate, setEndDate] = useState(dayjs()); + const [isZooming, setIsZooming] = useState(false); + + useEffect(() => { + if (isZooming) { + setLoading(true); + } else if (!isZooming && dailyDataArray.length > 0) { + setLoading(false); + } + }, [isZooming, dailyDataArray]); useEffect(() => { const resultPromise: Promise<{ @@ -97,11 +106,14 @@ function Overview(props: OverviewProps) { }); }, []); + const startZoom = () => { + setIsZooming(true); + }; + const handleBeforeZoom = (chartContext, { xaxis }) => { const startX = parseInt(xaxis.min) / 1000; const endX = parseInt(xaxis.max) / 1000; - setLoading(true); const resultPromise: Promise<{ chartData: chartDataInterface; chartOverview: overviewInterface; @@ -111,21 +123,31 @@ function Overview(props: OverviewProps) { UnixTime.fromTicks(endX) ); + let isComponentMounted = true; + resultPromise .then((result) => { - setDailyDataArray((prevData) => - prevData.concat({ - chartData: result.chartData, - chartOverview: result.chartOverview - }) - ); - - setLoading(false); - setChartState(dailyDataArray.length); + if (isComponentMounted) { + setDailyDataArray((prevData) => + prevData.concat({ + chartData: result.chartData, + chartOverview: result.chartOverview + }) + ); + setIsZooming(false); + setChartState(dailyDataArray.length); + } }) .catch((error) => { - console.error('Error:', error); + if (isComponentMounted) { + console.error('Error:', error); + setLoading(false); // Ensure loading is turned off even if there is an error + } }); + + return () => { + isComponentMounted = false; + }; }; const handle24HourData = () => { @@ -595,7 +617,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -761,7 +786,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -851,7 +879,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -982,7 +1013,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -1040,7 +1074,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -1111,7 +1148,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} @@ -1196,7 +1236,10 @@ function Overview(props: OverviewProps) { ), chart: { events: { - beforeZoom: handleBeforeZoom + beforeZoom: (chartContext, options) => { + startZoom(); + handleBeforeZoom(chartContext, options); + } } } }} diff --git a/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/FlatInstallationView.tsx b/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/FlatInstallationView.tsx index ce419e002..54cac80e9 100644 --- a/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/FlatInstallationView.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/FlatInstallationView.tsx @@ -1,6 +1,7 @@ import React, { useContext, useState } from 'react'; import { Card, + CircularProgress, Grid, Table, TableBody, @@ -16,6 +17,7 @@ import { WebSocketContext } from 'src/contexts/WebSocketContextProvider'; import { FormattedMessage } from 'react-intl'; import { useLocation, useNavigate } from 'react-router-dom'; import routes from '../../../Resources/routes.json'; +import CancelIcon from '@mui/icons-material/Cancel'; interface FlatInstallationViewProps { installations: I_Installation[]; @@ -29,6 +31,21 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => { const [selectedInstallation, setSelectedInstallation] = useState(-1); const currentLocation = useLocation(); + const sortedInstallations = [...props.installations].sort((a, b) => { + // Compare the status field of each installation and sort them based on the status. + //Installations with alarms go first + let a_status = getStatus(a.id); + let b_status = getStatus(b.id); + + if (a_status > b_status) { + return -1; + } + if (a_status < b_status) { + return 1; + } + return 0; + }); + const handleSelectOneInstallation = (installationID: number): void => { if (selectedInstallation != installationID) { setSelectedInstallation(installationID); @@ -95,10 +112,13 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => { + + + - {props.installations.map((installation) => { + {sortedInstallations.map((installation) => { const isInstallationSelected = installation.s3BucketId === selectedInstallation; @@ -200,6 +220,57 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => { + + +
+ {status === -1 ? ( + + ) : ( + '' + )} + + {status === -2 ? ( + + ) : ( + '' + )} + +
+
+ ); })} diff --git a/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/Installation.tsx b/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/Installation.tsx index 4519132f0..b673f0d31 100644 --- a/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/Installation.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/SalidomoInstallations/Installation.tsx @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useState } from 'react'; -import { Card, Grid, Typography } from '@mui/material'; +import { Card, CircularProgress, Grid, Typography } from '@mui/material'; import { I_Installation } from 'src/interfaces/InstallationTypes'; import { UserContext } from 'src/contexts/userContext'; import { TimeSpan, UnixTime } from 'src/dataCache/time'; @@ -15,6 +15,8 @@ import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; import routes from '../../../Resources/routes.json'; import InformationSalidomo from '../Information/InformationSalidomo'; import BatteryView from '../BatteryView/BatteryView'; +import Log from '../Log/Log'; +import CancelIcon from '@mui/icons-material/Cancel'; interface singleInstallationProps { current_installation?: I_Installation; @@ -174,6 +176,69 @@ function Installation(props: singleInstallationProps) { {props.current_installation.installationName}
+
+ + Status: + +
+ {status === -1 ? ( + + ) : ( + '' + )} + + {status === -2 ? ( + + ) : ( + '' + )} + +
+
+
+ + } + /> + { let path = location.pathname.split('/'); @@ -43,6 +43,15 @@ function SalidomoInstallationTabs() { } }, [salidomoInstallations]); + useEffect(() => { + if (salidomoInstallations && salidomoInstallations.length > 0) { + if (socket) { + closeSocket(); + } + openSocket(salidomoInstallations); + } + }, [salidomoInstallations]); + const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => { setCurrentTab(value); }; @@ -83,6 +92,10 @@ function SalidomoInstallationTabs() { /> ) }, + { + value: 'log', + label: + }, { value: 'information',