Enabled set date button in front end
Use s3cmd in backend to search the corresponding timestamps
This commit is contained in:
parent
b499d01473
commit
cce3a6f9bd
|
@ -1,4 +1,6 @@
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
using InnovEnergy.App.Backend.DataTypes;
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
using InnovEnergy.App.Backend.DataTypes.Methods;
|
using InnovEnergy.App.Backend.DataTypes.Methods;
|
||||||
|
@ -145,8 +147,10 @@ public class Controller : ControllerBase
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet(nameof(GetCsvTimestampsForInstallation))]
|
[HttpGet(nameof(GetCsvTimestampsForInstallation))]
|
||||||
public ActionResult<IEnumerable<CsvTimestamp>> GetCsvTimestampsForInstallation(Int64 id, Int32 start, Int32 end, Token authToken)
|
public ActionResult<IEnumerable<Int64>> GetCsvTimestampsForInstallation(Int64 id, Int32 start, Int32 end, Token authToken)
|
||||||
{
|
{
|
||||||
var user = Db.GetSession(authToken)?.User;
|
var user = Db.GetSession(authToken)?.User;
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -158,21 +162,84 @@ public class Controller : ControllerBase
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
|
|
||||||
var sampleSize = 100;
|
var sampleSize = 100;
|
||||||
var allTimestamps = new List<CsvTimestamp>();
|
var allTimestamps = new List<Int64>();
|
||||||
|
|
||||||
if (start != 0 && end != 0)
|
static string FindCommonPrefix(string str1, string str2)
|
||||||
{
|
{
|
||||||
allTimestamps = Db.CsvTimestamps
|
int minLength = Math.Min(str1.Length, str2.Length);
|
||||||
.Where(csvTimestamp => csvTimestamp.InstallationId == id && csvTimestamp.Timestamp > start && csvTimestamp.Timestamp < end)
|
int i = 0;
|
||||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp).ToList();
|
while (i < minLength && str1[i] == str2[i])
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return str1.Substring(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
string commonPrefix = FindCommonPrefix(start.ToString(), end.ToString());
|
||||||
|
|
||||||
|
string bucketPath = "s3://"+installation.S3BucketId + "-3e5b3069-214a-43ee-8d85-57d72000c19d/"+commonPrefix;
|
||||||
|
string configPath = "/home/ubuntu/.s3cfg";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Set up process start info
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "s3cmd",
|
||||||
|
Arguments = $"--config {configPath} ls {bucketPath}",
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start the process
|
||||||
|
Process process = new Process
|
||||||
|
{
|
||||||
|
StartInfo = startInfo
|
||||||
|
};
|
||||||
|
|
||||||
|
process.Start();
|
||||||
|
|
||||||
|
// Read the output
|
||||||
|
string output = process.StandardOutput.ReadToEnd();
|
||||||
|
string error = process.StandardError.ReadToEnd();
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (process.ExitCode != 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error executing command:");
|
||||||
|
Console.WriteLine(error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
allTimestamps = Db.CsvTimestamps
|
Console.WriteLine("Command output:");
|
||||||
.Where(csvTimestamp => csvTimestamp.InstallationId == id)
|
//Console.WriteLine(output);
|
||||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp).ToList();
|
// Define a regex pattern to match the filenames without .csv extension
|
||||||
|
var pattern = @"/([^/]+)\.csv$";
|
||||||
|
var regex = new Regex(pattern);
|
||||||
|
|
||||||
|
// Process each line of the output
|
||||||
|
foreach (var line in output.Split('\n'))
|
||||||
|
{
|
||||||
|
var match = regex.Match(line);
|
||||||
|
if (match.Success && long.Parse(match.Groups[1].Value)>=start && long.Parse(match.Groups[1].Value)<=end)
|
||||||
|
{
|
||||||
|
allTimestamps.Add(long.Parse(match.Groups[1].Value));
|
||||||
|
//Console.WriteLine(match.Groups[1].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Exception: {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int totalRecords = allTimestamps.Count;
|
int totalRecords = allTimestamps.Count;
|
||||||
if (totalRecords <= sampleSize)
|
if (totalRecords <= sampleSize)
|
||||||
|
@ -186,7 +253,7 @@ public class Controller : ControllerBase
|
||||||
|
|
||||||
|
|
||||||
int interval = totalRecords / sampleSize;
|
int interval = totalRecords / sampleSize;
|
||||||
var sampledTimestamps = new List<CsvTimestamp>();
|
var sampledTimestamps = new List<Int64>();
|
||||||
|
|
||||||
for (int i = 0; i < totalRecords; i += interval)
|
for (int i = 0; i < totalRecords; i += interval)
|
||||||
{
|
{
|
||||||
|
@ -204,11 +271,6 @@ public class Controller : ControllerBase
|
||||||
Console.WriteLine("SampledTimestamps = " + sampledTimestamps.Count);
|
Console.WriteLine("SampledTimestamps = " + sampledTimestamps.Count);
|
||||||
|
|
||||||
return sampledTimestamps;
|
return sampledTimestamps;
|
||||||
|
|
||||||
// return Db.CsvTimestamps
|
|
||||||
// .Where(csvTimestamp => csvTimestamp.InstallationId == id)
|
|
||||||
// .OrderByDescending(csvTimestamp => csvTimestamp.Timestamp)
|
|
||||||
// .ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet(nameof(GetUserById))]
|
[HttpGet(nameof(GetUserById))]
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.DataTypes;
|
|
||||||
|
|
||||||
public class CsvTimestamp{
|
|
||||||
[PrimaryKey, AutoIncrement]
|
|
||||||
public Int64 Id { get; set; }
|
|
||||||
public Int64 InstallationId { get; set; }
|
|
||||||
public Int32 Timestamp { get; set; }
|
|
||||||
|
|
||||||
}
|
|
|
@ -105,7 +105,7 @@ public static class InstallationMethods
|
||||||
|
|
||||||
public static Installation HideWriteKeyIfUserIsNotAdmin(this Installation installation, int userIsAdmin)
|
public static Installation HideWriteKeyIfUserIsNotAdmin(this Installation installation, int userIsAdmin)
|
||||||
{
|
{
|
||||||
if(userIsAdmin!=2)
|
if(userIsAdmin==2)
|
||||||
return installation;
|
return installation;
|
||||||
|
|
||||||
installation.S3WriteKey = "";
|
installation.S3WriteKey = "";
|
||||||
|
|
|
@ -42,11 +42,6 @@ public static partial class Db
|
||||||
return Insert(warning);
|
return Insert(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Boolean Create(CsvTimestamp csvTimestamp)
|
|
||||||
{
|
|
||||||
return Insert(csvTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Boolean Create(Folder folder)
|
public static Boolean Create(Folder folder)
|
||||||
{
|
{
|
||||||
return Insert(folder);
|
return Insert(folder);
|
||||||
|
@ -176,34 +171,4 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddCsvTimestamp(CsvTimestamp newCsvTimestamp,int installationId)
|
|
||||||
{
|
|
||||||
var maxCSvPerInstallation = 60 * 24;
|
|
||||||
//Find the total number of warnings for this installation
|
|
||||||
var totalCsvNames = CsvTimestamps.Count(csvTimestamp => csvTimestamp.InstallationId == installationId);
|
|
||||||
|
|
||||||
//If there are 100 warnings, remove the one with the oldest timestamp
|
|
||||||
if (totalCsvNames == maxCSvPerInstallation)
|
|
||||||
{
|
|
||||||
var oldestCSvTimestamp =
|
|
||||||
CsvTimestamps.Where(csvTimestamp => csvTimestamp.InstallationId == installationId)
|
|
||||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
//Remove the old error
|
|
||||||
Delete(oldestCSvTimestamp);
|
|
||||||
|
|
||||||
//Add the new error
|
|
||||||
Create(newCsvTimestamp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Console.WriteLine("---------------Added the new Csv Timestamp to the database-----------------");
|
|
||||||
Create(newCsvTimestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -37,7 +37,6 @@ public static partial class Db
|
||||||
fileConnection.CreateTable<Error>();
|
fileConnection.CreateTable<Error>();
|
||||||
fileConnection.CreateTable<Warning>();
|
fileConnection.CreateTable<Warning>();
|
||||||
fileConnection.CreateTable<UserAction>();
|
fileConnection.CreateTable<UserAction>();
|
||||||
fileConnection.CreateTable<CsvTimestamp>();
|
|
||||||
|
|
||||||
return fileConnection;
|
return fileConnection;
|
||||||
//return CopyDbToMemory(fileConnection);
|
//return CopyDbToMemory(fileConnection);
|
||||||
|
@ -58,7 +57,6 @@ public static partial class Db
|
||||||
memoryConnection.CreateTable<Error>();
|
memoryConnection.CreateTable<Error>();
|
||||||
memoryConnection.CreateTable<Warning>();
|
memoryConnection.CreateTable<Warning>();
|
||||||
fileConnection.CreateTable<UserAction>();
|
fileConnection.CreateTable<UserAction>();
|
||||||
fileConnection.CreateTable<CsvTimestamp>();
|
|
||||||
|
|
||||||
//Copy all the existing tables from the disk to main memory
|
//Copy all the existing tables from the disk to main memory
|
||||||
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
||||||
|
@ -71,7 +69,6 @@ public static partial class Db
|
||||||
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<Warning>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Warning>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<UserAction>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<UserAction>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<CsvTimestamp>().ForEach(memoryConnection.Insert);
|
|
||||||
|
|
||||||
return memoryConnection;
|
return memoryConnection;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +89,6 @@ public static partial class Db
|
||||||
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
||||||
public static TableQuery<Warning> Warnings => Connection.Table<Warning>();
|
public static TableQuery<Warning> Warnings => Connection.Table<Warning>();
|
||||||
public static TableQuery<UserAction> UserActions => Connection.Table<UserAction>();
|
public static TableQuery<UserAction> UserActions => Connection.Table<UserAction>();
|
||||||
public static TableQuery<CsvTimestamp> CsvTimestamps => Connection.Table<CsvTimestamp>();
|
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
@ -115,7 +111,6 @@ public static partial class Db
|
||||||
Connection.CreateTable<Error>();
|
Connection.CreateTable<Error>();
|
||||||
Connection.CreateTable<Warning>();
|
Connection.CreateTable<Warning>();
|
||||||
Connection.CreateTable<UserAction>();
|
Connection.CreateTable<UserAction>();
|
||||||
Connection.CreateTable<CsvTimestamp>();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//UpdateKeys();
|
//UpdateKeys();
|
||||||
|
|
|
@ -90,20 +90,6 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Boolean Delete(CsvTimestamp csvTimestampToDelete)
|
|
||||||
{
|
|
||||||
var deleteSuccess = RunTransaction(DeleteCsvTimestampToDelete);
|
|
||||||
if (deleteSuccess)
|
|
||||||
Backup();
|
|
||||||
return deleteSuccess;
|
|
||||||
|
|
||||||
|
|
||||||
Boolean DeleteCsvTimestampToDelete()
|
|
||||||
{
|
|
||||||
return CsvTimestamps.Delete(csvTimestamp => csvTimestamp.Id == csvTimestampToDelete.Id) >0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Boolean Delete(Installation installation)
|
public static Boolean Delete(Installation installation)
|
||||||
{
|
{
|
||||||
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Diagnostics;
|
||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using Hellang.Middleware.ProblemDetails;
|
using Hellang.Middleware.ProblemDetails;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
|
@ -22,6 +23,7 @@ public static class Program
|
||||||
RabbitMqManager.StartRabbitMqConsumer();
|
RabbitMqManager.StartRabbitMqConsumer();
|
||||||
WebsocketManager.MonitorInstallationTable();
|
WebsocketManager.MonitorInstallationTable();
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddProblemDetails(setup =>
|
builder.Services.AddProblemDetails(setup =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,8 +52,6 @@ public static class RabbitMqManager
|
||||||
//A message can be an alarm, a warning or a heartbit
|
//A message can be an alarm, a warning or a heartbit
|
||||||
StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize<StatusMessage>(message);
|
StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize<StatusMessage>(message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lock (WebsocketManager.InstallationConnections)
|
lock (WebsocketManager.InstallationConnections)
|
||||||
{
|
{
|
||||||
//Consumer received a message
|
//Consumer received a message
|
||||||
|
@ -69,17 +67,6 @@ public static class RabbitMqManager
|
||||||
if (receivedStatusMessage.Type == MessageType.Heartbit)
|
if (receivedStatusMessage.Type == MessageType.Heartbit)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("This is a heartbit message from installation: " + installationId + " Name of the file is "+ receivedStatusMessage.Timestamp);
|
//Console.WriteLine("This is a heartbit message from installation: " + installationId + " Name of the file is "+ receivedStatusMessage.Timestamp);
|
||||||
|
|
||||||
if (receivedStatusMessage.Timestamp != 0)
|
|
||||||
{
|
|
||||||
CsvTimestamp newCsvTimestamp = new CsvTimestamp
|
|
||||||
{
|
|
||||||
InstallationId = installationId,
|
|
||||||
Timestamp = receivedStatusMessage.Timestamp
|
|
||||||
};
|
|
||||||
|
|
||||||
Db.AddCsvTimestamp(newCsvTimestamp, installationId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -133,7 +120,7 @@ public static class RabbitMqManager
|
||||||
Seen = false
|
Seen = false
|
||||||
};
|
};
|
||||||
|
|
||||||
Console.WriteLine("Add an alarm for installation "+installationId);
|
//Console.WriteLine("Add an alarm for installation "+installationId);
|
||||||
|
|
||||||
// Send replace battery email to support team if this alarm is "NeedToReplaceBattery"
|
// Send replace battery email to support team if this alarm is "NeedToReplaceBattery"
|
||||||
if (alarm.Description == "2 or more string are disabled")
|
if (alarm.Description == "2 or more string are disabled")
|
||||||
|
@ -187,9 +174,7 @@ public static class RabbitMqManager
|
||||||
{
|
{
|
||||||
WebsocketManager.InformWebsocketsForInstallation(installationId);
|
WebsocketManager.InformWebsocketsForInstallation(installationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer);
|
Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer);
|
||||||
|
|
|
@ -19,7 +19,6 @@ public static class WebsocketManager
|
||||||
lock (InstallationConnections){
|
lock (InstallationConnections){
|
||||||
foreach (var installationConnection in InstallationConnections){
|
foreach (var installationConnection in InstallationConnections){
|
||||||
if ((DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(1)){
|
if ((DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(1)){
|
||||||
Console.WriteLine("Installation "+installationConnection.Key+" is offline, latest timestamp was "+installationConnection.Value.Timestamp);
|
|
||||||
installationConnection.Value.Status = -1;
|
installationConnection.Value.Status = -1;
|
||||||
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +93,7 @@ public static class WebsocketManager
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Received a new message from websocket");
|
//Console.WriteLine("Received a new message from websocket");
|
||||||
lock (InstallationConnections)
|
lock (InstallationConnections)
|
||||||
{
|
{
|
||||||
//Each front-end will send the list of the installations it wants to access
|
//Each front-end will send the list of the installations it wants to access
|
||||||
|
@ -102,6 +101,7 @@ public static class WebsocketManager
|
||||||
//Then, report the status of each requested installation to the front-end that created the websocket connection
|
//Then, report the status of each requested installation to the front-end that created the websocket connection
|
||||||
foreach (var installationId in installationIds)
|
foreach (var installationId in installationIds)
|
||||||
{
|
{
|
||||||
|
//Console.WriteLine("New id is "+installationId);
|
||||||
var installation = Db.GetInstallationById(installationId);
|
var installation = Db.GetInstallationById(installationId);
|
||||||
if (!InstallationConnections.ContainsKey(installationId))
|
if (!InstallationConnections.ContainsKey(installationId))
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,5 +9,5 @@ Salimax0005 ie-entwicklung@10.2.4.36 Schreinerei Schönthal (Thu
|
||||||
Salimax0006 ie-entwicklung@10.2.4.35 Steakhouse Mettmenstetten
|
Salimax0006 ie-entwicklung@10.2.4.35 Steakhouse Mettmenstetten
|
||||||
Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg
|
Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg
|
||||||
Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn
|
Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn
|
||||||
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1
|
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1 (Beat Moser)
|
||||||
SalidomoServer ig@134.209.238.170
|
SalidomoServer ig@134.209.238.170
|
|
@ -54,6 +54,6 @@ INNOVENERGY_PROTOCOL_VERSION = '48TL200V3'
|
||||||
|
|
||||||
|
|
||||||
# S3 Credentials
|
# S3 Credentials
|
||||||
S3BUCKET = "10-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
S3BUCKET = "35-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
||||||
S3KEY = "EXOa8cc58d2e51e389fed9ccbfa"
|
S3KEY = "EXO2a70f415b6b387b5628020bd"
|
||||||
S3SECRET = "hofDGMmSSN1OACYXHWRUGdG61mFjBxKC18sF0VpMQgY"
|
S3SECRET = "qdlYoXDZyME8LEB8BFTuCmJoTzkP2Nebr2jVmlXUzgY"
|
||||||
|
|
|
@ -448,6 +448,8 @@ function Configuration(props: ConfigurationProps) {
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{props.values.maximumDischargePower && (
|
||||||
<div style={{ marginBottom: '5px' }}>
|
<div style={{ marginBottom: '5px' }}>
|
||||||
<TextField
|
<TextField
|
||||||
label={
|
label={
|
||||||
|
@ -464,6 +466,7 @@ function Configuration(props: ConfigurationProps) {
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<TextField
|
||||||
label={
|
label={
|
||||||
|
|
|
@ -387,6 +387,26 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
/>
|
/>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
<FormattedMessage id="edit" defaultMessage="Edit" />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div style={{ maxHeight: '600px', overflowY: 'auto' }}>
|
<div style={{ maxHeight: '600px', overflowY: 'auto' }}>
|
||||||
|
|
|
@ -282,30 +282,10 @@ function Information(props: InformationProps) {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/*<div>*/}
|
|
||||||
{/* <TextField*/}
|
|
||||||
{/* label="S3 Write Key"*/}
|
|
||||||
{/* name="s3writekey"*/}
|
|
||||||
{/* value={formValues.s3WriteKey}*/}
|
|
||||||
{/* variant="outlined"*/}
|
|
||||||
{/* fullWidth*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
|
|
||||||
{/*<div>*/}
|
|
||||||
{/* <TextField*/}
|
|
||||||
{/* label="S3 Write Secret Key"*/}
|
|
||||||
{/* name="s3writesecretkey"*/}
|
|
||||||
{/* value={formValues.s3WriteSecret}*/}
|
|
||||||
{/* variant="outlined"*/}
|
|
||||||
{/* fullWidth*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<TextField
|
||||||
label="S3 Bucket Name"
|
label="S3 Bucket Name"
|
||||||
name="s3writesecretkey"
|
name="s3bucketname"
|
||||||
value={
|
value={
|
||||||
formValues.s3BucketId +
|
formValues.s3BucketId +
|
||||||
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
||||||
|
@ -314,6 +294,25 @@ function Information(props: InformationProps) {
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
label="S3 Write Key"
|
||||||
|
name="s3writekey"
|
||||||
|
value={formValues.s3WriteKey}
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
label="S3 Write Secret Key"
|
||||||
|
name="s3writesecretkey"
|
||||||
|
value={formValues.s3WriteSecret}
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -117,11 +117,11 @@ function Installation(props: singleInstallationProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDataPeriodically = async () => {
|
const fetchDataPeriodically = async () => {
|
||||||
var timeperiodToSearch = 70;
|
var timeperiodToSearch = 90;
|
||||||
let res;
|
let res;
|
||||||
let timestampToFetch;
|
let timestampToFetch;
|
||||||
|
|
||||||
for (var i = timeperiodToSearch; i > 0; i -= 2) {
|
for (var i = 0; i < timeperiodToSearch; i += 2) {
|
||||||
if (!continueFetching.current) {
|
if (!continueFetching.current) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -379,6 +379,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
{loading &&
|
{loading &&
|
||||||
currentTab != 'information' &&
|
currentTab != 'information' &&
|
||||||
currentTab != 'history' &&
|
currentTab != 'history' &&
|
||||||
|
currentTab != 'overview' &&
|
||||||
currentTab != 'log' && (
|
currentTab != 'log' && (
|
||||||
<Container
|
<Container
|
||||||
maxWidth="xl"
|
maxWidth="xl"
|
||||||
|
|
|
@ -85,7 +85,14 @@ function Overview(props: OverviewProps) {
|
||||||
const resultPromise: Promise<{
|
const resultPromise: Promise<{
|
||||||
chartData: chartDataInterface;
|
chartData: chartDataInterface;
|
||||||
chartOverview: overviewInterface;
|
chartOverview: overviewInterface;
|
||||||
}> = transformInputToDailyData(props.s3Credentials, props.id);
|
}> = transformInputToDailyData(
|
||||||
|
props.s3Credentials,
|
||||||
|
props.id,
|
||||||
|
UnixTime.fromTicks(new Date().getTime() / 1000).earlier(
|
||||||
|
TimeSpan.fromDays(1)
|
||||||
|
),
|
||||||
|
UnixTime.fromTicks(new Date().getTime() / 1000)
|
||||||
|
);
|
||||||
|
|
||||||
resultPromise
|
resultPromise
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
@ -169,6 +176,7 @@ function Overview(props: OverviewProps) {
|
||||||
const resultPromise: Promise<{
|
const resultPromise: Promise<{
|
||||||
chartAggregatedData: chartAggregatedDataInterface;
|
chartAggregatedData: chartAggregatedDataInterface;
|
||||||
chartOverview: overviewInterface;
|
chartOverview: overviewInterface;
|
||||||
|
dateList: string[];
|
||||||
}> = transformInputToAggregatedData(
|
}> = transformInputToAggregatedData(
|
||||||
props.s3Credentials,
|
props.s3Credentials,
|
||||||
dayjs().subtract(1, 'week'),
|
dayjs().subtract(1, 'week'),
|
||||||
|
@ -193,7 +201,7 @@ function Overview(props: OverviewProps) {
|
||||||
prevData.concat({
|
prevData.concat({
|
||||||
chartData: result.chartAggregatedData,
|
chartData: result.chartAggregatedData,
|
||||||
chartOverview: result.chartOverview,
|
chartOverview: result.chartOverview,
|
||||||
datelist: computeLast7Days(),
|
datelist: result.dateList,
|
||||||
netbalance: powerDifference
|
netbalance: powerDifference
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -482,7 +490,7 @@ function Overview(props: OverviewProps) {
|
||||||
<FormattedMessage id="lastweek" defaultMessage="Last week" />
|
<FormattedMessage id="lastweek" defaultMessage="Last week" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{aggregatedData && (
|
{/*{aggregatedData && (*/}
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleSetDate}
|
onClick={handleSetDate}
|
||||||
|
@ -497,7 +505,7 @@ function Overview(props: OverviewProps) {
|
||||||
>
|
>
|
||||||
<FormattedMessage id="set_date" defaultMessage="Set Date" />
|
<FormattedMessage id="set_date" defaultMessage="Set Date" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
{/*)}*/}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
|
|
|
@ -78,6 +78,7 @@ function SalidomoOverview(props: salidomoOverviewProps) {
|
||||||
const resultPromise: Promise<{
|
const resultPromise: Promise<{
|
||||||
chartAggregatedData: chartAggregatedDataInterface;
|
chartAggregatedData: chartAggregatedDataInterface;
|
||||||
chartOverview: overviewInterface;
|
chartOverview: overviewInterface;
|
||||||
|
dateList: string[];
|
||||||
}> = transformInputToAggregatedData(
|
}> = transformInputToAggregatedData(
|
||||||
props.s3Credentials,
|
props.s3Credentials,
|
||||||
dayjs().subtract(1, 'week'),
|
dayjs().subtract(1, 'week'),
|
||||||
|
@ -102,7 +103,7 @@ function SalidomoOverview(props: salidomoOverviewProps) {
|
||||||
prevData.concat({
|
prevData.concat({
|
||||||
chartData: result.chartAggregatedData,
|
chartData: result.chartAggregatedData,
|
||||||
chartOverview: result.chartOverview,
|
chartOverview: result.chartOverview,
|
||||||
datelist: computeLast7Days(),
|
datelist: result.dateList,
|
||||||
netbalance: powerDifference
|
netbalance: powerDifference
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { FormattedMessage } from 'react-intl';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
|
|
||||||
interface FlatInstallationViewProps {
|
interface FlatInstallationViewProps {
|
||||||
installations: I_Installation[];
|
installations: I_Installation[];
|
||||||
|
@ -26,7 +27,7 @@ interface FlatInstallationViewProps {
|
||||||
const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
const [isRowHovered, setHoveredRow] = useState(-1);
|
const [isRowHovered, setHoveredRow] = useState(-1);
|
||||||
const webSocketContext = useContext(WebSocketContext);
|
const webSocketContext = useContext(WebSocketContext);
|
||||||
const { getStatus } = webSocketContext;
|
const { getStatus, getTestingMode } = webSocketContext;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||||
const currentLocation = useLocation();
|
const currentLocation = useLocation();
|
||||||
|
@ -320,6 +321,19 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
: 'green'
|
: 'green'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{getTestingMode(installation.id) && (
|
||||||
|
<BuildIcon
|
||||||
|
style={{
|
||||||
|
width: '23px',
|
||||||
|
height: '23px',
|
||||||
|
color: 'purple',
|
||||||
|
borderRadius: '50%',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 1,
|
||||||
|
marginLeft: '15px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
|
@ -24,6 +24,9 @@ import BatteryView from '../BatteryView/BatteryView';
|
||||||
import Log from '../Log/Log';
|
import Log from '../Log/Log';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import SalidomoOverview from '../Overview/salidomoOverview';
|
import SalidomoOverview from '../Overview/salidomoOverview';
|
||||||
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
|
import HistoryOfActions from '../History/History';
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
|
|
||||||
interface singleInstallationProps {
|
interface singleInstallationProps {
|
||||||
current_installation?: I_Installation;
|
current_installation?: I_Installation;
|
||||||
|
@ -36,7 +39,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
const location = useLocation().pathname;
|
const location = useLocation().pathname;
|
||||||
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
|
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
|
||||||
const webSocketsContext = useContext(WebSocketContext);
|
const webSocketsContext = useContext(WebSocketContext);
|
||||||
const { getStatus } = webSocketsContext;
|
const { getStatus, getTestingMode } = webSocketsContext;
|
||||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||||
const status = getStatus(props.current_installation.id);
|
const status = getStatus(props.current_installation.id);
|
||||||
|
@ -74,11 +77,11 @@ function Installation(props: singleInstallationProps) {
|
||||||
const continueFetching = useRef(false);
|
const continueFetching = useRef(false);
|
||||||
|
|
||||||
const fetchDataPeriodically = async () => {
|
const fetchDataPeriodically = async () => {
|
||||||
var timeperiodToSearch = 70;
|
var timeperiodToSearch = 90;
|
||||||
let res;
|
let res;
|
||||||
let timestampToFetch;
|
let timestampToFetch;
|
||||||
|
|
||||||
for (var i = timeperiodToSearch; i > 0; i -= 2) {
|
for (var i = 0; i < timeperiodToSearch; i += 2) {
|
||||||
if (!continueFetching.current) {
|
if (!continueFetching.current) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -274,11 +277,26 @@ function Installation(props: singleInstallationProps) {
|
||||||
: 'green'
|
: 'green'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{getTestingMode(props.current_installation.id) && (
|
||||||
|
<BuildIcon
|
||||||
|
style={{
|
||||||
|
width: '23px',
|
||||||
|
height: '23px',
|
||||||
|
color: 'purple',
|
||||||
|
borderRadius: '50%',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 1,
|
||||||
|
marginLeft: '15px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{loading &&
|
{loading &&
|
||||||
currentTab != 'information' &&
|
currentTab != 'information' &&
|
||||||
currentTab != 'overview' &&
|
currentTab != 'overview' &&
|
||||||
|
currentTab != 'history' &&
|
||||||
currentTab != 'log' && (
|
currentTab != 'log' && (
|
||||||
<Container
|
<Container
|
||||||
maxWidth="xl"
|
maxWidth="xl"
|
||||||
|
@ -354,6 +372,18 @@ function Installation(props: singleInstallationProps) {
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
||||||
|
{currentUser.userType == UserType.admin && (
|
||||||
|
<Route
|
||||||
|
path={routes.history}
|
||||||
|
element={
|
||||||
|
<HistoryOfActions
|
||||||
|
errorLoadingS3Data={errorLoadingS3Data}
|
||||||
|
id={props.current_installation.id}
|
||||||
|
></HistoryOfActions>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={'*'}
|
path={'*'}
|
||||||
element={<Navigate to={routes.information}></Navigate>}
|
element={<Navigate to={routes.information}></Navigate>}
|
||||||
|
|
|
@ -14,7 +14,7 @@ function SalidomoInstallationTabs() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
const { currentUser } = context;
|
const { currentUser } = context;
|
||||||
const tabList = ['batteryview', 'information', 'overview', 'log'];
|
const tabList = ['batteryview', 'information', 'overview', 'log', 'history'];
|
||||||
|
|
||||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||||
const [fetchedInstallations, setFetchedInstallations] =
|
const [fetchedInstallations, setFetchedInstallations] =
|
||||||
|
@ -106,6 +106,15 @@ function SalidomoInstallationTabs() {
|
||||||
label: (
|
label: (
|
||||||
<FormattedMessage id="information" defaultMessage="Information" />
|
<FormattedMessage id="information" defaultMessage="Information" />
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'history',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="history"
|
||||||
|
defaultMessage="History Of Actions"
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
|
|
|
@ -380,16 +380,15 @@ export const transformInputToDailyData = async (
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
let timestampArray: CsvTimestamp[] = [];
|
let timestampArray: number[] = [];
|
||||||
let adjustedTimestampArray = [];
|
let adjustedTimestampArray = [];
|
||||||
const timestampPromises = [];
|
const timestampPromises = [];
|
||||||
|
|
||||||
if (start_time && end_time) {
|
|
||||||
await axiosConfig
|
await axiosConfig
|
||||||
.get(
|
.get(
|
||||||
`/GetCsvTimestampsForInstallation?id=${id}&start=${start_time.ticks}&end=${end_time.ticks}`
|
`/GetCsvTimestampsForInstallation?id=${id}&start=${start_time.ticks}&end=${end_time.ticks}`
|
||||||
)
|
)
|
||||||
.then((res: AxiosResponse<CsvTimestamp[]>) => {
|
.then((res: AxiosResponse<number[]>) => {
|
||||||
timestampArray = res.data;
|
timestampArray = res.data;
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
|
@ -398,29 +397,13 @@ export const transformInputToDailyData = async (
|
||||||
//navigate(routes.login);
|
//navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await axiosConfig
|
|
||||||
.get(`/GetCsvTimestampsForInstallation?id=${id}&start=${0}&end=${0}`)
|
|
||||||
.then((res: AxiosResponse<CsvTimestamp[]>) => {
|
|
||||||
timestampArray = res.data;
|
|
||||||
})
|
|
||||||
.catch((err: AxiosError) => {
|
|
||||||
if (err.response && err.response.status == 401) {
|
|
||||||
//removeToken();
|
|
||||||
//navigate(routes.login);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < timestampArray.length; i++) {
|
for (var i = 0; i < timestampArray.length; i++) {
|
||||||
timestampPromises.push(
|
timestampPromises.push(
|
||||||
fetchDataForOneTime(
|
fetchDataForOneTime(UnixTime.fromTicks(timestampArray[i]), s3Credentials)
|
||||||
UnixTime.fromTicks(timestampArray[i].timestamp),
|
|
||||||
s3Credentials
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const adjustedTimestamp = new Date(timestampArray[i].timestamp * 1000);
|
const adjustedTimestamp = new Date(timestampArray[i] * 1000);
|
||||||
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
||||||
adjustedTimestamp.setHours(
|
adjustedTimestamp.setHours(
|
||||||
adjustedTimestamp.getHours() - adjustedTimestamp.getTimezoneOffset() / 60
|
adjustedTimestamp.getHours() - adjustedTimestamp.getTimezoneOffset() / 60
|
||||||
|
@ -619,7 +602,6 @@ export const transformInputToAggregatedData = async (
|
||||||
if (result[path].value < overviewData[path].min) {
|
if (result[path].value < overviewData[path].min) {
|
||||||
overviewData[path].min = result[path].value;
|
overviewData[path].min = result[path].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result[path].value > overviewData[path].max) {
|
if (result[path].value > overviewData[path].max) {
|
||||||
overviewData[path].max = result[path].value;
|
overviewData[path].max = result[path].value;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue