Merge remote-tracking branch 'origin/main'
# Conflicts: # csharp/App/Backend/Database/User.cs # csharp/App/Backend/Model/User.cs
This commit is contained in:
commit
f1394e4755
|
@ -0,0 +1,18 @@
|
||||||
|
using InnovEnergy.App.Backend.Model;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO ?
|
||||||
|
public struct DbConnection
|
||||||
|
{
|
||||||
|
public DbConnection(SQLiteConnection connection, User caller)
|
||||||
|
{
|
||||||
|
Connection = connection;
|
||||||
|
Caller = caller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SQLiteConnection Connection { get;}
|
||||||
|
public User Caller { get;}
|
||||||
|
}
|
|
@ -30,10 +30,25 @@ public partial class Db
|
||||||
|
|
||||||
public Boolean IsParentOfChild(Int64 parentId, User child)
|
public Boolean IsParentOfChild(Int64 parentId, User child)
|
||||||
{
|
{
|
||||||
return child
|
return Ancestors(child)
|
||||||
.Unfold(u => GetUserById(u.ParentId))
|
.Any(u => u.Id == parentId);
|
||||||
.Select(u => u.Id)
|
}
|
||||||
.Contains(parentId);
|
|
||||||
|
private IEnumerable<User> Ancestors(User child)
|
||||||
|
{
|
||||||
|
return child.Unfold(GetParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User? GetParent(User u)
|
||||||
|
{
|
||||||
|
return IsRoot(u)
|
||||||
|
? null
|
||||||
|
: GetUserById(u.ParentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean IsRoot(User u)
|
||||||
|
{
|
||||||
|
return u.ParentId == 0; // root has ParentId 0 by definition
|
||||||
}
|
}
|
||||||
|
|
||||||
public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
|
public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
|
||||||
|
|
|
@ -5,10 +5,10 @@ namespace InnovEnergy.App.Backend.Model;
|
||||||
public class User : TreeNode
|
public class User : TreeNode
|
||||||
{
|
{
|
||||||
[Indexed]
|
[Indexed]
|
||||||
public String Email { get; set; } = "";
|
public String Email { get; set; } = null!;
|
||||||
public Boolean HasWriteAccess { get; set; }
|
public Boolean HasWriteAccess { get; set; } = false;
|
||||||
public String Salt { get; set; }
|
public String Salt { get; set; } = null!;
|
||||||
public String Password { get; set; }
|
public String Password { get; set; } = null!;
|
||||||
|
|
||||||
// TODO: must reset pwd
|
// TODO: must reset pwd
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,60 @@
|
||||||
using DecimalMath;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
||||||
using InnovEnergy.Lib.StatusApi.Connections;
|
using InnovEnergy.Lib.Units.Composite;
|
||||||
|
using static DecimalMath.DecimalEx;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
public class AmptCommunicationUnit
|
public class AmptCommunicationUnit
|
||||||
{
|
{
|
||||||
private ModbusTcpClient Modbus { get; }
|
private ModbusTcpClient? Modbus { get; set; }
|
||||||
|
|
||||||
private const Int32 RegistersPerDevice = 16;
|
private const UInt16 RegistersPerDevice = 16;
|
||||||
private const Int32 FirstDeviceOffset = 85;
|
private const UInt16 FirstDeviceOffset = 85;
|
||||||
|
|
||||||
|
public String Hostname { get; }
|
||||||
|
public UInt16 Port { get; }
|
||||||
|
public Byte SlaveAddress { get; }
|
||||||
|
|
||||||
|
|
||||||
public AmptCommunicationUnit(String hostname, UInt16 port = 502, Byte slaveAddress = 1)
|
public AmptCommunicationUnit(String hostname, UInt16 port = 502, Byte slaveAddress = 1)
|
||||||
{
|
{
|
||||||
var connection = new ModbusTcpConnection(hostname, port);
|
Hostname = hostname;
|
||||||
Modbus = new ModbusTcpClient(connection, slaveAddress);
|
Port = port;
|
||||||
|
SlaveAddress = slaveAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AmptStatus? ReadStatus()
|
public AmptCommunicationUnitStatus? ReadStatus()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return TryReadStatus();
|
var modbus = OpenConnection();
|
||||||
|
return TryReadStatus(modbus);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch
|
||||||
{
|
{
|
||||||
Modbus.CloseConnection();
|
Modbus?.CloseConnection();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AmptStatus TryReadStatus()
|
|
||||||
{
|
|
||||||
// Console.WriteLine("Reading Ampt Device");
|
|
||||||
|
|
||||||
var r = Modbus.ReadHoldingRegisters(1, 116);
|
|
||||||
|
|
||||||
var currentFactor = DecimalEx.Pow(10.0m, r.GetInt16(73));
|
private ModbusTcpClient OpenConnection()
|
||||||
var voltageFactor = DecimalEx.Pow(10.0m, r.GetInt16(74));
|
{
|
||||||
var energyFactor = DecimalEx.Pow(10.0m, r.GetInt16(76) + 3); // +3 => converted from Wh to kWh
|
if (Modbus is null)
|
||||||
|
{
|
||||||
|
var connection = new ModbusTcpConnection(Hostname, Port);
|
||||||
|
Modbus = new ModbusTcpClient(connection, SlaveAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Modbus;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AmptCommunicationUnitStatus TryReadStatus(ModbusTcpClient modbus)
|
||||||
|
{
|
||||||
|
var r = modbus.ReadHoldingRegisters(1, 116);
|
||||||
|
|
||||||
|
var currentFactor = Pow(10.0m, r.GetInt16(73));
|
||||||
|
var voltageFactor = Pow(10.0m, r.GetInt16(74));
|
||||||
|
var energyFactor = Pow(10.0m, r.GetInt16(76) + 3); // +3 => converted from Wh to kWh
|
||||||
var nbrOfDevices = r.GetUInt16(78);
|
var nbrOfDevices = r.GetUInt16(78);
|
||||||
|
|
||||||
var devices = Enumerable
|
var devices = Enumerable
|
||||||
|
@ -48,84 +62,45 @@ public class AmptCommunicationUnit
|
||||||
.Select(ReadDeviceStatus)
|
.Select(ReadDeviceStatus)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var amptSt = new AmptStatus
|
return new AmptCommunicationUnitStatus
|
||||||
(
|
|
||||||
Sid : r.GetUInt32(1),
|
|
||||||
IdSunSpec : r.GetUInt16(3),
|
|
||||||
Manufacturer : r.GetString(5, 16),
|
|
||||||
Model : r.GetString(21, 16),
|
|
||||||
Version : r.GetString(45, 8),
|
|
||||||
SerialNumber : r.GetString(53, 16),
|
|
||||||
DeviceAddress : r.GetInt16(69),
|
|
||||||
IdVendor : r.GetUInt16(71),
|
|
||||||
Devices : devices
|
|
||||||
// devices.d Current1 = r.GetInt16(90) * currentFactor,
|
|
||||||
// Current2 = r.GetInt16(106) * currentFactor,
|
|
||||||
// Voltage1 = r.GetUInt32(91) * voltageFactor,
|
|
||||||
// Voltage2 = r.GetUInt32(107) * voltageFactor
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return amptSt;
|
|
||||||
|
|
||||||
Decimal ReadDevicesVoltage(Int32 numberOfDevice)
|
|
||||||
{
|
{
|
||||||
var avgVoltage = 0.0m;
|
Sid = r.GetUInt32(1),
|
||||||
|
IdSunSpec = r.GetUInt16(3),
|
||||||
for (var i = 0; i < numberOfDevice; i++)
|
Manufacturer = r.GetString(5, 16),
|
||||||
|
Model = r.GetString(21, 16),
|
||||||
|
Version = r.GetString(45, 8),
|
||||||
|
SerialNumber = r.GetString(53, 16),
|
||||||
|
DeviceAddress = r.GetInt16(69),
|
||||||
|
IdVendor = r.GetUInt16(71),
|
||||||
|
Devices = devices
|
||||||
|
};
|
||||||
|
|
||||||
|
AmptStatus ReadDeviceStatus(Int32 deviceNumber)
|
||||||
|
{
|
||||||
|
var baseAddress = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address
|
||||||
|
|
||||||
|
return new AmptStatus
|
||||||
{
|
{
|
||||||
var b = (UInt16)(FirstDeviceOffset + i * RegistersPerDevice); // base address
|
Dc = new DcBus
|
||||||
|
|
||||||
avgVoltage+= r.GetUInt32((UInt16)(b + 6)) * voltageFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return avgVoltage / numberOfDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
Decimal ReadDevicesCurrent(Int32 numberOfDevice)
|
|
||||||
{
|
|
||||||
Decimal avgCurrent = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < numberOfDevice; i++)
|
|
||||||
{
|
|
||||||
var b = (UInt16)(FirstDeviceOffset + i * RegistersPerDevice); // base address
|
|
||||||
|
|
||||||
avgCurrent+= r!.GetUInt32((UInt16)(b + 5)) * voltageFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return avgCurrent / numberOfDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
AmptDeviceStatus ReadDeviceStatus(Int32 deviceNumber)
|
|
||||||
{
|
|
||||||
var b = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address
|
|
||||||
|
|
||||||
return new AmptDeviceStatus
|
|
||||||
(
|
|
||||||
Dc : new DcConnection
|
|
||||||
(
|
|
||||||
Voltage:r.GetUInt32((UInt16)(b + 6)) * voltageFactor,
|
|
||||||
Current:r.GetUInt16((UInt16)(b + 5)) * currentFactor
|
|
||||||
),
|
|
||||||
DeviceId : r.GetInt16 (b) ,
|
|
||||||
Timestamp : r.GetUInt32((UInt16)(b + 3)),
|
|
||||||
ProductionToday : r.GetUInt32((UInt16)(b + 12))* energyFactor,
|
|
||||||
|
|
||||||
Strings : new []
|
|
||||||
{
|
{
|
||||||
new DcConnection
|
Voltage = r.GetUInt32((UInt16)(baseAddress + 6)) * voltageFactor,
|
||||||
(
|
Current = r.GetUInt16((UInt16)(baseAddress + 5)) * currentFactor
|
||||||
Voltage : r.GetUInt32((UInt16)(b + 8)) * voltageFactor,
|
},
|
||||||
Current : r.GetUInt16((UInt16)(b + 14)) * currentFactor
|
Strings = new DcBus[]
|
||||||
),
|
{
|
||||||
new DcConnection
|
new()
|
||||||
(
|
{
|
||||||
Voltage : r.GetUInt32((UInt16)(b + 9)) * voltageFactor,
|
Voltage = r.GetUInt32((UInt16)(baseAddress + 8)) * voltageFactor,
|
||||||
Current : r.GetUInt16((UInt16)(b + 15)) * currentFactor
|
Current = r.GetUInt16((UInt16)(baseAddress + 14)) * currentFactor
|
||||||
)
|
},
|
||||||
}
|
new()
|
||||||
);
|
{
|
||||||
|
Voltage = r.GetUInt32((UInt16)(baseAddress + 9)) * voltageFactor,
|
||||||
|
Current = r.GetUInt16((UInt16)(baseAddress + 15)) * currentFactor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ProductionToday = r.GetUInt32((UInt16)(baseAddress + 12)) * energyFactor,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
|
public record AmptCommunicationUnitStatus
|
||||||
|
{
|
||||||
|
public UInt32 Sid { get; init; } // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map
|
||||||
|
public UInt16 IdSunSpec { get; init; } // A well-known value 1, uniquely identifies this as a SunSpec Common Model
|
||||||
|
|
||||||
|
public String Manufacturer { get; init; } = "undefined"; // A well-known value registered with SunSpec for compliance: "Ampt"
|
||||||
|
public String Model { get; init; } = "undefined"; // Manufacturer specific value "Communication Unit"
|
||||||
|
public String Version { get; init; } = "undefined"; // Software Version
|
||||||
|
public String SerialNumber { get; init; } = "undefined"; // Manufacturer specific value
|
||||||
|
public Int16 DeviceAddress { get; init; } // Modbus Device ID
|
||||||
|
public UInt16 IdVendor { get; init; } // Ampt SunSpec Vendor Code 64050
|
||||||
|
|
||||||
|
public IReadOnlyList<AmptStatus> Devices { get; init; } = Array.Empty<AmptStatus>();
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
using InnovEnergy.Lib.StatusApi.Connections;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
|
||||||
|
|
||||||
public record AmptDeviceStatus
|
|
||||||
(
|
|
||||||
DcConnection Dc,
|
|
||||||
// UInt16 NbrOfStrings,
|
|
||||||
Int16 DeviceId, // The string number
|
|
||||||
UInt32 Timestamp, // The UTC timestamp of the measurements
|
|
||||||
Decimal ProductionToday, // converted to kW in AmptCU class
|
|
||||||
IReadOnlyList<DcConnection> Strings
|
|
||||||
): MpptStatus(Dc, Strings)
|
|
||||||
{}
|
|
|
@ -1,24 +1,9 @@
|
||||||
|
using InnovEnergy.Lib.StatusApi;
|
||||||
|
using InnovEnergy.Lib.Units;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
public record AmptStatus
|
public record AmptStatus : MpptStatus
|
||||||
(
|
|
||||||
UInt32 Sid, // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map
|
|
||||||
UInt16 IdSunSpec, // A well-known value 1, uniquely identifies this as a SunSpec Common Model
|
|
||||||
// UInt16 L, // Well-known # of 16-bit registers to follow : 66
|
|
||||||
String? Manufacturer, // A well-known value registered with SunSpec for compliance: "Ampt"
|
|
||||||
String? Model, // Manufacturer specific value "Communication Unit"
|
|
||||||
String? Version, // Software Version
|
|
||||||
String? SerialNumber, // Manufacturer specific value
|
|
||||||
Int16 DeviceAddress, // Modbus Device ID
|
|
||||||
UInt16 IdVendor, // Ampt SunSpec Vendor Code 64050
|
|
||||||
// Decimal Current1,
|
|
||||||
// Decimal Current2,
|
|
||||||
// Decimal Voltage1,
|
|
||||||
// Decimal Voltage2,
|
|
||||||
IReadOnlyList<AmptDeviceStatus> Devices
|
|
||||||
//internal const UInt16 StartRegister = 1;
|
|
||||||
//internal const UInt16 TotalNbOfRegister = 116;
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
public Energy ProductionToday { get; init; } // converted to kW in AmptCU class
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
|
||||||
|
|
||||||
public record AmptStringStatus
|
|
||||||
{
|
|
||||||
public Decimal Voltage { get; init; }
|
|
||||||
public Decimal Current { get; init; }
|
|
||||||
}
|
|
Loading…
Reference in New Issue