Added SodistoreGrid as an empty templated and built S3 bucket creation pipeline

This commit is contained in:
Yinyin Liu 2026-03-04 10:59:08 +01:00
parent 7df4842980
commit 7aacddd761
23 changed files with 239 additions and 53 deletions

View File

@ -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<IEnumerable<Installation>> 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<IEnumerable<Installation>> 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<IEnumerable<Folder>> 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
};

View File

@ -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

View File

@ -7,7 +7,8 @@ public enum ProductType
Salimax = 0,
Salidomo = 1,
SodioHome =2,
SodiStoreMax=3
SodiStoreMax=3,
SodistoreGrid=4
}
public enum StatusType

View File

@ -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 = $$"""

View File

@ -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}";
}

View File

@ -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);
}

View File

@ -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}");

View File

@ -16,6 +16,7 @@ public class Session : Relation<String, Int64>
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<String, Int64>
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);

View File

@ -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 =

View File

@ -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);

View File

@ -35,7 +35,8 @@ function App() {
setAccessToSalimax,
setAccessToSalidomo,
setAccessToSodiohome,
setAccessToSodistore
setAccessToSodistore,
setAccessToSodistoreGrid
} = useContext(ProductIdContext);
const [language, setLanguage] = useState<string>(
@ -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() {
}
/>
<Route
path={routes.sodistoregrid_installations + '*'}
element={
<AccessContextProvider>
<InstallationTabs product={4} />
</AccessContextProvider>
}
/>
<Route path={routes.users + '*'} element={<Users />} />
<Route
path={'*'}

View File

@ -4,6 +4,7 @@
"salidomo_installations": "/salidomo_installations/",
"sodistore_installations": "/sodistore_installations/",
"sodiohome_installations": "/sodiohome_installations/",
"sodistoregrid_installations": "/sodistoregrid_installations/",
"installation": "installation/",
"login": "/login/",
"forgotPassword": "/forgotPassword/",

View File

@ -40,7 +40,8 @@ function Login() {
setAccessToSalimax,
setAccessToSalidomo,
setAccessToSodiohome,
setAccessToSodistore
setAccessToSodistore,
setAccessToSodistoreGrid
} = useContext(ProductIdContext);
const navigate = useNavigate();
@ -84,6 +85,7 @@ function Login() {
setAccessToSalidomo(response.data.accessToSalidomo);
setAccessToSodiohome(response.data.accessToSodioHome);
setAccessToSodistore(response.data.accessToSodistoreMax);
setAccessToSodistoreGrid(response.data.accessToSodistoreGrid);
if (rememberMe) {
cookies.set('rememberedUsername', username, { path: '/' });
@ -95,6 +97,8 @@ function Login() {
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);
}

View File

@ -245,7 +245,7 @@ function BatteryView(props: BatteryViewProps) {
) : (
<TableCell align="center">Max Cell Voltage</TableCell>
)}
{product === 3 && (
{(product === 3 || product === 4) && (
<TableCell align="center">Voltage Difference</TableCell>
)}
</TableRow>
@ -469,7 +469,7 @@ function BatteryView(props: BatteryViewProps) {
</TableCell>
</>
)}
{product === 3 && (
{(product === 3 || product === 4) && (
<>
{(() => {
const cellVoltagesString =
@ -524,7 +524,7 @@ function BatteryView(props: BatteryViewProps) {
})()}
</>
)}
{product === 3 && (
{(product === 3 || product === 4) && (
<>
{(() => {
const cellVoltagesString =

View File

@ -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'
}

View File

@ -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) {
}
></Route>
<Route
path={routes.pvview + '/*'}
element={
<PvView values={values} connected={connected}></PvView>
}
></Route>
{/* TODO: SodistoreGrid — PV View excluded, add back when data path is ready */}
{props.current_installation.product !== 4 && (
<Route
path={routes.pvview + '/*'}
element={
<PvView values={values} connected={connected}></PvView>
}
></Route>
)}
<Route
path={routes.overview}
@ -447,11 +454,28 @@ function Installation(props: singleInstallationProps) {
<Route
path={routes.live}
element={
<Topology
values={values}
connected={connected}
loading={loading}
></Topology>
props.current_installation.product === 4 ? (
// TODO: SodistoreGrid — implement actual topology layout
<Container
maxWidth="xl"
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '40vh'
}}
>
<Typography variant="body1" color="text.secondary">
Live view coming soon
</Typography>
</Container>
) : (
<Topology
values={values}
connected={connected}
loading={loading}
></Topology>
)
}
/>
@ -470,10 +494,27 @@ function Installation(props: singleInstallationProps) {
<Route
path={routes.configuration}
element={
<Configuration
values={values}
id={props.current_installation.id}
></Configuration>
props.current_installation.product === 4 ? (
// TODO: SodistoreGrid — implement actual configuration
<Container
maxWidth="xl"
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '40vh'
}}
>
<Typography variant="body1" color="text.secondary">
Configuration not yet available
</Typography>
</Container>
) : (
<Configuration
values={values}
id={props.current_installation.id}
></Configuration>
)
}
/>
)}

View File

@ -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) {
<FormattedMessage id="information" defaultMessage="Information" />
)
}
];
]
).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 ? (
<>
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
<TabsContainerWrapper>
@ -384,7 +400,7 @@ function InstallationTabs(props: InstallationTabsProps) {
textColor="primary"
indicatorColor="primary"
>
{tabs.map((tab) => (
{filteredTabs.map((tab) => (
<Tab
key={tab.value}
value={tab.value}
@ -415,7 +431,7 @@ function InstallationTabs(props: InstallationTabsProps) {
<Grid item xs={12}>
<Box p={4}>
<InstallationSearch
installations={salimax_or_sodistore_Installations}
installations={installations}
/>
</Box>
</Grid>
@ -428,6 +444,10 @@ function InstallationTabs(props: InstallationTabsProps) {
element={
props.product === 0 ? (
<Navigate to={routes.installations + routes.list} />
) : props.product === 4 ? (
<Navigate
to={routes.sodistoregrid_installations + routes.list}
/>
) : (
<Navigate
to={routes.sodistore_installations + routes.list}
@ -441,7 +461,7 @@ function InstallationTabs(props: InstallationTabsProps) {
</Container>
<Footer />
</>
) : salimax_or_sodistore_Installations.length === 1 ? (
) : installations.length === 1 ? (
<>
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
<TabsContainerWrapper>
@ -480,7 +500,7 @@ function InstallationTabs(props: InstallationTabsProps) {
<Box p={4}>
<Installation
current_installation={
salimax_or_sodistore_Installations[0]
installations[0]
}
type="installation"
></Installation>

View File

@ -65,10 +65,11 @@ function TreeInformation(props: TreeInformationProps) {
setProduct(e.target.value); // Directly update the product state
};
const ProductTypes = ['Salimax', 'Salidomo', 'SodistoreHome', 'SodistoreMax'];
const ProductTypes = ['Salimax', 'Salidomo', 'SodistoreHome', 'SodistoreMax', 'SodistoreGrid'];
const ProductDisplayNames: Record<string, string> = {
'SodistoreHome': 'Sodistore Home',
'SodistoreMax': 'Sodistore Max'
'SodistoreMax': 'Sodistore Max',
'SodistoreGrid': 'Sodistore Grid'
};
const isMobile = window.innerWidth <= 1490;
@ -327,7 +328,8 @@ function TreeInformation(props: TreeInformationProps) {
)}
{openModalInstallation &&
(product == 'Salimax' ||
product == 'SodistoreMax') && (
product == 'SodistoreMax' ||
product == 'SodistoreGrid') && (
<InstallationForm
cancel={handleFormCancel}
submit={handleInstallationFormSubmit}

View File

@ -80,7 +80,7 @@ function InstallationTree() {
key={installation.id}
path={routes.installation + installation.id + '/*'}
element={
installation.product == 0 || installation.product == 3 ? (
installation.product == 0 || installation.product == 3 || installation.product == 4 ? (
<Installation
key={installation.id}
current_installation={installation}

View File

@ -31,6 +31,9 @@ const InstallationsContextProvider = ({
const [sodiohomeInstallations, setSodiohomeInstallations] = useState<
I_Installation[]
>([]);
const [sodistoreGridInstallations, setSodistoreGridInstallations] = useState<
I_Installation[]
>([]);
const [foldersAndInstallations, setFoldersAndInstallations] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
@ -89,16 +92,31 @@ const InstallationsContextProvider = ({
: installation;
});
const updatedSodistoreGrid = sodistoreGridInstallations.map(
(installation) => {
const update = pendingUpdates.current[installation.id];
return update
? {
...installation,
status: update.status,
testingMode: update.testingMode
}
: installation;
}
);
setSalidomoInstallations(updatedSalidomo);
setSalimax_Or_Sodistore_Installations(updatedSalimax);
setSodiohomeInstallations(updatedSodiohome);
setSodistoreGridInstallations(updatedSodistoreGrid);
// Clear the pending updates after applying
pendingUpdates.current = {};
}, [
salidomoInstallations,
salimax_or_sodistore_Installations,
sodiohomeInstallations
sodiohomeInstallations,
sodistoreGridInstallations
]);
useEffect(() => {
@ -172,6 +190,8 @@ const InstallationsContextProvider = ({
setSalidomoInstallations(res.data);
} else if (product === 0 || product === 3) {
setSalimax_Or_Sodistore_Installations(res.data);
} else if (product === 4) {
setSodistoreGridInstallations(res.data);
}
if (open_socket) {
@ -390,6 +410,7 @@ const InstallationsContextProvider = ({
salimax_or_sodistore_Installations,
salidomoInstallations,
sodiohomeInstallations,
sodistoreGridInstallations,
foldersAndInstallations,
fetchAllInstallations,
fetchAllFoldersAndInstallations,
@ -416,6 +437,7 @@ const InstallationsContextProvider = ({
salimax_or_sodistore_Installations,
salidomoInstallations,
sodiohomeInstallations,
sodistoreGridInstallations,
foldersAndInstallations,
loading,
error,

View File

@ -9,10 +9,12 @@ interface ProductIdContextType {
accessToSalidomo: boolean;
accessToSodiohome: boolean;
accessToSodistore: boolean;
accessToSodistoreGrid: boolean;
setAccessToSalimax: (access: boolean) => void;
setAccessToSalidomo: (access: boolean) => void;
setAccessToSodiohome: (access: boolean) => void;
setAccessToSodistore: (access: boolean) => void;
setAccessToSodistoreGrid: (access: boolean) => void;
}
// Create the context.
@ -43,6 +45,10 @@ export const ProductIdContextProvider = ({
const storedValue = localStorage.getItem('accessToSodistore');
return storedValue === 'true';
});
const [accessToSodistoreGrid, setAccessToSodistoreGrid] = useState(() => {
const storedValue = localStorage.getItem('accessToSodistoreGrid');
return storedValue === 'true';
});
// const [product, setProduct] = useState(location.includes('salidomo') ? 1 : 0);
// const [product, setProduct] = useState<number>(
// productMapping[Object.keys(productMapping).find((key) => location.includes(key)) || ''] || -1
@ -52,6 +58,8 @@ export const ProductIdContextProvider = ({
return 1;
} else if (location.includes('sodiohome')) {
return 2;
} else if (location.includes('sodistoregrid')) {
return 4;
} else {
return 0;
}
@ -80,6 +88,10 @@ export const ProductIdContextProvider = ({
setAccessToSodistore(access);
localStorage.setItem('accessToSodistore', JSON.stringify(access));
};
const changeAccessSodistoreGrid = (access: boolean) => {
setAccessToSodistoreGrid(access);
localStorage.setItem('accessToSodistoreGrid', JSON.stringify(access));
};
return (
<ProductIdContext.Provider
@ -90,10 +102,12 @@ export const ProductIdContextProvider = ({
accessToSalidomo,
accessToSodiohome,
accessToSodistore,
accessToSodistoreGrid,
setAccessToSalimax: changeAccessSalimax,
setAccessToSalidomo: changeAccessSalidomo,
setAccessToSodiohome: changeAccessSodiohome,
setAccessToSodistore: changeAccessSodistore
setAccessToSodistore: changeAccessSodistore,
setAccessToSodistoreGrid: changeAccessSodistoreGrid
}}
>
{children}

View File

@ -89,8 +89,9 @@ export const transformInputToBatteryViewDataJson = async (
const categories = isSodioHome
? ['Soc', 'Power', 'Voltage', 'Current', 'Soh']
: ['Soc', 'Temperature', 'Power', 'Voltage', 'Current'];
// TODO: SodistoreGrid — update data paths when installation data format is finalized
const pathCategories =
product === 3
product === 3 || product === 4
? [
'.BatteryDeligreenDataRecord.Soc',
'.BatteryDeligreenDataRecord.TemperaturesList.EnvironmentTemperature',
@ -167,7 +168,7 @@ export const transformInputToBatteryViewDataJson = async (
);
const adjustedTimestamp =
product == 0 || product == 2 || product == 3
product == 0 || product == 2 || product == 3 || product == 4
? new Date(timestampArray[i] * 1000)
: new Date(timestampArray[i] * 100000);
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
@ -270,7 +271,7 @@ export const transformInputToBatteryViewDataJson = async (
if (battery_nodes.length > old_length) {
battery_nodes.forEach((node) => {
const node_number =
product == 3 ? Number(node) + 1 : Number(node) - 1;
product == 3 || product == 4 ? Number(node) + 1 : Number(node) - 1;
if (!pathsToSave.includes('Node' + node_number)) {
pathsToSave.push('Node' + node_number);
}

View File

@ -168,7 +168,8 @@ function SidebarMenu() {
accessToSalimax,
accessToSodistore,
accessToSalidomo,
accessToSodiohome
accessToSodiohome,
accessToSodistoreGrid
} = useContext(ProductIdContext);
return (
@ -242,6 +243,27 @@ function SidebarMenu() {
</List>
)}
{accessToSodistoreGrid && (
<List component="div">
<ListItem component="div">
<Button
disableRipple
component={RouterLink}
onClick={closeSidebar}
to="/sodistoregrid_installations"
startIcon={<BrightnessLowTwoToneIcon />}
>
<Box sx={{ marginTop: '3px' }}>
<FormattedMessage
id="sodistoregrid"
defaultMessage="Sodistore Grid"
/>
</Box>
</Button>
</ListItem>
</List>
)}
{accessToSodiohome && (
<List component="div">
<ListItem component="div">