Update backend to support SodioHome installations, update backend controller to support new user access management features

This commit is contained in:
Noe 2025-09-01 13:05:39 +02:00
parent 0d8978c6b0
commit 076dcda4a2
12 changed files with 81 additions and 240 deletions

View File

@ -345,6 +345,18 @@ public class Controller : ControllerBase
.ToList();
}
[HttpGet(nameof(GetInstallationsTheUserHasAccess))]
public ActionResult<IEnumerable<Object>> GetInstallationsTheUserHasAccess(Int64 userId, Token authToken)
{
var user = Db.GetUserById(userId);
if (user == null)
return Unauthorized();
return user.AccessibleInstallations().ToList();
}
[HttpGet(nameof(GetUsersWithInheritedAccessToInstallation))]
public ActionResult<IEnumerable<Object>> GetUsersWithInheritedAccessToInstallation(Int64 id, Token authToken)
{
@ -927,6 +939,8 @@ public class Controller : ControllerBase
{
var session = Db.GetSession(authToken);
Console.WriteLine("CONFIG IS " + config.GetConfigurationString());
// Send configuration changes
var success = await session.SendInstallationConfig(installationId, config);
@ -940,6 +954,7 @@ public class Controller : ControllerBase
Timestamp = DateTime.Now,
Description = config.GetConfigurationString()
};
Console.WriteLine(action.Description);
var actionSuccess = await session.InsertUserAction(action);
return actionSuccess?Ok():Unauthorized();
@ -1020,7 +1035,7 @@ public class Controller : ControllerBase
Db.DeleteUserPassword(user);
return Redirect($"https://monitor.innov.energy/?username={user.Email}&reset=true"); // TODO: move to settings file
return Redirect($"https://monitor.inesco.energy/?username={user.Email}&reset=true"); // TODO: move to settings file
}
}

View File

@ -413,6 +413,8 @@ public static class ExoCmd
byte[] data = Encoding.UTF8.GetBytes(JsonSerializer.Serialize<Configuration>(config));
udpClient.Send(data, data.Length, installation.VpnIp, port);
Console.WriteLine(config.GetConfigurationString());
//Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}: {config}");
Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}"+" GridSetPoint is "+config.GridSetPoint +" and MinimumSoC is "+config.MinimumSoC);
@ -435,15 +437,6 @@ public static class ExoCmd
}
}
}
return false;
//var s3Region = new S3Region($"https://{installation.S3Region}.{installation.S3Provider}", S3Credentials!);
//var url = s3Region.Bucket(installation.BucketName()).Path("config.json");
//return await url.PutObject(config);
}
}

View File

@ -7,12 +7,9 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods;
public static class InstallationMethods
{
private static readonly String BucketNameSalt =
// Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == ""
// ? "stage" :"3e5b3069-214a-43ee-8d85-57d72000c19d";
"3e5b3069-214a-43ee-8d85-57d72000c19d";
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";
public static String BucketName(this Installation installation)
{
@ -21,6 +18,11 @@ public static class InstallationMethods
return $"{installation.S3BucketId}-{BucketNameSalt}";
}
if (installation.Product == (int)ProductType.SodioHome)
{
return $"{installation.S3BucketId}-{SodioHomeBucketNameSalt}";
}
return $"{installation.S3BucketId}-{SalidomoBucketNameSalt}";
}

View File

@ -223,7 +223,7 @@ public static class SessionMethods
}
if (installation.Product == (int)ProductType.SodiStoreMax)
if (installation.Product == (int)ProductType.SodiStoreMax || installation.Product == (int)ProductType.SodioHome)
{
return user is not null
&& user.UserType != 0
@ -244,15 +244,15 @@ public static class SessionMethods
&& await installation.CreateBucket()
&& await installation.RenewS3Credentials();
}
if (installation.Product == (int)ProductType.SodioHome)
{
return user is not null
&& user.UserType != 0
&& user.HasAccessToParentOf(installation)
&& Db.Create(installation);
}
//
// if (installation.Product == (int)ProductType.SodioHome)
// {
// return user is not null
// && user.UserType != 0
// && user.HasAccessToParentOf(installation)
// && Db.Create(installation);
// }
//
return false;

View File

@ -229,6 +229,9 @@ public static class UserMethods
public static Task SendEmail(this User user, String subject, String body)
{
Console.WriteLine(user.Name);
Console.WriteLine(subject);
return Mailer.Send(user.Name, user.Email, subject, body);
}

View File

@ -284,6 +284,7 @@ public static partial class Db
}
catch
{
Console.WriteLine("return false");
return false;
}
}

View File

@ -1,8 +1,8 @@
{
"SmtpServerUrl" : "mail.agenturserver.de",
"SmtpUsername" : "p518526p69",
"SmtpPassword" : "i;b*xqm4iB5uhl",
"SmtpServerUrl" : "smtp.gmail.com",
"SmtpUsername" : "angelis@inesco.energy",
"SmtpPassword" : "huvu pkqd kakz hqtm ",
"SmtpPort" : 587,
"SenderName" : "InnovEnergy",
"SenderAddress" : "noreply@innov.energy"
"SenderName" : "Inesco Energy",
"SenderAddress" : "noreply@inesco.energy"
}

View File

@ -28,9 +28,8 @@ public static class Program
RabbitMqManager.InitializeEnvironment();
RabbitMqManager.StartRabbitMqConsumer().SupressAwaitWarning();
WebsocketManager.MonitorSalimaxInstallationTable().SupressAwaitWarning();
WebsocketManager.MonitorSalidomoInstallationTable().SupressAwaitWarning();
WebsocketManager.MonitorSodistoreInstallationTable().SupressAwaitWarning();
WebsocketManager.MonitorInstallationTable().SupressAwaitWarning();
// Task.Run(() => DeleteOldDataFromS3.DeleteOldData());

View File

@ -49,6 +49,10 @@ 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;
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);
}
private static String CreateToken()

View File

@ -13,105 +13,45 @@ public static class WebsocketManager
{
public static Dictionary<Int64, InstallationInfo> InstallationConnections = new Dictionary<Int64, InstallationInfo>();
//Every 1 minute, check the timestamp of the latest received message for every installation.
//If the difference between the two timestamps is more than two minutes, we consider this Salimax installation unavailable.
public static async Task MonitorSalimaxInstallationTable()
public static async Task MonitorInstallationTable()
{
while (true){
lock (InstallationConnections){
// Console.WriteLine("MONITOR SALIMAX INSTALLATIONS\n");
foreach (var installationConnection in InstallationConnections){
while (true)
{
lock (InstallationConnections)
{
Console.WriteLine("Monitoring installation table...");
foreach (var installationConnection in InstallationConnections)
{
Console.WriteLine("installationConnection ID is " + installationConnection.Key + "latest timestamp is" +installationConnection.Value.Timestamp + "product is "+ installationConnection.Value.Product
+ "and time diff is "+ (DateTime.Now - installationConnection.Value.Timestamp));
if (installationConnection.Value.Product==(int)ProductType.Salimax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2)){
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(2)) ||
(installationConnection.Value.Product == (int)ProductType.SodiStoreMax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2))
)
{
// Console.WriteLine("Installation ID is "+installationConnection.Key);
// Console.WriteLine("installationConnection.Value.Timestamp is "+installationConnection.Value.Timestamp);
Console.WriteLine("Installation ID is " + installationConnection.Key);
Console.WriteLine("installationConnection.Value.Timestamp is " + installationConnection.Value.Timestamp);
// Console.WriteLine("diff is "+(DateTime.Now-installationConnection.Value.Timestamp));
installationConnection.Value.Status = (int)StatusType.Offline;
Installation installation = Db.Installations.FirstOrDefault(f => f.Product == (int)ProductType.Salimax && f.Id == installationConnection.Key);
Installation installation = Db.Installations.FirstOrDefault(f => f.Product == installationConnection.Value.Product && f.Id == installationConnection.Key);
installation.Status = (int)StatusType.Offline;
installation.Apply(Db.Update);
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
if (installationConnection.Value.Connections.Count > 0)
{
InformWebsocketsForInstallation(installationConnection.Key);
}
}
}
// Console.WriteLine("FINISHED MONITORING SALIMAX INSTALLATIONS\n");
}
await Task.Delay(TimeSpan.FromMinutes(1));
}
}
//Every 1 minute, check the timestamp of the latest received message for every installation.
//If the difference between the two timestamps is more than 1 hour, we consider this Salidomo installation unavailable.
public static async Task MonitorSalidomoInstallationTable()
{
while (true){
//Console.WriteLine("TRY TO LOCK FOR MONITOR SALIDOMO INSTALLATIONS\n");
lock (InstallationConnections){
//Console.WriteLine("MONITOR SALIDOMO INSTALLATIONS\n");
foreach (var installationConnection in InstallationConnections)
{
//Console.WriteLine("Installation ID is "+installationConnection.Key);
// if (installationConnection.Value.Product == (int)ProductType.Salidomo && (DateTime.Now - installationConnection.Value.Timestamp) < TimeSpan.FromMinutes(60)){
// Console.WriteLine("Installation ID is "+installationConnection.Key + " diff is "+(DateTime.Now-installationConnection.Value.Timestamp));
// }
if (installationConnection.Value.Product==(int)ProductType.Salidomo && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(60))
{
//Console.WriteLine("installationConnection.Value.Timestamp is "+installationConnection.Value.Timestamp);
//Console.WriteLine("timestamp now is is "+(DateTime.Now));
Installation installation = Db.Installations.FirstOrDefault(f => f.Product == (int)ProductType.Salidomo && f.Id == installationConnection.Key);
//Console.WriteLine("Installation ID is "+installation.Name + " diff is "+(DateTime.Now-installationConnection.Value.Timestamp));
installation.Status = (int)StatusType.Offline;
installation.Apply(Db.Update);
installationConnection.Value.Status = (int)StatusType.Offline;
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
//else{Console.WriteLine("NONE IS CONNECTED TO THAT INSTALLATION-------------------------------------------------------------");}
}
}
//Console.WriteLine("FINISHED WITH UPDATING\n");
}
await Task.Delay(TimeSpan.FromMinutes(1));
}
}
//Every 1 minute, check the timestamp of the latest received message for every installation.
//If the difference between the two timestamps is more than two minutes, we consider this Sodistore installation unavailable.
public static async Task MonitorSodistoreInstallationTable()
{
while (true){
//Console.WriteLine("TRY TO LOCK FOR MONITOR SODISTORE INSTALLATIONS\n");
lock (InstallationConnections){
//Console.WriteLine("MONITOR SODISTORE INSTALLATIONS\n");
foreach (var installationConnection in InstallationConnections)
{
if (installationConnection.Value.Product==(int)ProductType.SodiStoreMax && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(2))
{
//Console.WriteLine("installationConnection.Value.Timestamp is "+installationConnection.Value.Timestamp);
//Console.WriteLine("timestamp now is is "+(DateTime.Now));
Installation installation = Db.Installations.FirstOrDefault(f => f.Product == (int)ProductType.SodiStoreMax && f.Id == installationConnection.Key);
//Console.WriteLine("Installation ID is "+installation.Name + " diff is "+(DateTime.Now-installationConnection.Value.Timestamp));
installation.Status = (int)StatusType.Offline;
installation.Apply(Db.Update);
installationConnection.Value.Status = (int)StatusType.Offline;
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
//else{Console.WriteLine("NONE IS CONNECTED TO THAT INSTALLATION-------------------------------------------------------------");}
}
}
//Console.WriteLine("FINISHED WITH UPDATING\n");
}
await Task.Delay(TimeSpan.FromMinutes(1));
}
}
//Inform all the connected websockets regarding installation "installationId"
public static void InformWebsocketsForInstallation(Int64 installationId)
{
@ -140,6 +80,7 @@ public static class WebsocketManager
}
}
public static async Task HandleWebSocketConnection(WebSocket currentWebSocket)
{
var buffer = new byte[4096];
@ -155,6 +96,7 @@ public static class WebsocketManager
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
var installationIds = JsonSerializer.Deserialize<int[]>(message);
Console.WriteLine("Received Websocket message: " + message);
//This is a ping message to keep the connection alive, reply with a pong
if (installationIds[0] == -1)

View File

@ -5191,7 +5191,7 @@
"order": 5,
"width": 0,
"height": 0,
"format": "<a href=\"https://monitor.innov.energy/salidomo_installations/list/\" target=\"_blank\" class=\"button\"> Battery Monitor </a>\n",
"format": "<a href=\"https://monitor.inesco.energy/salidomo_installations/list/\" target=\"_blank\" class=\"button\"> Battery Monitor </a>\n",
"storeOutMessages": true,
"fwdInMessages": true,
"resendOnRefresh": true,

View File

@ -55,112 +55,6 @@ const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
[]
);
useEffect(() => {
// if (sortedInstallations) {
// const tokenString = localStorage.getItem('token');
// const token = tokenString !== null ? tokenString : '';
// const urlWithToken = `wss://monitor.innov.energy/api/CreateWebSocket?authToken=${token}`;
//
// const socket = new WebSocket(urlWithToken);
// // Connection opened
// socket.addEventListener('open', (event) => {
// socket.send(
// JSON.stringify(
// sortedInstallations.map((installation) => installation.id)
// )
// );
// });
//
// // Periodically send ping messages to keep the connection alive
// const pingInterval = setInterval(() => {
// if (socket.readyState === WebSocket.OPEN) {
// socket.send(JSON.stringify([-1]));
// }
// }, 10000); // Send a ping every 10 seconds
//
// let messageBuffer = [];
// let isProcessing = false;
//
// socket.addEventListener('message', (event) => {
// const message = JSON.parse(event.data); // Parse the JSON data
//
// if (Array.isArray(message)) {
// message.forEach((item) => {
// console.log('status is ' + item.status);
// // Update status and testingMode for each installation received
// // updateInstallationStatus(item.id, item.status, item.testingMode);
// });
// }
// // } else if (message.id !== -1) {
// // // Handle individual messages for installations
// // updateInstallationStatus(
// // message.id,
// // message.status,
// // message.testingMode
// // );
// // }
//
// // if (Array.isArray(message)) {
// // // Existing code for handling arrays, if necessary
// // setInstallationMode((prevMode) => {
// // const newMode = new Map(prevMode);
// // message.forEach((item) => {
// // newMode.set(item.id, item.testingMode);
// // });
// // return newMode;
// // });
// //
// // setInstallationStatus((prevStatus) => {
// // const newStatus = new Map(prevStatus);
// // message.forEach((item) => {
// // newStatus.set(item.id, item.status);
// // });
// // return newStatus;
// // });
// // } else if (message.id != -1) {
// // // Accumulate messages in the buffer
// // messageBuffer.push(message);
// //
// // // Process the buffer if not already processing
// // if (!isProcessing) {
// // isProcessing = true;
// //
// // // Use setTimeout to process the buffer periodically
// // setTimeout(() => {
// // const newInstallationMode = new Map();
// // const newInstallationStatus = new Map();
// //
// // // Process all accumulated messages
// // messageBuffer.forEach((msg) => {
// // newInstallationMode.set(msg.id, msg.testingMode);
// // newInstallationStatus.set(msg.id, msg.status);
// // });
// //
// // // Update the state with the accumulated messages
// // setInstallationMode(
// // (prevMode) => new Map([...prevMode, ...newInstallationMode])
// // );
// // setInstallationStatus(
// // (prevStatus) =>
// // new Map([...prevStatus, ...newInstallationStatus])
// // );
// //
// // // Clear the buffer after processing
// // messageBuffer = [];
// // isProcessing = false; // Reset processing flag
// // }, 100); // Adjust the delay as needed to control processing frequency
// // }
// // }
// });
//
// setSocket(socket);
// }
}, [sortedInstallations]);
// const openSocket = (installations: I_Installation[]) => {
// setInstallations(installations);
// };
const openSocket = (installations) => {
// setSortedInstallations(installations.sort((a, b) => b.status - a.status)); // Sort installations by status
};
@ -169,18 +63,6 @@ const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
// socket.close();
};
// const getStatus = (installationId: number) => {
// return installationStatus.get(installationId);
// // if (installationStatus.has(installationId)) {
// // installationStatus.get(installationId);
// // } else {
// // return -2;
// // }
// };
// const getTestingMode = (installationId: number) => {
// return installationMode.get(installationId);
// };
return (
<WebSocketContext.Provider