Innovenergy_trunk/csharp/Lib/Devices/AMPT/AmptDevices.cs

129 lines
4.0 KiB
C#
Raw Normal View History

2023-06-13 10:53:37 +00:00
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);
2023-08-15 13:05:26 +00:00
_StringOptimizers = StringOptimizers(modbusClient);
2023-06-13 10:53:37 +00:00
}
2023-08-25 15:15:46 +00:00
public AmptStatus? Read()
2023-06-13 10:53:37 +00:00
{
try
{
2023-08-25 15:15:46 +00:00
return TryRead();
2023-06-13 10:53:37 +00:00
}
2023-10-23 08:05:06 +00:00
catch ( Exception e)
2023-06-13 10:53:37 +00:00
{
2023-10-23 08:05:06 +00:00
if( e is not NullChannelException)
Console.WriteLine("Failed to read Ampt data \n" + e.Message);
2023-08-25 15:15:46 +00:00
return null;
2023-06-13 10:53:37 +00:00
}
2023-08-25 15:15:46 +00:00
}
public AmptStatus TryRead()
{
var cuStatus = _CommunicationUnit.Read();
2023-06-13 10:53:37 +00:00
// CommunicationUnit knows how many StringOptimizers are connected
2023-08-25 15:15:46 +00:00
var nStringOptimizers = cuStatus.NumberOfStringOptimizers;
2023-06-13 10:53:37 +00:00
2024-01-19 11:32:43 +00:00
//Factor
var nEnergyFactor = cuStatus.EnergyScaleFactor;
2024-01-19 11:32:43 +00:00
var nCurrentFactor = cuStatus.CurrentScaleFactor;
var nVoltageFactor = cuStatus.VoltageScaleFactor;
2023-06-13 10:53:37 +00:00
// 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
2024-01-19 11:32:43 +00:00
var busVoltage = nStringOptimizers == 0 ? 0 : soStati.Average(r => r.Voltage);
var busCurrent = nStringOptimizers == 0 ? 0 : soStati.Sum (r => r.Current);
var dailyOutputEnergy = nStringOptimizers == 0 ? 0 : soStati.Sum (r => r.ProductionToday);
2023-08-31 12:16:09 +00:00
var dc = new DcBus
{
Voltage = busVoltage,
2024-01-19 11:32:43 +00:00
Current = busCurrent
2023-08-31 12:16:09 +00:00
};
2023-06-13 10:53:37 +00:00
// flatten the 2 strings of each SO into one array
2023-08-25 15:15:46 +00:00
var strings = soStati.SelectMany(GetStrings).ToArray(nStrings);
2023-06-13 10:53:37 +00:00
2023-08-25 15:15:46 +00:00
return new AmptStatus
{
Dc = dc,
2024-06-10 12:59:42 +00:00
NbrOfStrings = nStringOptimizers,
2024-01-19 11:32:43 +00:00
Strings = strings,
DcWh = dailyOutputEnergy
2023-08-25 15:15:46 +00:00
};
2023-06-13 10:53:37 +00:00
}
private static IEnumerable<DcBus> GetStrings(StringOptimizerRegisters r)
{
// hardcoded: every SO has 2 strings (produced like this by AMPT)
2023-08-31 12:16:09 +00:00
yield return new()
{
Voltage = r.String1Voltage,
Current = r.String1Current,
};
yield return new()
{
Voltage = r.String2Voltage,
Current = r.String2Current,
};
2023-06-13 10:53:37 +00:00
}
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);
}
}