diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index b9278ccb6..bfc787bcc 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -200,6 +200,8 @@ public class Controller : ControllerBase bucketPath = "s3://" + installation.S3BucketId + "-3e5b3069-214a-43ee-8d85-57d72000c19d/" + startTimestamp; else if (installation.Product == (int)ProductType.SodioHome) bucketPath = "s3://" + installation.S3BucketId + "-e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa/" + startTimestamp; + else if (installation.Product == (int)ProductType.SodistoreGrid) + bucketPath = "s3://" + installation.S3BucketId + "-5109c126-e141-43ab-8658-f3c44c838ae8/" + startTimestamp; else bucketPath = "s3://" + installation.S3BucketId + "-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/" + startTimestamp; Console.WriteLine("Fetching data for "+startTimestamp); @@ -537,16 +539,29 @@ public class Controller : ControllerBase public ActionResult> GetAllSodioHomeInstallations(Token authToken) { var user = Db.GetSession(authToken)?.User; - + if (user is null) return Unauthorized(); - + return user .AccessibleInstallations(product:(int)ProductType.SodioHome) .ToList(); } - - + + [HttpGet(nameof(GetAllSodistoreGridInstallations))] + public ActionResult> GetAllSodistoreGridInstallations(Token authToken) + { + var user = Db.GetSession(authToken)?.User; + + if (user is null) + return Unauthorized(); + + return user + .AccessibleInstallations(product:(int)ProductType.SodistoreGrid) + .ToList(); + } + + [HttpGet(nameof(GetAllFolders))] public ActionResult> GetAllFolders(Token authToken) @@ -1513,6 +1528,7 @@ public class Controller : ControllerBase 0 => config.GetConfigurationSalimax(), // Salimax 3 => config.GetConfigurationSodistoreMax(), // SodiStoreMax 2 => config.GetConfigurationSodistoreHome(), // SodiStoreHome + 4 => config.GetConfigurationSodistoreGrid(), // SodistoreGrid _ => config.GetConfigurationString() // fallback }; diff --git a/csharp/App/Backend/DataTypes/Configuration.cs b/csharp/App/Backend/DataTypes/Configuration.cs index a99492044..5c0726ca5 100644 --- a/csharp/App/Backend/DataTypes/Configuration.cs +++ b/csharp/App/Backend/DataTypes/Configuration.cs @@ -48,6 +48,12 @@ public class Configuration $"BatteriesCount: {BatteriesCount}, ClusterNumber: {ClusterNumber}, PvNumber: {PvNumber}, ControlPermission:{ControlPermission}, "+ $"SinexcelTimeChargeandDischargePower: {TimeChargeandDischargePower}, SinexcelStartTimeChargeandDischargeDayandTime: {StartTimeChargeandDischargeDayandTime}, SinexcelStopTimeChargeandDischargeDayandTime: {StopTimeChargeandDischargeDayandTime}"; } + + // TODO: SodistoreGrid — update configuration fields when defined + public string GetConfigurationSodistoreGrid() + { + return ""; + } } public enum CalibrationChargeType diff --git a/csharp/App/Backend/DataTypes/Installation.cs b/csharp/App/Backend/DataTypes/Installation.cs index fe9cb24b1..70406e08c 100644 --- a/csharp/App/Backend/DataTypes/Installation.cs +++ b/csharp/App/Backend/DataTypes/Installation.cs @@ -7,7 +7,8 @@ public enum ProductType Salimax = 0, Salidomo = 1, SodioHome =2, - SodiStoreMax=3 + SodiStoreMax=3, + SodistoreGrid=4 } public enum StatusType diff --git a/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs b/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs index a0173ada5..ab3526cfe 100644 --- a/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs +++ b/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs @@ -145,6 +145,7 @@ public static class ExoCmd const String method = "iam-role"; String rolename = installation.Product==(int)ProductType.Salimax?Db.Installations.Count(f => f.Product == (int)ProductType.Salimax) + installation.Name: installation.Product==(int)ProductType.SodiStoreMax?Db.Installations.Count(f => f.Product == (int)ProductType.SodiStoreMax) + installation.Name: + installation.Product==(int)ProductType.SodistoreGrid?Db.Installations.Count(f => f.Product == (int)ProductType.SodistoreGrid) + installation.Name: Db.Installations.Count(f => f.Product == (int)ProductType.Salidomo) + installation.Name; @@ -320,6 +321,7 @@ public static class ExoCmd const String method = "iam-role"; String rolename = installation.Product==(int)ProductType.Salimax?Db.Installations.Count(f => f.Product == (int)ProductType.Salimax) + installation.Name: installation.Product==(int)ProductType.SodiStoreMax?Db.Installations.Count(f => f.Product == (int)ProductType.SodiStoreMax) + installation.Name: + installation.Product==(int)ProductType.SodistoreGrid?Db.Installations.Count(f => f.Product == (int)ProductType.SodistoreGrid) + installation.Name: Db.Installations.Count(f => f.Product == (int)ProductType.Salidomo) + installation.Name; var contentString = $$""" diff --git a/csharp/App/Backend/DataTypes/Methods/Installation.cs b/csharp/App/Backend/DataTypes/Methods/Installation.cs index 7072e785a..0bd36b6f6 100644 --- a/csharp/App/Backend/DataTypes/Methods/Installation.cs +++ b/csharp/App/Backend/DataTypes/Methods/Installation.cs @@ -10,6 +10,7 @@ public static class InstallationMethods private static readonly String BucketNameSalt = "3e5b3069-214a-43ee-8d85-57d72000c19d"; private static readonly String SalidomoBucketNameSalt = "c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"; private static readonly String SodioHomeBucketNameSalt = "e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa"; + private static readonly String SodistoreGridBucketNameSalt = "5109c126-e141-43ab-8658-f3c44c838ae8"; public static String BucketName(this Installation installation) { @@ -17,12 +18,17 @@ public static class InstallationMethods { return $"{installation.S3BucketId}-{BucketNameSalt}"; } - + if (installation.Product == (int)ProductType.SodioHome) { return $"{installation.S3BucketId}-{SodioHomeBucketNameSalt}"; } + if (installation.Product == (int)ProductType.SodistoreGrid) + { + return $"{installation.S3BucketId}-{SodistoreGridBucketNameSalt}"; + } + return $"{installation.S3BucketId}-{SalidomoBucketNameSalt}"; } diff --git a/csharp/App/Backend/DataTypes/Methods/Session.cs b/csharp/App/Backend/DataTypes/Methods/Session.cs index 3b62cb6f3..be56b6ead 100644 --- a/csharp/App/Backend/DataTypes/Methods/Session.cs +++ b/csharp/App/Backend/DataTypes/Methods/Session.cs @@ -239,7 +239,7 @@ public static class SessionMethods } - if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodioHome) + if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodioHome || installation.Product == (int)ProductType.SodistoreGrid) { return user is not null && user.UserType != 0 @@ -295,9 +295,9 @@ public static class SessionMethods .Apply(Db.Update); } - if (installation.Product == (int)ProductType.SodiStoreMax) + if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodistoreGrid) { - + return user is not null && installation is not null && original is not null @@ -305,7 +305,7 @@ public static class SessionMethods && user.HasAccessTo(installation) && installation .WithParentOf(original) // prevent moving - .Apply(Db.Update); + .Apply(Db.Update); } diff --git a/csharp/App/Backend/DeleteOldData/DeleteOldDataFromS3.cs b/csharp/App/Backend/DeleteOldData/DeleteOldDataFromS3.cs index d4a6e3835..1588c33a8 100644 --- a/csharp/App/Backend/DeleteOldData/DeleteOldDataFromS3.cs +++ b/csharp/App/Backend/DeleteOldData/DeleteOldDataFromS3.cs @@ -12,7 +12,11 @@ public class DeleteOldDataFromS3 { string configPath = "/home/ubuntu/.s3cfg"; - string bucketPath = installation.Product ==(int)ProductType.Salidomo ? $"s3://{installation.S3BucketId}-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/{timestamps_to_delete}*" : $"s3://{installation.S3BucketId}-3e5b3069-214a-43ee-8d85-57d72000c19d/{timestamps_to_delete}*" ; + string bucketPath = installation.Product == (int)ProductType.Salidomo + ? $"s3://{installation.S3BucketId}-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/{timestamps_to_delete}*" + : installation.Product == (int)ProductType.SodistoreGrid + ? $"s3://{installation.S3BucketId}-5109c126-e141-43ab-8658-f3c44c838ae8/{timestamps_to_delete}*" + : $"s3://{installation.S3BucketId}-3e5b3069-214a-43ee-8d85-57d72000c19d/{timestamps_to_delete}*" ; //Console.WriteLine($"Deleting old data from {bucketPath}"); diff --git a/csharp/App/Backend/Relations/Session.cs b/csharp/App/Backend/Relations/Session.cs index 6128ce237..9b54bca5f 100644 --- a/csharp/App/Backend/Relations/Session.cs +++ b/csharp/App/Backend/Relations/Session.cs @@ -16,6 +16,7 @@ public class Session : Relation public Boolean AccessToSalidomo { get; set; } = false; public Boolean AccessToSodistoreMax { get; set; } = false; public Boolean AccessToSodioHome { get; set; } = false; + public Boolean AccessToSodistoreGrid { get; set; } = false; [Ignore] public Boolean Valid => DateTime.Now - LastSeen <=MaxAge ; // Private backing field @@ -49,7 +50,8 @@ public class Session : Relation AccessToSalidomo = user.AccessibleInstallations(product: (int)ProductType.Salidomo).ToList().Count > 0; AccessToSodistoreMax = user.AccessibleInstallations(product: (int)ProductType.SodiStoreMax).ToList().Count > 0; AccessToSodioHome = user.AccessibleInstallations(product: (int)ProductType.SodioHome).ToList().Count > 0; - + AccessToSodistoreGrid = user.AccessibleInstallations(product: (int)ProductType.SodistoreGrid).ToList().Count > 0; + Console.WriteLine("salimax" +user.AccessibleInstallations(product: (int)ProductType.Salimax).ToList().Count); Console.WriteLine("AccessToSodistoreMax" +user.AccessibleInstallations(product: (int)ProductType.SodiStoreMax).ToList().Count); Console.WriteLine("sodio" + user.AccessibleInstallations(product: (int)ProductType.SodioHome).ToList().Count); diff --git a/csharp/App/Backend/Websockets/RabbitMQManager.cs b/csharp/App/Backend/Websockets/RabbitMQManager.cs index 417a04e86..f3d810920 100644 --- a/csharp/App/Backend/Websockets/RabbitMQManager.cs +++ b/csharp/App/Backend/Websockets/RabbitMQManager.cs @@ -100,6 +100,11 @@ public static class RabbitMqManager monitorLink = $"https://monitor.inesco.energy/sodistore_installations/list/installation/{installation.S3BucketId}/batteryview"; } + else if (installation.Product == (int)ProductType.SodistoreGrid) + { + monitorLink = + $"https://monitor.inesco.energy/sodistoregrid_installations/list/installation/{installation.S3BucketId}/batteryview"; + } else { monitorLink = diff --git a/csharp/App/Backend/Websockets/WebsockerManager.cs b/csharp/App/Backend/Websockets/WebsockerManager.cs index 5d521364a..9a6a7dc40 100644 --- a/csharp/App/Backend/Websockets/WebsockerManager.cs +++ b/csharp/App/Backend/Websockets/WebsockerManager.cs @@ -30,7 +30,8 @@ public static class WebsocketManager if ((installationConnection.Value.Product == (int)ProductType.Salimax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) || (installationConnection.Value.Product == (int)ProductType.Salidomo && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(60)) || (installationConnection.Value.Product == (int)ProductType.SodioHome && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(4)) || - (installationConnection.Value.Product == (int)ProductType.SodiStoreMax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) + (installationConnection.Value.Product == (int)ProductType.SodiStoreMax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) || + (installationConnection.Value.Product == (int)ProductType.SodistoreGrid && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)) ) { Console.WriteLine("Installation ID is " + installationConnection.Key); diff --git a/typescript/frontend-marios2/src/App.tsx b/typescript/frontend-marios2/src/App.tsx index b03530cb7..7ba5ece03 100644 --- a/typescript/frontend-marios2/src/App.tsx +++ b/typescript/frontend-marios2/src/App.tsx @@ -35,7 +35,8 @@ function App() { setAccessToSalimax, setAccessToSalidomo, setAccessToSodiohome, - setAccessToSodistore + setAccessToSodistore, + setAccessToSodistoreGrid } = useContext(ProductIdContext); const [language, setLanguage] = useState( @@ -102,12 +103,15 @@ function App() { setAccessToSalidomo(response.data.accessToSalidomo); setAccessToSodiohome(response.data.accessToSodioHome); setAccessToSodistore(response.data.accessToSodistoreMax); + setAccessToSodistoreGrid(response.data.accessToSodistoreGrid); if (response.data.accessToSalimax) { navigate(routes.installations); } else if (response.data.accessToSalidomo) { navigate(routes.salidomo_installations); } else if (response.data.accessToSodistoreMax) { navigate(routes.sodistore_installations); + } else if (response.data.accessToSodistoreGrid) { + navigate(routes.sodistoregrid_installations); } else { navigate(routes.sodiohome_installations); } @@ -215,6 +219,15 @@ function App() { } /> + + + + } + /> + } /> Max Cell Voltage )} - {product === 3 && ( + {(product === 3 || product === 4) && ( Voltage Difference )} @@ -469,7 +469,7 @@ function BatteryView(props: BatteryViewProps) { )} - {product === 3 && ( + {(product === 3 || product === 4) && ( <> {(() => { const cellVoltagesString = @@ -524,7 +524,7 @@ function BatteryView(props: BatteryViewProps) { })()} )} - {product === 3 && ( + {(product === 3 || product === 4) && ( <> {(() => { const cellVoltagesString = diff --git a/typescript/frontend-marios2/src/content/dashboards/Information/Information.tsx b/typescript/frontend-marios2/src/content/dashboards/Information/Information.tsx index a0fb5f8f1..acfe3220a 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Information/Information.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Information/Information.tsx @@ -328,9 +328,12 @@ function Information(props: InformationProps) { label="S3 Bucket Name" name="s3bucketname" value={ - product === 0 || product == 3 + formValues.product === 0 || formValues.product == 3 ? formValues.s3BucketId + '-3e5b3069-214a-43ee-8d85-57d72000c19d' + : formValues.product == 4 + ? formValues.s3BucketId + + '-5109c126-e141-43ab-8658-f3c44c838ae8' : formValues.s3BucketId + '-e7b9a240-3c5d-4d2e-a019-6d8b1f7b73fa' } diff --git a/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx b/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx index 6092a0670..41aff6831 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx @@ -57,9 +57,13 @@ function Installation(props: singleInstallationProps) { s3BucketId: props.current_installation.s3BucketId }; + // TODO: SodistoreGrid — uses its own bucket salt + const s3BucketSalt = + props.current_installation.product === 4 + ? '5109c126-e141-43ab-8658-f3c44c838ae8' + : '3e5b3069-214a-43ee-8d85-57d72000c19d'; const s3Bucket = - props.current_installation.s3BucketId.toString() + - '-3e5b3069-214a-43ee-8d85-57d72000c19d'; + props.current_installation.s3BucketId.toString() + '-' + s3BucketSalt; const s3Credentials = { s3Bucket, ...S3data }; @@ -427,12 +431,15 @@ function Installation(props: singleInstallationProps) { } > - - } - > + {/* TODO: SodistoreGrid — PV View excluded, add back when data path is ready */} + {props.current_installation.product !== 4 && ( + + } + > + )} + props.current_installation.product === 4 ? ( + // TODO: SodistoreGrid — implement actual topology layout + + + Live view coming soon + + + ) : ( + + ) } /> @@ -470,10 +494,27 @@ function Installation(props: singleInstallationProps) { + props.current_installation.product === 4 ? ( + // TODO: SodistoreGrid — implement actual configuration + + + Configuration not yet available + + + ) : ( + + ) } /> )} diff --git a/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx b/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx index 41f138f2a..7ffc7d20f 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx @@ -39,11 +39,18 @@ function InstallationTabs(props: InstallationTabsProps) { const { salimax_or_sodistore_Installations, + sodistoreGridInstallations, fetchAllInstallations, socket, openSocket, closeSocket } = useContext(InstallationsContext); + + // Use the correct installations array based on product + const installations = + props.product === 4 + ? sodistoreGridInstallations + : salimax_or_sodistore_Installations; const { product, setProduct } = useContext(ProductIdContext); useEffect(() => { @@ -93,7 +100,10 @@ function InstallationTabs(props: InstallationTabsProps) { return ret_path; }; - const singleInstallationTabs = + // TODO: SodistoreGrid — PV View excluded for product 4, add back when data path is ready + const hidePvView = props.product === 4; + + const singleInstallationTabs = ( currentUser.userType == UserType.admin ? [ { @@ -204,7 +214,8 @@ function InstallationTabs(props: InstallationTabsProps) { ) } - ]; + ] + ).filter((tab) => !(hidePvView && tab.value === 'pvview')); const tabs = currentTab != 'list' && @@ -372,7 +383,12 @@ function InstallationTabs(props: InstallationTabsProps) { } ]; - return salimax_or_sodistore_Installations.length > 1 ? ( + // Filter out PV View for SodistoreGrid + const filteredTabs = hidePvView + ? tabs.filter((tab) => tab.value !== 'pvview') + : tabs; + + return installations.length > 1 ? ( <> @@ -384,7 +400,7 @@ function InstallationTabs(props: InstallationTabsProps) { textColor="primary" indicatorColor="primary" > - {tabs.map((tab) => ( + {filteredTabs.map((tab) => ( @@ -428,6 +444,10 @@ function InstallationTabs(props: InstallationTabsProps) { element={ props.product === 0 ? ( + ) : props.product === 4 ? ( + ) : (