Update SodistoreMax code.

Fixed the product to value 3 when sending heartbits.
Deleted prints during aggregation
Updated backend code to support SodistoreMax
This commit is contained in:
Noe 2025-04-29 15:08:06 +02:00
parent 31c06e2815
commit cf9c96377f
6 changed files with 77 additions and 114 deletions

View File

@ -193,7 +193,8 @@ public class Controller : ControllerBase
while (startTimestamp <= endTimestamp) while (startTimestamp <= endTimestamp)
{ {
string bucketPath = installation.Product==(int)ProductType.Salimax? "s3://"+installation.S3BucketId + "-3e5b3069-214a-43ee-8d85-57d72000c19d/"+startTimestamp : string bucketPath = installation.Product==(int)ProductType.Salimax || installation.Product==(int)ProductType.SodiStoreMax?
"s3://"+installation.S3BucketId + "-3e5b3069-214a-43ee-8d85-57d72000c19d/"+startTimestamp :
"s3://"+installation.S3BucketId + "-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/"+startTimestamp; "s3://"+installation.S3BucketId + "-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e/"+startTimestamp;
Console.WriteLine("Fetching data for "+startTimestamp); Console.WriteLine("Fetching data for "+startTimestamp);
@ -442,6 +443,20 @@ public class Controller : ControllerBase
} }
[HttpGet(nameof(GetAllInstallationsFromProduct))]
public ActionResult<IEnumerable<Installation>> GetAllInstallationsFromProduct(int product,Token authToken)
{
var user = Db.GetSession(authToken)?.User;
if (user is null)
return Unauthorized();
return user
.AccessibleInstallations(product)
.Select(i => i.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(user).HideWriteKeyIfUserIsNotAdmin(user.UserType))
.ToList();
}
[HttpGet(nameof(GetAllInstallations))] [HttpGet(nameof(GetAllInstallations))]
public ActionResult<IEnumerable<Installation>> GetAllInstallations(Token authToken) public ActionResult<IEnumerable<Installation>> GetAllInstallations(Token authToken)
{ {
@ -451,9 +466,8 @@ public class Controller : ControllerBase
return Unauthorized(); return Unauthorized();
return user return user
.AccessibleInstallations(product:(int)ProductType.Salimax) .AccessibleInstallations(product:(int)ProductType.Salimax)
.Select(i => i.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(user).HideWriteKeyIfUserIsNotAdmin(user.UserType)) .ToList();
.ToList();
} }
[HttpGet(nameof(GetAllSalidomoInstallations))] [HttpGet(nameof(GetAllSalidomoInstallations))]

View File

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

View File

@ -29,6 +29,7 @@ public static class Program
RabbitMqManager.StartRabbitMqConsumer().SupressAwaitWarning(); RabbitMqManager.StartRabbitMqConsumer().SupressAwaitWarning();
WebsocketManager.MonitorSalimaxInstallationTable().SupressAwaitWarning(); WebsocketManager.MonitorSalimaxInstallationTable().SupressAwaitWarning();
WebsocketManager.MonitorSalidomoInstallationTable().SupressAwaitWarning(); WebsocketManager.MonitorSalidomoInstallationTable().SupressAwaitWarning();
WebsocketManager.MonitorSodistoreInstallationTable().SupressAwaitWarning();
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddProblemDetails(setup => builder.Services.AddProblemDetails(setup =>

View File

@ -79,6 +79,39 @@ public static class WebsocketManager
} }
} }
//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" //Inform all the connected websockets regarding installation "installationId"
public static void InformWebsocketsForInstallation(Int64 installationId) public static void InformWebsocketsForInstallation(Int64 installationId)
{ {

View File

@ -70,7 +70,7 @@ public static class Aggregator
dailyAggregatedData.Save("DailyData"); dailyAggregatedData.Save("DailyData");
if (await dailyAggregatedData.PushToS3()) if (await dailyAggregatedData.PushToS3())
{ {
//DeleteHourlyData("HourlyData",currentTime.ToUnixTime()); DeleteHourlyData("HourlyData",currentTime.ToUnixTime());
//AggregatedData.DeleteDailyData("DailyData"); //AggregatedData.DeleteDailyData("DailyData");
} }
@ -86,13 +86,13 @@ public static class Aggregator
private static void DeleteHourlyData(String myDirectory, Int64 beforeTimestamp) private static void DeleteHourlyData(String myDirectory, Int64 beforeTimestamp)
{ {
var jsonFiles = Directory.GetFiles(myDirectory, "*.json"); var jsonFiles = Directory.GetFiles(myDirectory, "*.json");
Console.WriteLine("Delete data before"+beforeTimestamp); //Console.WriteLine("Delete data before"+beforeTimestamp);
foreach (var jsonFile in jsonFiles) foreach (var jsonFile in jsonFiles)
{ {
if (IsFileWithinTimeRange(jsonFile, 0, beforeTimestamp)) if (IsFileWithinTimeRange(jsonFile, 0, beforeTimestamp))
{ {
File.Delete(jsonFile); File.Delete(jsonFile);
Console.WriteLine($"Deleted hourly data file: {jsonFile}"); //Console.WriteLine($"Deleted hourly data file: {jsonFile}");
} }
} }
} }
@ -103,15 +103,11 @@ public static class Aggregator
var jsonFiles = Directory.GetFiles(myDirectory, "*.json"); var jsonFiles = Directory.GetFiles(myDirectory, "*.json");
var batterySoc = new List<Double>(); var batterySoc = new List<Double>();
var pvPowerSum = new List<Double>(); var pvPowerSum = new List<Double>();
var heatingPower = new List<Double>();
var gridPowerImport = new List<Double>(); var gridPowerImport = new List<Double>();
var gridPowerExport = new List<Double>(); var gridPowerExport = new List<Double>();
var batteryDischargePower = new List<Double>(); var batteryDischargePower = new List<Double>();
var batteryChargePower = new List<Double>(); var batteryChargePower = new List<Double>();
Console.WriteLine("File timestamp should start after "+ afterTimestamp);
foreach (var jsonFile in jsonFiles) foreach (var jsonFile in jsonFiles)
{ {
if (jsonFile == "JsonLogDirectory/log.json") if (jsonFile == "JsonLogDirectory/log.json")
@ -136,7 +132,6 @@ public static class Aggregator
var jsonObject = JObject.Parse(jsonData); var jsonObject = JObject.Parse(jsonData);
//Console.WriteLine(jsonObject);
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Soc"] != null) if (jsonObject["Battery"] != null && jsonObject["Battery"]["Soc"] != null)
{ {
batterySoc.Add((double)jsonObject["Battery"]["Soc"]); batterySoc.Add((double)jsonObject["Battery"]["Soc"]);
@ -155,12 +150,10 @@ public static class Aggregator
} }
if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerExportT3"] != null) if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerExportT3"] != null)
{ {
Console.WriteLine("power export is "+jsonObject["GridMeter"]["ActivePowerExportT3"]);
gridPowerExport.Add((double)jsonObject["GridMeter"]["ActivePowerExportT3"]); gridPowerExport.Add((double)jsonObject["GridMeter"]["ActivePowerExportT3"]);
} }
if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerImportT3"] != null) if (jsonObject["GridMeter"] != null && jsonObject["GridMeter"]["ActivePowerImportT3"] != null)
{ {
Console.WriteLine("power import is "+jsonObject["GridMeter"]["ActivePowerImportT3"]);
gridPowerImport.Add((double)jsonObject["GridMeter"]["ActivePowerImportT3"]); gridPowerImport.Add((double)jsonObject["GridMeter"]["ActivePowerImportT3"]);
} }
} }
@ -235,10 +228,6 @@ public static class Aggregator
var batteryChargePower = new List<Double>(); var batteryChargePower = new List<Double>();
var heatingPowerAvg = new List<Double>(); var heatingPowerAvg = new List<Double>();
Console.WriteLine("File timestamp should start after "+ afterTimestamp);
foreach (var jsonFile in jsonFiles) foreach (var jsonFile in jsonFiles)
{ {
if (jsonFile == "JsonLogDirectory/log.json") if (jsonFile == "JsonLogDirectory/log.json")
@ -252,7 +241,6 @@ public static class Aggregator
try try
{ {
var jsonData = File.ReadAllText(jsonFile); var jsonData = File.ReadAllText(jsonFile);
//Console.WriteLine("Parse file "+jsonFile);
// Parse JSON into a Dictionary // Parse JSON into a Dictionary
var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, Double>>(jsonData); var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, Double>>(jsonData);
@ -287,13 +275,6 @@ public static class Aggregator
gridPowerImport.Add(value); gridPowerImport.Add(value);
break; break;
case "HeatingPower":
heatingPowerAvg.Add(value);
break;
default:
// Ignore unknown variables
break;
} }
} }
@ -302,70 +283,6 @@ public static class Aggregator
{ {
Console.WriteLine($"Failed to parse JSON file {jsonFile}: {e.Message}"); Console.WriteLine($"Failed to parse JSON file {jsonFile}: {e.Message}");
} }
// using var reader = new StreamReader(csvFile);
//
// while (!reader.EndOfStream)
// {
//
// var line = reader.ReadLine();
// var lines = line?.Split(';');
//
// // Assuming there are always three columns (variable name and its value)
// if (lines is { Length: 3 })
// {
// var variableName = lines[0].Trim();
//
// if (TryParse(lines[1].Trim(), out var value))
// {
// switch (variableName)
// {
// case "/MinSoc" or "/MaxSoc":
// batterySoc.Add(value);
// break;
//
// case "/PvPower":
// pvPower.Add(value);
// break;
//
// case "/DischargingBatteryPower" :
// batteryDischargePower.Add(value);
// break;
//
// case "/ChargingBatteryPower" :
// batteryChargePower.Add(value);
// break;
//
// case "/GridExportPower":
// gridPowerExport.Add(value);
// break;
//
// case "/GridImportPower":
// gridPowerImport.Add(value);
// break;
//
// case "/HeatingPower":
// heatingPowerAvg.Add(value);
// break;
// // Add more cases as needed
// default:
// // Code to execute when variableName doesn't match any condition
// break;
// }
//
// }
// else
// {
// //Handle cases where variableValue is not a valid number
// // Console.WriteLine(
// // $"Invalid numeric value for variable {variableName}:{lines[1].Trim()}");
// }
// }
// else
// {
// // Handle invalid column format
// //Console.WriteLine("Invalid format in column");
// }
//}
} }
} }

View File

@ -278,9 +278,6 @@ internal static class Program
var s3Bucket = Config.Load().S3?.Bucket; var s3Bucket = Config.Load().S3?.Bucket;
var subscribedNow = false; var subscribedNow = false;
//Every 15 iterations(30 seconds), the installation sends a heartbit message to the queue
//_heartBitInterval++;
//When the controller boots, it tries to subscribe to the queue //When the controller boots, it tries to subscribe to the queue
if (_subscribeToQueueForTheFirstTime == false) if (_subscribeToQueueForTheFirstTime == false)
{ {
@ -297,16 +294,6 @@ internal static class Program
if (s3Bucket != null) if (s3Bucket != null)
RabbitMqManager.InformMiddleware(currentSalimaxState); RabbitMqManager.InformMiddleware(currentSalimaxState);
} }
// else if (_subscribedToQueue && _heartBitInterval >= 30)
// {
// //Send a heartbit to the backend
// Console.WriteLine("----------------------------------------Sending Heartbit----------------------------------------");
// _heartBitInterval = 0;
// currentSalimaxState.Type = MessageType.Heartbit;
//
// if (s3Bucket != null)
// RabbitMqManager.InformMiddleware(currentSalimaxState);
// }
//If there is an available message from the RabbitMQ Broker, apply the configuration file //If there is an available message from the RabbitMQ Broker, apply the configuration file
Configuration? config = SetConfigurationFile(); Configuration? config = SetConfigurationFile();
@ -498,7 +485,7 @@ internal static class Program
var returnedStatus = new StatusMessage var returnedStatus = new StatusMessage
{ {
InstallationId = installationId, InstallationId = installationId,
Product = 0, Product = 3,
Status = _salimaxAlarmState, Status = _salimaxAlarmState,
Type = MessageType.AlarmOrWarning, Type = MessageType.AlarmOrWarning,
Alarms = alarmList, Alarms = alarmList,
@ -845,6 +832,16 @@ internal static class Program
} }
else else
{ {
// var values = value.Split(','); //in case it is a list
// Console.WriteLine("len is ",values.Length);
// if (values.Length > 4)
// {
// foreach (var val in values)
// {
// Console.WriteLine("value from list is ", val);
// }
// }
currentDict[key] = value; // Store as string if not a number currentDict[key] = value; // Store as string if not a number
} }
} }
@ -944,7 +941,7 @@ internal static class Program
var returnedStatus = new StatusMessage var returnedStatus = new StatusMessage
{ {
InstallationId = installationId, InstallationId = installationId,
Product = 0, // Salimax is always 0 Product = 3, // Salimax is always 0
Status = _salimaxAlarmState, Status = _salimaxAlarmState,
Type = MessageType.Heartbit, Type = MessageType.Heartbit,
Timestamp = nameOfJsonFile Timestamp = nameOfJsonFile