Created error table, provided error handling
This commit is contained in:
parent
22dd4222ca
commit
6a18e56cf7
|
@ -226,8 +226,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="DbBackups\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -54,6 +54,8 @@ public class Controller : ControllerBase
|
||||||
: Unauthorized();
|
: Unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet(nameof(CreateWebSocket))]
|
[HttpGet(nameof(CreateWebSocket))]
|
||||||
public async Task CreateWebSocket(Token authToken)
|
public async Task CreateWebSocket(Token authToken)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +84,23 @@ public class Controller : ControllerBase
|
||||||
await WebsocketManager.HandleWebSocketConnection(webSocket);
|
await WebsocketManager.HandleWebSocketConnection(webSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(GetAllErrorsForInstallation))]
|
||||||
|
public ActionResult<IEnumerable<Error>> GetAllErrorsForInstallation(Int64 id, Token authToken)
|
||||||
|
{
|
||||||
|
var user = Db.GetSession(authToken)?.User;
|
||||||
|
if (user == null)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var installation = Db.GetInstallationById(id);
|
||||||
|
|
||||||
|
if (installation is null || !user.HasAccessTo(installation))
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
return Db.Errors
|
||||||
|
.Where(error => error.InstallationId == id)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet(nameof(GetUserById))]
|
[HttpGet(nameof(GetUserById))]
|
||||||
public ActionResult<User> GetUserById(Int64 id, Token authToken)
|
public ActionResult<User> GetUserById(Int64 id, Token authToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
|
public class Error
|
||||||
|
{
|
||||||
|
[PrimaryKey, AutoIncrement]
|
||||||
|
public Int64 Id { get; set; }
|
||||||
|
public Int64 InstallationId { get; set; }
|
||||||
|
public String ErrorDescription { get; set; } = null!;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public String DeviceCreatedTheError { get; set; } = null!;
|
||||||
|
public Boolean Seen { get; set; }
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods;
|
||||||
|
|
||||||
public static class FolderMethods
|
public static class FolderMethods
|
||||||
{
|
{
|
||||||
|
|
||||||
public static IEnumerable<User> UsersWithAccess(this Folder folder)
|
public static IEnumerable<User> UsersWithAccess(this Folder folder)
|
||||||
{
|
{
|
||||||
var direct = folder.UsersWithDirectAccess();
|
var direct = folder.UsersWithDirectAccess();
|
||||||
|
|
|
@ -141,7 +141,7 @@ public static class InstallationMethods
|
||||||
foreach (var orderNumber in installation.OrderNumbers.Split(","))
|
foreach (var orderNumber in installation.OrderNumbers.Split(","))
|
||||||
{
|
{
|
||||||
var rel = relations.FirstOrDefault(i => i.OrderNumber == orderNumber);
|
var rel = relations.FirstOrDefault(i => i.OrderNumber == orderNumber);
|
||||||
if ( rel != null) relations.Remove(rel);
|
if ( rel != null) {relations.Remove(rel); continue;}
|
||||||
var o2I = new OrderNumber2Installation
|
var o2I = new OrderNumber2Installation
|
||||||
{
|
{
|
||||||
OrderNumber = orderNumber,
|
OrderNumber = orderNumber,
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
public abstract partial class TreeNode
|
public abstract partial class TreeNode
|
||||||
{
|
{
|
||||||
[PrimaryKey, AutoIncrement]
|
[PrimaryKey, AutoIncrement]
|
||||||
public virtual Int64 Id { get; set; }
|
public Int64 Id { get; set; }
|
||||||
public virtual String Name { get; set; } = ""; // overridden by User (unique)
|
public virtual String Name { get; set; } = ""; // overridden by User (unique)
|
||||||
public String Information { get; set; } = ""; // unstructured random info
|
public String Information { get; set; } = ""; // unstructured random info
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,11 @@ public static partial class Db
|
||||||
return Insert(installation);
|
return Insert(installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean Create(Error error)
|
||||||
|
{
|
||||||
|
return Insert(error);
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean Create(Folder folder)
|
public static Boolean Create(Folder folder)
|
||||||
{
|
{
|
||||||
return Insert(folder);
|
return Insert(folder);
|
||||||
|
@ -49,4 +54,30 @@ public static partial class Db
|
||||||
{
|
{
|
||||||
return Insert(o2i);
|
return Insert(o2i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void HandleError(Error newError,int installationId)
|
||||||
|
{
|
||||||
|
//Find the total number of errors for this installation
|
||||||
|
var totalErrors = Errors.Count(error => error.InstallationId == installationId);
|
||||||
|
|
||||||
|
//If there are 100 errors, remove the one with the oldest timestamp
|
||||||
|
if (totalErrors == 100)
|
||||||
|
{
|
||||||
|
var oldestError =
|
||||||
|
Errors.Where(error => error.InstallationId == installationId)
|
||||||
|
.OrderBy(error => error.CreatedAt)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
//Remove the old error
|
||||||
|
Delete(oldestError);
|
||||||
|
|
||||||
|
//Add the new error
|
||||||
|
Create(newError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("---------------Added the new Error to the database-----------------");
|
||||||
|
Create(newError);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,21 +15,36 @@ namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public static partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
// internal const String DbPath = "./db.sqlite";
|
private static SQLiteConnection Connection { get; } = InitConnection();
|
||||||
|
|
||||||
private static SQLiteConnection Connection { get; } = ((Func<SQLiteConnection>)(() =>
|
private static SQLiteConnection InitConnection()
|
||||||
{
|
{
|
||||||
var latestDb = new DirectoryInfo(@"DbBackups").GetFiles()
|
var latestDb = new DirectoryInfo("DbBackups")
|
||||||
|
.GetFiles()
|
||||||
.OrderBy(f => f.LastWriteTime)
|
.OrderBy(f => f.LastWriteTime)
|
||||||
.Last().Name;
|
.Last().Name;
|
||||||
|
|
||||||
var fileConnection = new SQLiteConnection("DbBackups/"+latestDb);
|
//This is the file connection from the DbBackups folder
|
||||||
|
var fileConnection = new SQLiteConnection("DbBackups/" + latestDb);
|
||||||
|
|
||||||
Console.Out.Write(latestDb);
|
//Create a table if it does not exist
|
||||||
|
fileConnection.CreateTable<User>();
|
||||||
|
fileConnection.CreateTable<Installation>();
|
||||||
|
fileConnection.CreateTable<Folder>();
|
||||||
|
fileConnection.CreateTable<FolderAccess>();
|
||||||
|
fileConnection.CreateTable<InstallationAccess>();
|
||||||
|
fileConnection.CreateTable<Session>();
|
||||||
|
fileConnection.CreateTable<OrderNumber2Installation>();
|
||||||
|
fileConnection.CreateTable<Error>();
|
||||||
|
|
||||||
|
return CopyDbToMemory(fileConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SQLiteConnection CopyDbToMemory(SQLiteConnection fileConnection)
|
||||||
|
{
|
||||||
var memoryConnection = new SQLiteConnection(":memory:");
|
var memoryConnection = new SQLiteConnection(":memory:");
|
||||||
|
|
||||||
// fileConnection.Backup(memoryConnection.DatabasePath);
|
//Create a table if it does not exist in main memory
|
||||||
|
|
||||||
memoryConnection.CreateTable<User>();
|
memoryConnection.CreateTable<User>();
|
||||||
memoryConnection.CreateTable<Installation>();
|
memoryConnection.CreateTable<Installation>();
|
||||||
memoryConnection.CreateTable<Folder>();
|
memoryConnection.CreateTable<Folder>();
|
||||||
|
@ -37,17 +52,20 @@ public static partial class Db
|
||||||
memoryConnection.CreateTable<InstallationAccess>();
|
memoryConnection.CreateTable<InstallationAccess>();
|
||||||
memoryConnection.CreateTable<Session>();
|
memoryConnection.CreateTable<Session>();
|
||||||
memoryConnection.CreateTable<OrderNumber2Installation>();
|
memoryConnection.CreateTable<OrderNumber2Installation>();
|
||||||
|
memoryConnection.CreateTable<Error>();
|
||||||
|
|
||||||
fileConnection.Table<Session> ().ForEach(memoryConnection.Insert);
|
//Copy all the existing tables from the disk to main memory
|
||||||
fileConnection.Table<Folder> ().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<Installation> ().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Folder>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<User> ().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Installation>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<FolderAccess> ().ForEach(memoryConnection.Insert);
|
fileConnection.Table<User>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<InstallationAccess> ().ForEach(memoryConnection.Insert);
|
fileConnection.Table<FolderAccess>().ForEach(memoryConnection.Insert);
|
||||||
|
fileConnection.Table<InstallationAccess>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert);
|
||||||
|
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
||||||
|
|
||||||
return memoryConnection;
|
return memoryConnection;
|
||||||
}))();
|
}
|
||||||
|
|
||||||
public static void BackupDatabase()
|
public static void BackupDatabase()
|
||||||
{
|
{
|
||||||
|
@ -62,17 +80,16 @@ public static partial class Db
|
||||||
public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>();
|
public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>();
|
||||||
public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();
|
public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();
|
||||||
public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>();
|
public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>();
|
||||||
|
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
||||||
|
|
||||||
public static void Init()
|
public static void Init(){
|
||||||
{
|
|
||||||
// used to force static constructor
|
// used to force static constructor
|
||||||
|
//Since this class is static, we call Init method from the Program.cs to initialize all the fields of the class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//This is the constructor of the class
|
||||||
static Db()
|
static Db()
|
||||||
{
|
{
|
||||||
// on startup create/migrate tables
|
|
||||||
|
|
||||||
Connection.RunInTransaction(() =>
|
Connection.RunInTransaction(() =>
|
||||||
{
|
{
|
||||||
Connection.CreateTable<User>();
|
Connection.CreateTable<User>();
|
||||||
|
@ -82,6 +99,7 @@ public static partial class Db
|
||||||
Connection.CreateTable<InstallationAccess>();
|
Connection.CreateTable<InstallationAccess>();
|
||||||
Connection.CreateTable<Session>();
|
Connection.CreateTable<Session>();
|
||||||
Connection.CreateTable<OrderNumber2Installation>();
|
Connection.CreateTable<OrderNumber2Installation>();
|
||||||
|
Connection.CreateTable<Error>();
|
||||||
});
|
});
|
||||||
|
|
||||||
Observable.Interval(TimeSpan.FromHours(0.5))
|
Observable.Interval(TimeSpan.FromHours(0.5))
|
||||||
|
|
|
@ -35,6 +35,20 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean Delete(Error errorToDelete)
|
||||||
|
{
|
||||||
|
var deleteSuccess = RunTransaction(DeleteError);
|
||||||
|
if (deleteSuccess)
|
||||||
|
BackupDatabase();
|
||||||
|
return deleteSuccess;
|
||||||
|
|
||||||
|
|
||||||
|
Boolean DeleteError()
|
||||||
|
{
|
||||||
|
return Errors.Delete(error => error.Id == errorToDelete.Id) >0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean Delete(Installation installation)
|
public static Boolean Delete(Installation installation)
|
||||||
{
|
{
|
||||||
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
||||||
|
|
|
@ -33,7 +33,4 @@ public static partial class Db
|
||||||
|
|
||||||
return Update(obj: user);
|
return Update(obj: user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,4 +3,7 @@ public class StatusMessage
|
||||||
{
|
{
|
||||||
public required int InstallationId { get; init; }
|
public required int InstallationId { get; init; }
|
||||||
public required int Status { get; init; }
|
public required int Status { get; init; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public String Error { get; init; } = null!;
|
||||||
|
public String DeviceCreatedTheError { get; init; } = null!;
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using RabbitMQ.Client.Events;
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
|
@ -19,7 +20,6 @@ public static class WebsocketManager
|
||||||
|
|
||||||
public static void InformInstallationsToSubscribeToRabbitMq()
|
public static void InformInstallationsToSubscribeToRabbitMq()
|
||||||
{
|
{
|
||||||
//var installationIps = new List<string> { "10.2.3.115" };
|
|
||||||
var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList();
|
var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList();
|
||||||
Console.WriteLine("Count is "+installationIps.Count);
|
Console.WriteLine("Count is "+installationIps.Count);
|
||||||
var maxRetransmissions = 2;
|
var maxRetransmissions = 2;
|
||||||
|
@ -83,7 +83,7 @@ public static class WebsocketManager
|
||||||
|
|
||||||
lock (InstallationConnections)
|
lock (InstallationConnections)
|
||||||
{
|
{
|
||||||
// Process the received message
|
//Consumer received a message
|
||||||
if (receivedStatusMessage != null)
|
if (receivedStatusMessage != null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status);
|
Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status);
|
||||||
|
@ -91,6 +91,24 @@ public static class WebsocketManager
|
||||||
Console.WriteLine("Update installation connection table");
|
Console.WriteLine("Update installation connection table");
|
||||||
var installationId = receivedStatusMessage.InstallationId;
|
var installationId = receivedStatusMessage.InstallationId;
|
||||||
|
|
||||||
|
//This is an error message
|
||||||
|
if (receivedStatusMessage.Status==2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("-----------------------New error-----------------------");
|
||||||
|
|
||||||
|
Error newError = new Error
|
||||||
|
{
|
||||||
|
InstallationId = receivedStatusMessage.InstallationId,
|
||||||
|
ErrorDescription = receivedStatusMessage.Error,
|
||||||
|
CreatedAt = receivedStatusMessage.CreatedAt,
|
||||||
|
DeviceCreatedTheError = receivedStatusMessage.DeviceCreatedTheError,
|
||||||
|
Seen = false
|
||||||
|
};
|
||||||
|
//Create a new error and add it to the database
|
||||||
|
Db.HandleError(newError,receivedStatusMessage.InstallationId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!InstallationConnections.ContainsKey(installationId))
|
if (!InstallationConnections.ContainsKey(installationId))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Create new empty list for installation: " + installationId);
|
Console.WriteLine("Create new empty list for installation: " + installationId);
|
||||||
|
|
|
@ -3,6 +3,10 @@ namespace InnovEnergy.App.SaliMax.MiddlewareClasses;
|
||||||
|
|
||||||
public class StatusMessage
|
public class StatusMessage
|
||||||
{
|
{
|
||||||
|
|
||||||
public required int InstallationId { get; init; }
|
public required int InstallationId { get; init; }
|
||||||
public required int Status { get; init; }
|
public required int Status { get; init; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public String Error { get; set; } = null!;
|
||||||
|
public String DeviceCreatedTheError { get; set; } = null!;
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
@ -265,10 +266,14 @@ internal static class Program
|
||||||
{
|
{
|
||||||
_subscribeToQueueForTheFirstTime = true;
|
_subscribeToQueueForTheFirstTime = true;
|
||||||
SubscribeToQueue(currentSalimaxState, s3Bucket);
|
SubscribeToQueue(currentSalimaxState, s3Bucket);
|
||||||
}
|
|
||||||
|
|
||||||
//If already subscribed to the queue and the status has been changed, update the queue
|
|
||||||
if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
|
if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
|
||||||
|
{
|
||||||
|
_prevSalimaxState = currentSalimaxState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//If already subscribed to the queue and the status has been changed, update the queue
|
||||||
|
else if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
|
||||||
{
|
{
|
||||||
_prevSalimaxState = currentSalimaxState;
|
_prevSalimaxState = currentSalimaxState;
|
||||||
if (s3Bucket != null)
|
if (s3Bucket != null)
|
||||||
|
@ -343,13 +348,19 @@ internal static class Program
|
||||||
private static void InformMiddleware(String? bucket, int status)
|
private static void InformMiddleware(String? bucket, int status)
|
||||||
{
|
{
|
||||||
int.TryParse(bucket[0].ToString(), out var installationId);
|
int.TryParse(bucket[0].ToString(), out var installationId);
|
||||||
|
|
||||||
var jsonObject = new StatusMessage
|
var jsonObject = new StatusMessage
|
||||||
{
|
{
|
||||||
InstallationId = installationId,
|
InstallationId = installationId,
|
||||||
Status = status
|
Status = status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (status == 2)
|
||||||
|
{
|
||||||
|
jsonObject.CreatedAt = DateTime.Now;
|
||||||
|
jsonObject.Error = "Battery Temperature High";
|
||||||
|
jsonObject.DeviceCreatedTheError = "Battery/1";
|
||||||
|
}
|
||||||
|
|
||||||
var message = JsonSerializer.Serialize(jsonObject);
|
var message = JsonSerializer.Serialize(jsonObject);
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
var body = Encoding.UTF8.GetBytes(message);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.ComponentModel;
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
|
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
||||||
using InnovEnergy.Lib.Units.Composite;
|
using InnovEnergy.Lib.Units.Composite;
|
||||||
|
@ -18,6 +19,9 @@ public class AcDcDevicesRecord
|
||||||
public SystemControlRegisters? SystemControl { get; }
|
public SystemControlRegisters? SystemControl { get; }
|
||||||
public IReadOnlyList<AcDcRecord> Devices { get; init; }
|
public IReadOnlyList<AcDcRecord> Devices { get; init; }
|
||||||
|
|
||||||
|
//public IEnumerable<AlarmMessage> Alarms => new []{AlarmMessage.BatteryOvervoltage}; //Devices.SelectMany(d => d.Status.Alarms).Distinct();
|
||||||
|
//public IEnumerable<WarningMessage> Warnings => new []{WarningMessage.TempDerating}; //Devices.SelectMany(d => d.Status.Warnings).Distinct();
|
||||||
|
|
||||||
public IEnumerable<AlarmMessage> Alarms => Devices.SelectMany(d => d.Status.Alarms).Distinct();
|
public IEnumerable<AlarmMessage> Alarms => Devices.SelectMany(d => d.Status.Alarms).Distinct();
|
||||||
public IEnumerable<WarningMessage> Warnings => Devices.SelectMany(d => d.Status.Warnings).Distinct();
|
public IEnumerable<WarningMessage> Warnings => Devices.SelectMany(d => d.Status.Warnings).Distinct();
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ public enum WarningMessage : UInt16
|
||||||
{
|
{
|
||||||
NoWarning = 00000,
|
NoWarning = 00000,
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
// these warnings are not official (not in the manual), and they seem to collide with the DCDC warnings
|
// these warnings are not official (not in the manual), and they seem to collide with the DCDC warnings
|
||||||
// so I commented them
|
// so I commented them
|
||||||
|
@ -28,5 +28,5 @@ public enum WarningMessage : UInt16
|
||||||
RuntimeEeprom = 11023, //AC-DC module warning
|
RuntimeEeprom = 11023, //AC-DC module warning
|
||||||
Overcurrent = 11024 //Overcurrent handling is active
|
Overcurrent = 11024 //Overcurrent handling is active
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const axiosConfigWithoutToken = axios.create({
|
export const axiosConfigWithoutToken = axios.create({
|
||||||
baseURL: 'https://monitor.innov.energy/api'
|
//baseURL: 'https://monitor.innov.energy/api'
|
||||||
// baseURL: 'http://127.0.0.1:7087/api'
|
baseURL: 'http://127.0.0.1:7087/api'
|
||||||
});
|
});
|
||||||
|
|
||||||
const axiosConfig = axios.create({
|
const axiosConfig = axios.create({
|
||||||
baseURL: 'https://monitor.innov.energy/api'
|
//baseURL: 'https://monitor.innov.energy/api'
|
||||||
//baseURL: 'http://127.0.0.1:7087/api'
|
baseURL: 'http://127.0.0.1:7087/api'
|
||||||
});
|
});
|
||||||
|
|
||||||
axiosConfig.defaults.params = {};
|
axiosConfig.defaults.params = {};
|
||||||
|
|
|
@ -28,7 +28,6 @@ import {
|
||||||
extractValues,
|
extractValues,
|
||||||
TopologyValues
|
TopologyValues
|
||||||
} from 'src/content/dashboards/Log/graph.util';
|
} from 'src/content/dashboards/Log/graph.util';
|
||||||
import { Notification } from 'src/interfaces/S3Types';
|
|
||||||
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
||||||
import Topology from '../Topology/Topology';
|
import Topology from '../Topology/Topology';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
@ -62,8 +61,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
deleteInstallation
|
deleteInstallation
|
||||||
} = installationContext;
|
} = installationContext;
|
||||||
|
|
||||||
const [warnings, setWarnings] = useState<Notification[]>([]);
|
|
||||||
const [errors, setErrors] = useState<Notification[]>([]);
|
|
||||||
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
|
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
|
||||||
const webSocketsContext = useContext(WebSocketContext);
|
const webSocketsContext = useContext(WebSocketContext);
|
||||||
const { getStatus } = webSocketsContext;
|
const { getStatus } = webSocketsContext;
|
||||||
|
@ -153,9 +150,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newWarnings: Notification[] = [];
|
|
||||||
const newErrors: Notification[] = [];
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
res === FetchResult.notAvailable ||
|
res === FetchResult.notAvailable ||
|
||||||
res === FetchResult.tryLater
|
res === FetchResult.tryLater
|
||||||
|
@ -681,9 +675,8 @@ function Installation(props: singleInstallationProps) {
|
||||||
{currentTab === 'live' && <Topology values={values}></Topology>}
|
{currentTab === 'live' && <Topology values={values}></Topology>}
|
||||||
{currentTab === 'log' && (
|
{currentTab === 'log' && (
|
||||||
<Log
|
<Log
|
||||||
warnings={warnings}
|
|
||||||
errors={errors}
|
|
||||||
errorLoadingS3Data={errorLoadingS3Data}
|
errorLoadingS3Data={errorLoadingS3Data}
|
||||||
|
id={props.current_installation.id}
|
||||||
></Log>
|
></Log>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Card,
|
Card,
|
||||||
|
@ -14,26 +14,49 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
useTheme
|
useTheme
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { Notification } from 'src/interfaces/S3Types';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
|
import axiosConfig from '../../../Resources/axiosConfig';
|
||||||
|
import { AxiosError, AxiosResponse } from 'axios/index';
|
||||||
|
import routes from '../../../Resources/routes.json';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { TokenContext } from '../../../contexts/tokenContext';
|
||||||
|
import { ErrorMessage } from '../../../interfaces/S3Types';
|
||||||
|
|
||||||
interface LogProps {
|
interface LogProps {
|
||||||
warnings: Notification[];
|
|
||||||
errors: Notification[];
|
|
||||||
errorLoadingS3Data: boolean;
|
errorLoadingS3Data: boolean;
|
||||||
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Log(props: LogProps) {
|
function Log(props: LogProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
//const [warnings, setWarnings] = useState<Notification[]>([]);
|
||||||
|
const [errors, setErrors] = useState<ErrorMessage[]>([]);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const tokencontext = useContext(TokenContext);
|
||||||
|
const { removeToken } = tokencontext;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axiosConfig
|
||||||
|
.get(`/GetAllErrorsForInstallation?id=${props.id}`)
|
||||||
|
.then((res: AxiosResponse<ErrorMessage[]>) => {
|
||||||
|
setErrors(res.data);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
if (err.response && err.response.status == 401) {
|
||||||
|
removeToken();
|
||||||
|
navigate(routes.login);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
{(props.errors.length > 0 || props.warnings.length > 0) && (
|
{/* IT SHOULD BE {(errors.length > 0 || props.warnings.length > 0) && (*/}
|
||||||
|
{errors.length > 0 && (
|
||||||
<Card sx={{ marginTop: '10px' }}>
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
|
@ -43,25 +66,26 @@ function Log(props: LogProps) {
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage id="type" defaultMessage="Type" />
|
<FormattedMessage id="type" defaultMessage="Type" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
|
||||||
<FormattedMessage id="device" defaultMessage="Device" />
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="description"
|
id="description"
|
||||||
defaultMessage="Description"
|
defaultMessage="Description"
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage id="device" defaultMessage="Device" />
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage id="date" defaultMessage="Date" />
|
<FormattedMessage id="date" defaultMessage="Date" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage id="time" defaultMessage="Time" />
|
<FormattedMessage id="seen" defaultMessage="Seen" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{props.errors.map((error, index) => {
|
{errors.map((error, index) => {
|
||||||
return (
|
return (
|
||||||
<TableRow hover key={index}>
|
<TableRow hover key={index}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -82,9 +106,9 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
sx={{ marginTop: '5px', marginLeft: '-40px' }}
|
||||||
>
|
>
|
||||||
{error.device}
|
{error.errorDescription}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -96,7 +120,7 @@ function Log(props: LogProps) {
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
sx={{ marginTop: '5px' }}
|
||||||
>
|
>
|
||||||
{error.description}
|
{error.deviceCreatedTheError}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -106,9 +130,9 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
sx={{ marginTop: '5px', marginLeft: '-40px' }}
|
||||||
>
|
>
|
||||||
{error.date}
|
{error.createdAt}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -118,87 +142,87 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
sx={{ marginTop: '5px', marginLeft: '10px' }}
|
||||||
>
|
>
|
||||||
{error.time}
|
{error.seen == false ? 'No' : 'Yes'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{props.warnings.map((warning, index) => {
|
{/*{props.warnings.map((warning, index) => {*/}
|
||||||
return (
|
{/* return (*/}
|
||||||
<TableRow hover key={index}>
|
{/* <TableRow hover key={index}>*/}
|
||||||
<TableCell>
|
{/* <TableCell>*/}
|
||||||
<WarningIcon
|
{/* <WarningIcon*/}
|
||||||
sx={{
|
{/* sx={{*/}
|
||||||
color: '#ffc04d',
|
{/* color: '#ffc04d',*/}
|
||||||
width: 25,
|
{/* width: 25,*/}
|
||||||
height: 25,
|
{/* height: 25,*/}
|
||||||
marginLeft: '5px',
|
{/* marginLeft: '5px',*/}
|
||||||
marginTop: '8px'
|
{/* marginTop: '8px'*/}
|
||||||
}}
|
{/* }}*/}
|
||||||
/>
|
{/* />*/}
|
||||||
</TableCell>
|
{/* </TableCell>*/}
|
||||||
<TableCell>
|
{/* <TableCell>*/}
|
||||||
<Typography
|
{/* <Typography*/}
|
||||||
variant="body1"
|
{/* variant="body1"*/}
|
||||||
fontWeight="bold"
|
{/* fontWeight="bold"*/}
|
||||||
color="text.primary"
|
{/* color="text.primary"*/}
|
||||||
gutterBottom
|
{/* gutterBottom*/}
|
||||||
noWrap
|
{/* noWrap*/}
|
||||||
sx={{ marginTop: '10px' }}
|
{/* sx={{ marginTop: '10px' }}*/}
|
||||||
>
|
{/* >*/}
|
||||||
{warning.device}
|
{/* {warning.device}*/}
|
||||||
</Typography>
|
{/* </Typography>*/}
|
||||||
</TableCell>
|
{/* </TableCell>*/}
|
||||||
<TableCell>
|
{/* <TableCell>*/}
|
||||||
<Typography
|
{/* <Typography*/}
|
||||||
variant="body1"
|
{/* variant="body1"*/}
|
||||||
fontWeight="bold"
|
{/* fontWeight="bold"*/}
|
||||||
color="text.primary"
|
{/* color="text.primary"*/}
|
||||||
gutterBottom
|
{/* gutterBottom*/}
|
||||||
noWrap
|
{/* noWrap*/}
|
||||||
sx={{ marginTop: '10px' }}
|
{/* sx={{ marginTop: '10px' }}*/}
|
||||||
>
|
{/* >*/}
|
||||||
{warning.description}
|
{/* {warning.description}*/}
|
||||||
</Typography>
|
{/* </Typography>*/}
|
||||||
</TableCell>
|
{/* </TableCell>*/}
|
||||||
<TableCell>
|
{/* <TableCell>*/}
|
||||||
<Typography
|
{/* <Typography*/}
|
||||||
variant="body1"
|
{/* variant="body1"*/}
|
||||||
fontWeight="bold"
|
{/* fontWeight="bold"*/}
|
||||||
color="text.primary"
|
{/* color="text.primary"*/}
|
||||||
gutterBottom
|
{/* gutterBottom*/}
|
||||||
noWrap
|
{/* noWrap*/}
|
||||||
sx={{ marginTop: '10px' }}
|
{/* sx={{ marginTop: '10px' }}*/}
|
||||||
>
|
{/* >*/}
|
||||||
{warning.date}
|
{/* {warning.date}*/}
|
||||||
</Typography>
|
{/* </Typography>*/}
|
||||||
</TableCell>
|
{/* </TableCell>*/}
|
||||||
<TableCell>
|
{/* <TableCell>*/}
|
||||||
<Typography
|
{/* <Typography*/}
|
||||||
variant="body1"
|
{/* variant="body1"*/}
|
||||||
fontWeight="bold"
|
{/* fontWeight="bold"*/}
|
||||||
color="text.primary"
|
{/* color="text.primary"*/}
|
||||||
gutterBottom
|
{/* gutterBottom*/}
|
||||||
noWrap
|
{/* noWrap*/}
|
||||||
sx={{ marginTop: '10px' }}
|
{/* sx={{ marginTop: '10px' }}*/}
|
||||||
>
|
{/* >*/}
|
||||||
{warning.time}
|
{/* {warning.time}*/}
|
||||||
</Typography>
|
{/* </Typography>*/}
|
||||||
</TableCell>
|
{/* </TableCell>*/}
|
||||||
</TableRow>
|
{/* </TableRow>*/}
|
||||||
);
|
{/* );*/}
|
||||||
})}
|
{/*})}*/}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!props.errorLoadingS3Data && props.errors.length == 0 && (
|
{!props.errorLoadingS3Data && errors.length == 0 && (
|
||||||
<Alert
|
<Alert
|
||||||
severity="error"
|
severity="error"
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -242,27 +266,27 @@ function Log(props: LogProps) {
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!props.errorLoadingS3Data && props.warnings.length == 0 && (
|
{/*{!props.errorLoadingS3Data && props.warnings.length == 0 && (*/}
|
||||||
<Alert
|
{/* <Alert*/}
|
||||||
severity="error"
|
{/* severity="error"*/}
|
||||||
sx={{
|
{/* sx={{*/}
|
||||||
display: 'flex',
|
{/* display: 'flex',*/}
|
||||||
alignItems: 'center',
|
{/* alignItems: 'center',*/}
|
||||||
//marginBottom: '20px'
|
{/* //marginBottom: '20px'*/}
|
||||||
marginTop: '20px'
|
{/* marginTop: '20px'*/}
|
||||||
}}
|
{/* }}*/}
|
||||||
>
|
{/* >*/}
|
||||||
<FormattedMessage
|
{/* <FormattedMessage*/}
|
||||||
id="nowarnings"
|
{/* id="nowarnings"*/}
|
||||||
defaultMessage="There are no warnings"
|
{/* defaultMessage="There are no warnings"*/}
|
||||||
/>
|
{/* />*/}
|
||||||
<IconButton
|
{/* <IconButton*/}
|
||||||
color="inherit"
|
{/* color="inherit"*/}
|
||||||
size="small"
|
{/* size="small"*/}
|
||||||
sx={{ marginLeft: '4px' }}
|
{/* sx={{ marginLeft: '4px' }}*/}
|
||||||
></IconButton>
|
{/* ></IconButton>*/}
|
||||||
</Alert>
|
{/* </Alert>*/}
|
||||||
)}
|
{/*)}*/}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { UnixTime } from '../../../dataCache/time';
|
|
||||||
import { I_S3Credentials } from '../../../interfaces/S3Types';
|
|
||||||
import { FetchResult } from '../../../dataCache/dataCache';
|
|
||||||
import { DataRecord } from '../../../dataCache/data';
|
|
||||||
import { S3Access } from '../../../dataCache/S3/S3Access';
|
|
||||||
import { parseCsv } from './graph.util';
|
|
||||||
|
|
||||||
export const fetchData = (
|
|
||||||
timestamp: UnixTime,
|
|
||||||
s3Credentials?: I_S3Credentials
|
|
||||||
): Promise<FetchResult<DataRecord>> => {
|
|
||||||
const s3Path = `${timestamp.ticks}.csv`;
|
|
||||||
if (s3Credentials && s3Credentials.s3Bucket) {
|
|
||||||
const s3Access = new S3Access(
|
|
||||||
s3Credentials.s3Bucket,
|
|
||||||
s3Credentials.s3Region,
|
|
||||||
s3Credentials.s3Provider,
|
|
||||||
s3Credentials.s3Key,
|
|
||||||
s3Credentials.s3Secret
|
|
||||||
);
|
|
||||||
return s3Access
|
|
||||||
.get(s3Path)
|
|
||||||
.then(async (r) => {
|
|
||||||
if (r.status === 404) {
|
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
|
||||||
} else if (r.status === 200) {
|
|
||||||
const text = await r.text();
|
|
||||||
return parseCsv(text);
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
return Promise.resolve(FetchResult.tryLater);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -6,9 +6,10 @@ export interface I_S3Credentials {
|
||||||
s3Bucket?: string;
|
s3Bucket?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Notification {
|
export interface ErrorMessage {
|
||||||
device: string;
|
installationId: number;
|
||||||
description: string;
|
createdAt: Date;
|
||||||
date: string;
|
errorDescription: string;
|
||||||
time: string;
|
deviceCreatedTheError: string;
|
||||||
|
seen: boolean;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue