Ampt V2
This commit is contained in:
parent
eeaefb0f54
commit
fd92374a4f
|
@ -1,67 +0,0 @@
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
|
|
||||||
using InnovEnergy.Lib.Units.Composite;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
|
||||||
|
|
||||||
public class AmptDevice
|
|
||||||
{
|
|
||||||
private readonly ModbusDevice<CommunicationUnitRegisters> _CommunicationUnit;
|
|
||||||
private readonly IEnumerable<ModbusDevice<StringOptimizerRegisters>> _StringOptimizers;
|
|
||||||
|
|
||||||
public AmptDevice(ModbusClient modbusClient)
|
|
||||||
{
|
|
||||||
_CommunicationUnit = new ModbusDevice<CommunicationUnitRegisters>(modbusClient);
|
|
||||||
_StringOptimizers = StringOptimizers(modbusClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public AmptStatus? Read()
|
|
||||||
{
|
|
||||||
var cuStatus = _CommunicationUnit.Read();
|
|
||||||
|
|
||||||
if (cuStatus.NumberOfStrings == 0)
|
|
||||||
return default;
|
|
||||||
|
|
||||||
var rs = _StringOptimizers
|
|
||||||
.Take(cuStatus.NumberOfStrings)
|
|
||||||
.Select(so => so.Read())
|
|
||||||
.ToArray(cuStatus.NumberOfStrings);
|
|
||||||
|
|
||||||
var busVoltage = rs.Average(r => r.Voltage);
|
|
||||||
var busCurrent = rs.Sum(r => r.Current);
|
|
||||||
var strings = rs.SelectMany(GetStrings).ToArray(rs.Length * 2);
|
|
||||||
|
|
||||||
return new AmptStatus
|
|
||||||
(
|
|
||||||
Dc : DcBus.FromVoltageCurrent(busVoltage, busCurrent),
|
|
||||||
Strings: strings
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<DcBus> GetStrings(StringOptimizerRegisters r)
|
|
||||||
{
|
|
||||||
yield return DcBus.FromVoltageCurrent(r.String1Voltage, r.String1Current);
|
|
||||||
yield return DcBus.FromVoltageCurrent(r.String2Voltage, r.String2Current);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static IEnumerable<ModbusDevice<StringOptimizerRegisters>> StringOptimizers(ModbusClient modbusClient)
|
|
||||||
{
|
|
||||||
var cache = new List<ModbusDevice<StringOptimizerRegisters>>();
|
|
||||||
|
|
||||||
ModbusDevice<StringOptimizerRegisters> GetOptimizer(Int32 i)
|
|
||||||
{
|
|
||||||
if (i < cache.Count)
|
|
||||||
return cache[i];
|
|
||||||
|
|
||||||
var modbusDevice = new ModbusDevice<StringOptimizerRegisters>(modbusClient, i * 16);
|
|
||||||
return modbusDevice.Apply(cache.Add);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enumerable
|
|
||||||
.Range(0, Byte.MaxValue)
|
|
||||||
.Select(GetOptimizer);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
|
||||||
|
using InnovEnergy.Lib.Units.Composite;
|
||||||
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
|
public class AmptDevices
|
||||||
|
{
|
||||||
|
private readonly ModbusDevice<CommunicationUnitRegisters> _CommunicationUnit;
|
||||||
|
private readonly IEnumerable<ModbusDevice<StringOptimizerRegisters>> _StringOptimizers;
|
||||||
|
|
||||||
|
public AmptDevices(String hostname, UInt16 port = 502) : this(new TcpChannel(hostname, port))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AmptDevices(Channel transport) : this(new ModbusTcpClient(transport, 2))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AmptDevices(ModbusClient modbusClient)
|
||||||
|
{
|
||||||
|
_CommunicationUnit = new ModbusDevice<CommunicationUnitRegisters>(modbusClient);
|
||||||
|
_StringOptimizers = StringOptimizers(modbusClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AmptStatus Read()
|
||||||
|
{
|
||||||
|
CommunicationUnitRegisters? cuStatus = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cuStatus = _CommunicationUnit.Read();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
// TODO: log
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommunicationUnit knows how many StringOptimizers are connected
|
||||||
|
var nStringOptimizers = cuStatus?.NumberOfStringOptimizers ?? 0;
|
||||||
|
|
||||||
|
// hardcoded: every SO has 2 strings (produced like this by AMPT)
|
||||||
|
var nStrings = nStringOptimizers * 2;
|
||||||
|
|
||||||
|
// read stati from optimizers
|
||||||
|
var soStati = _StringOptimizers
|
||||||
|
.Take(nStringOptimizers)
|
||||||
|
.Select(so => so.Read())
|
||||||
|
.ToArray(nStringOptimizers);
|
||||||
|
|
||||||
|
// every SO has 2 strings but ONE Dc Link Connection
|
||||||
|
// they are connected to a shared Dc Link, so Voltage seen by them should be approx the same.
|
||||||
|
// voltages are averaged, currents added
|
||||||
|
|
||||||
|
// TODO: alarm when we see substantially different voltages
|
||||||
|
|
||||||
|
var busVoltage = nStringOptimizers == 0 ? 0 : soStati.Average(r => r.Voltage);
|
||||||
|
var busCurrent = nStringOptimizers == 0 ? 0 : soStati.Sum (r => r.Current);
|
||||||
|
var dc = DcBus.FromVoltageCurrent(busVoltage, busCurrent);
|
||||||
|
|
||||||
|
// flatten the 2 strings of each SO into one array
|
||||||
|
var strings = soStati.SelectMany(GetStrings).ToArray(nStrings);
|
||||||
|
|
||||||
|
return new AmptStatus(dc, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<DcBus> GetStrings(StringOptimizerRegisters r)
|
||||||
|
{
|
||||||
|
// hardcoded: every SO has 2 strings (produced like this by AMPT)
|
||||||
|
|
||||||
|
yield return DcBus.FromVoltageCurrent(r.String1Voltage, r.String1Current);
|
||||||
|
yield return DcBus.FromVoltageCurrent(r.String2Voltage, r.String2Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<ModbusDevice<StringOptimizerRegisters>> StringOptimizers(ModbusClient modbusClient)
|
||||||
|
{
|
||||||
|
var cache = new List<ModbusDevice<StringOptimizerRegisters>>();
|
||||||
|
|
||||||
|
ModbusDevice<StringOptimizerRegisters> GetOptimizer(Int32 i)
|
||||||
|
{
|
||||||
|
if (i < cache.Count)
|
||||||
|
return cache[i];
|
||||||
|
|
||||||
|
var modbusDevice = new ModbusDevice<StringOptimizerRegisters>(modbusClient, i * 16);
|
||||||
|
cache.Add(modbusDevice);
|
||||||
|
return modbusDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enumerable
|
||||||
|
.Range(0, Byte.MaxValue)
|
||||||
|
.Select(GetOptimizer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,35 @@ using InnovEnergy.Lib.Units.Composite;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
public record AmptStatus(DcBus Dc, IReadOnlyList<DcBus> Strings) : IMppt;
|
public class AmptStatus : IMppt
|
||||||
|
{
|
||||||
|
public AmptStatus(DcBus dc, IReadOnlyList<DcBus> strings)
|
||||||
|
{
|
||||||
|
Dc = dc;
|
||||||
|
Strings = strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DcBus Dc { get; }
|
||||||
|
public IReadOnlyList<DcBus> Strings { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public static AmptStatus Parallel(IReadOnlyList<AmptStatus> stati)
|
||||||
|
// {
|
||||||
|
// if (stati.Count == 0)
|
||||||
|
// {
|
||||||
|
// return new AmptStatus
|
||||||
|
// (
|
||||||
|
// Dc: DcBus.FromVoltageCurrent(0, 0),
|
||||||
|
// Strings: Array.Empty<DcBus>()
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var voltage = stati.Average(s => s.Dc.Voltage.Value);
|
||||||
|
// var current = stati.Sum(s => s.Dc.Current.Value);
|
||||||
|
// var dc = DcBus.FromVoltageCurrent(voltage, current);
|
||||||
|
//
|
||||||
|
// var strings = stati.SelectMany(s => s.Strings).ToList();
|
||||||
|
//
|
||||||
|
// return new AmptStatus(dc, strings);
|
||||||
|
// }
|
|
@ -14,5 +14,5 @@ public record CommunicationUnitRegisters
|
||||||
[HoldingRegister<Int16>(74)] public Int16 VoltageScaleFactor { get; private set; }
|
[HoldingRegister<Int16>(74)] public Int16 VoltageScaleFactor { get; private set; }
|
||||||
[HoldingRegister<Int16>(76)] public Int16 EnergyScaleFactor { get; private set; }
|
[HoldingRegister<Int16>(76)] public Int16 EnergyScaleFactor { get; private set; }
|
||||||
|
|
||||||
[HoldingRegister(78)] public UInt16 NumberOfStrings { get; private set; }
|
[HoldingRegister(78)] public UInt16 NumberOfStringOptimizers { get; private set; }
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Text.Json;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
|
using InnovEnergy.Lib.Units;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
@ -11,15 +11,14 @@ public static class Program
|
||||||
{
|
{
|
||||||
var ch = new TcpChannel("localhost", 5005);
|
var ch = new TcpChannel("localhost", 5005);
|
||||||
var cl = new ModbusTcpClient(ch, 1);
|
var cl = new ModbusTcpClient(ch, 1);
|
||||||
var d = new AmptDevice(cl);
|
var d = new AmptDevices(cl);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var x = d.Read();
|
AmptStatus x = d.Read();
|
||||||
|
|
||||||
|
x.ToCsv().WriteLine();
|
||||||
|
|
||||||
var options = new JsonSerializerOptions{WriteIndented = true};
|
|
||||||
(x, options).Apply(JsonSerializer.Serialize).WriteLine();
|
|
||||||
|
|
||||||
//Console.WriteLine(x);
|
//Console.WriteLine(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue