Trumpf V2

This commit is contained in:
ig 2023-06-13 13:01:01 +02:00
parent a2f5286e45
commit 9c2a8d0966
91 changed files with 2034 additions and 1523 deletions

View File

@ -1,84 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
public record ControlRecord
{
private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromSeconds(10);
// TODO
// public UInt32 Date { get; init;}
// public UInt32 Time { get; init;}
// public UInt32 IpAddress { get; init;} //= 0x C0A80102;
// public UInt32 Subnet { get; init;} //= 0x FFFFFF00;
// public UInt32 Gateway { get; init;} //= 0x C0A80102;
// public Boolean ResetParamToDefault { get; init;} = false ; // Coil
// public TimeSpan CommunicationTimeout { get; init;} = DefaultCommunicationTimeOut;
// public Boolean FactoryResetParameters { get; init;} = false;
// public SystemConfig ConnectedSystemConfig { get; init;} = 0;
// public UInt16 UpdateSwTrigger { get; init;} = 0;
// public UInt16 AutomaticSwUpdate { get; init;} = 0;
// public UInt16 CustomerValuesSaveReset { get; init;} = 0;
// public UInt16 SerialNumberSystemControl { get; init;} = 0;
// public UInt16 SerialNumberAcDc { get; init;} = 0;
// public UInt16 IntegrationLevel { get; init;} = 0;
// public UInt16 IlBuildnumber { get; init;} = 0;
// public Boolean PowerStageEnable { get; init;} = true;
// public SymmetricAcOperationMode SetValueConfig { get; init;} = 0;
// public Boolean ResetsAlarmAndWarning { get; init;} = false;
// public PreChargeDcLinkConfig PreChargeDcLinkConfig { get; init;} = (PreChargeDcLinkConfig)0;
// public PowerFactorConvention PowerFactorConvention { get; init;} = 0; //0 = producer
// public UInt16 SlaveAddress { get; init;} = Slave.Broadcast;
// public ErrorPolicy ErrorHandlingPolicy { get; init;} = 0;
// public AcDcGridType GridType { get; init;} = 0;
// public UInt16 SubSlaveAddress { get; init;} = 0;
// public Boolean UseModbusSlaveIdForAddressing { get; init;} = false;
// public UInt16 SubSlaveErrorPolicy { get; init;} = 0; // must be an enum
// public Decimal SignedPowerNominalValue { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal SignedPowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal SignedPowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal SignedPowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal PowerSetValue { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal PowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal PowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal PowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva,
// public Decimal MaximumGridCurrentRmsL1 { get; init;} = 0; // resolution : 0.01
// public Decimal MaximumGridCurrentRmsL2 { get; init;} = 0; // resolution : 0.01
// public Decimal MaximumGridCurrentRmsL3 { get; init;} = 0; // resolution : 0.01
// public Decimal CosPhiSetValueL1 { get; init;} = 0; // resolution : 0.01
// public Decimal CosPhiSetValueL2 { get; init;} = 0; // resolution : 0.01
// public Decimal CosPhiSetValueL3 { get; init;} = 0; // resolution : 0.01
// public Boolean PhaseL1IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
// public Boolean PhaseL2IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
// public Boolean PhaseL3IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
// public Boolean PhasesAreCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
// public Double SetPointCosPhi { get; init;} = 0; // resolution 0.01
// public Double SetPointSinPhi { get; init;} = 0; // resolution 0.01
// public Double SetPointSinPhiL1 { get; init;} = 0; // resolution 0.01
// public Double SetPointSinPhiL2 { get; init;} = 0; // resolution 0.01
// public Double SetPointSinPhiL3 { get; init;} = 0; // resolution 0.01
// public Decimal FrequencyOffsetIm { get; init;} = 0; // resolution 0.01
// public UInt16 VoltageAdjustmentFactorIm { get; init;} = 0;
// public UInt16 PreChargeDcLinkVoltage { get; init;} = 0;
// public Decimal MaxPeakCurrentVoltageControlL1 { get; init;} = 0; // resolution 0.01
// public Decimal MaxPeakCurrentVoltageControlL2 { get; init;} = 0; // resolution 0.01
// public Decimal MaxPeakCurrentVoltageControlL3 { get; init;} = 0; // resolution 0.01
// public UInt16 GridFormingMode { get; init;} = 1; // 0 = not grid-forming (grid-tied) ,1 = grid-forming
// public UInt16 DcLinkRefVoltage { get; init;} = 800;
// public UInt16 DcLinkMinVoltage { get; init;} = 780;
// public UInt16 DcLinkMaxVoltage { get; init;} = 820;
// public UInt16 DcVoltageRefUs { get; init;} = 900;
// public UInt16 DcMinVoltageUs { get; init;} = 880;
// public UInt16 DcMaxVoltageUs { get; init;} = 920;
// // Need to discuss this with Ivo
// // public UInt16 FrequencySlopeIslandMode { get; init;} = 200; // resolution 0.01
// // public UInt16 VoltageSlopeIslandMode { get; init;} = 500; // resolution 0.01
// public UInt16 AcDcGcBypassMode { get; init;} = 0;
// public UInt16 AcDcGcPMaxThresholdPercent { get; init;} = 0; // resolution 0.01
// public UInt16 AcDcGcStartupRampEnable { get; init;} = 0;
// public DcStageConfiguration DcConfigModule { get; init;} = 0; // this must be an enum
// public UInt16 DcDcPowerDistribution { get; init;} = 0; // 0.1 resolution
// public AcDcDistributionMode AcDcDistributionMode { get; init;} = 0;
}

View File

@ -1,18 +1,18 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public enum AlarmMessage
public enum AlarmMessage : UInt16
{
NoAlarm = 0,
BmsCommunicationTimeoutHasOccured = 40302, // BMS communication timeout has occured.
Rs485CommunicationAlarm = 40303, // RS-485 communication alarm.
NoSlaveModuleWasFoundPleaseCheckRs485Connection = 40304, // No slave module was found, please check RS-485 connection(s).
NumberOfOrCombinationOfConnectedSlaveTypesNotSupported = 40305, // Number of or combination of connected slave types not supported.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch1 = 40412, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch2 = 40413, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch3 = 40414, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch4 = 40415, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch5 = 40416, // Software versions of system control and module(s) do not match.
NoSlaveModuleWasFoundPleaseCheckRs485Connection = 40304, // No slave module was found, please check RS-485 connection(s).
NumberOfOrCombinationOfConnectedSlaveTypesNotSupported = 40305, // Number of or combination of connected slave types not supported.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch5 = 40416, // Software versions of system control and module(s) do not match.
}

View File

@ -1,6 +1,6 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum MainState : UInt16
public enum DeviceState : UInt16
{
PowerUp = 0,
Alarm = 1,

View File

@ -1,6 +1,6 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum AcDcGridType : UInt16
public enum GridType : UInt16
{
GridTied400V50Hz = 0, // grid-tied, 400V, 50Hz
GridTied480V60Hz = 1, // grid-tied, 480V, 60Hz

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum PowerSetPointActivation : UInt16
{
Immediate = 0,
Trigger = 1,
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum PowerSetPointTrigger : UInt16
{
Wait = 0,
Trigger = 1,
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum ReferenceFrame : UInt16
{
Producer = 0,
Consumer = 1,
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum SlaveErrorHandling : UInt16
{
Relaxed = 0, // System keeps running even if some slaves are in error state.
Strict = 1, // System shuts down as soon as one component is in error state.
}

View File

@ -0,0 +1,8 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum SubSlaveErrorHandling : UInt16
{
Strict = 0, // SystemControl switches to error state if at least one submodules is in error state
Relaxed = 1, // SystemControl switches to error state if all submodules are in error state.
Off = 2, // If possible AC-DC module continues operation even if all submodules are in error state.
}

View File

@ -1,9 +1,9 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
public enum SystemConfig : UInt16
{
NoConfig = 0,
Simulator = 1,
DcDcOnly = 2,
AcDcAndDcDc = 3,
AcDcAndDcDc = 3
}

View File

@ -0,0 +1,10 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public enum WarningMessage : UInt16
{
NoWarning = 0,
// TODO: ???
}

View File

@ -1,7 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
public enum ErrorPolicy : UInt16
{
Relaxed = 0, // 0 = relaxed (System keeps running even if some slaves are in error state.)
Strict = 1, // 1 = strict (System shuts down as soon as one component is in error state.)
}

View File

@ -0,0 +1,46 @@
// using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
// using InnovEnergy.Lib.Utils;
//
// namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
//
// // TODO: remove
//
// public static class Program
// {
// public static void Main(String[] args)
// {
// var d = new SystemControlDevice("localhost", 5001);
//
// while (true)
// {
// var r = d.Read();
//
// Console.WriteLine(DateTime.Now);
// r.ToString().Replace(",", "\n").Replace(" {", "\n").WriteLine();
//
// "Alarms".WriteLine();
// r.Alarms.Count.WriteLine();
// r.Alarms.Select(a => a.ToString()).JoinLines().WriteLine();
//
// "Warnings".WriteLine();
// r.NumberOfWarnings.WriteLine();
// r.Warnings.Select(a => a.ToString()).JoinLines().WriteLine();
//
// var c = r with
// {
// UseSlaveIdForAddressing = true,
// ReferenceFrame = ReferenceFrame.Consumer,
// GridType = GridType.GridTied400V50Hz,
// SystemConfig = SystemConfig.AcDcAndDcDc,
// CommunicationTimeout = null,
// SlaveErrorHandling = SlaveErrorHandling.Relaxed,
// SubSlaveErrorHandling = SubSlaveErrorHandling.Off
// };
//
//
//
// d.Write(c);
//
// }
// }
// }

View File

@ -1,43 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using AlarmMessages = IReadOnlyList<AlarmMessage>;
using WarningMessages = IReadOnlyList<WarningMessage>;
// ReSharper disable UnusedAutoPropertyAccessor.Global
#pragma warning disable CS8618
public record StatusRecord
{
// TODO
// public MainState MainState { get; init; }
// public String SerialNumber { get; init; }
// public AcDcGridType GridType { get; init; }
// public WarningMessages Warnings { get; init; }
// public AlarmMessages Alarms { get; init; }
// public Decimal NumberOfConnectedSlaves { get; init; }
// public Decimal NumberOfConnectedSubSlaves { get; init; }
// public Frequency AcDcNominalGridFrequency { get; init; }
// public Voltage AcDcNominalGridVoltage { get; init; }
// public Power AcDcActNominalPower { get; init; }
// public Decimal AcDcPowerLimitingStatusAct { get; init; } // TODO: enum
// public Voltage AcDcDcVoltageReference { get; init; }
// public Voltage AcDcDcLinkVoltageMinAct { get; init; }
// public Voltage AcDcDcLinkVoltageMaxAct { get; init; }
// public Voltage AcDcDcLinkChargedMinVoltage { get; init; }
// public Decimal AcDcStmActCustomer { get; init; }
// public Decimal AcDcOverloadIntegratorStatusL1 { get; init; }
// public Decimal AcDcOverloadIntegratorStatusL2 { get; init; }
// public Decimal AcDcOverloadIntegratorStatusL3 { get; init; }
// public Power AcSignedPowerValue { get; init; }
// public Voltage ActualDcLinkVoltageUpperHalf { get; init; }
// public Voltage ActualDcLinkVoltageLowerHalf { get; init; }
// public Voltage ActualDcLinkVoltageUpperHalfExt { get; init; }
// public Voltage ActualDcLinkVoltageLowerHalfExt { get; init; }
// public Voltage VoltageIntNtoPe { get; init; }
// public Voltage VoltageExtNtoPe { get; init; }
// public Temperature InletAirTemperature { get; init; }
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
public enum SubSlavesErrorPolicy : UInt16
{
Strict = 0, // (AC-DC module switches to error state if at least one submodules is in error state
Relaxed = 1, // (AC-DC module switches to error state if all submodules are in error state.)
Off = 2, // (If possible AC-DC module continues operation even if all submodules are in error state.
}

View File

@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configurations>Debug;Release;Release-Server</Configurations>
<Platforms>AnyCPU;linux-arm</Platforms>
</PropertyGroup>
<Import Project="../../../InnovEnergy.Lib.props" />
<Import Project="../../../InnovEnergy.Lib.props" />
<!-- <Import Project="../../../../App/InnovEnergy.App.props" />-->
<ItemGroup>
<ProjectReference Include="..\..\..\Protocols\Modbus\Modbus.csproj" />
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Protocols.Modbus.Channels;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.Utils;
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.SystemControlRegisters;
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
@ -10,315 +9,21 @@ namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class SystemControlDevice
{
private ModbusTcpClient ModbusTcpClient { get; }
private readonly ModbusDevice<SystemControlRegisters> _SystemControlSlave;
public Channel Channel { get; }
public SystemControlDevice(String hostname, UInt16 port = ModbusTcpClient.DefaultPort, Byte slaveAddress = 0)
public SystemControlDevice(String hostname, Int32 port = 502) : this(new TcpChannel(hostname, port))
{
var connection = new ModbusTcpConnection(hostname, port);
ModbusTcpClient = new ModbusTcpClient(connection, slaveAddress);
}
public void WriteControl(ControlRecord c)
{
/*
WriteRegs(AcControlRegisters.Date, new List<UInt16> { c.Date.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Time, new List<UInt16> { c.Time.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.IpAddress, new List<UInt16> { c.IpAddress.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Subnet, new List<UInt16> { c.Subnet.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Gateway, new List<UInt16> { c.Gateway.ConvertTo<UInt16>()});
WriteCoils(AcControlRegisters.ResetParamToDefault, c.ResetParamToDefault);
WriteCoils(AcControlRegisters.FactoryResetParameters, c.FactoryResetParameters);
ModbusTcpClient.WriteRegisters(AcControlRegisters.UpdateSwTrigger, c.UpdateSwTrigger, c.AutomaticSwUpdate, c.CustomerValuesSaveReset);
*/
WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo<UInt16>());
WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig);
WriteCoils(PowerStageConfig, c.PowerStageEnable,
c.SetValueConfig.ConvertTo<Boolean>(),
c.ResetsAlarmAndWarning);
WriteRegs(PreChargeDcLinkConfigR, c.PreChargeDcLinkConfig,
c.PowerFactorConvention, c.SlaveAddress,
c.ErrorHandlingPolicy,
c.GridType, c.SubSlaveAddress);
WriteCoils(ModbusSlaveId, c.UseModbusSlaveIdForAddressing);
WriteRegs(SubSlaveErrorPolicy, c.SubSlaveErrorPolicy);
WriteRegs(SignedPowerNominalValue, -1.0m, c.SignedPowerNominalValue);/*, c.SignedPowerSetValueL1,
c.SignedPowerSetValueL2, c.SignedPowerSetValueL3,
c.PowerSetValue, c.PowerSetValueL1,
c.PowerSetValueL2, c.PowerSetValuesL3);*/
WriteRegs(MaximumGridCurrentRmsL1, 0.01m, c.MaximumGridCurrentRmsL1, c.MaximumGridCurrentRmsL2,
c.MaximumGridCurrentRmsL3, c.CosPhiSetValueL1,
c.CosPhiSetValueL2, c.CosPhiSetValueL3);
WriteCoils(PhaseL1IsCapacitive, c.PhaseL1IsCapacitive,
c.PhaseL2IsCapacitive,
c.PhaseL3IsCapacitive,
c.PhasesAreCapacitive);
/* WriteRegs(SetPointCosPhi, 0.01m, c.SetPointCosPhi.ConvertTo<UInt16>(),
c.SetPointSinPhi.ConvertTo<UInt16>(),
c.SetPointSinPhiL1.ConvertTo<UInt16>(),
c.SetPointSinPhiL2.ConvertTo<UInt16>(),
c.SetPointSinPhiL3.ConvertTo<UInt16>(),
c.FrequencyOffsetIm);*/
WriteRegs(VoltageAdjustmentFactorIm, c.VoltageAdjustmentFactorIm);
WriteRegs(PreChargeDcLinkVoltage, c.PreChargeDcLinkVoltage);
WriteRegs(MaxPeakCurrentVoltageControlL1, 0.01m, c.MaxPeakCurrentVoltageControlL1,
c.MaxPeakCurrentVoltageControlL2,
c.MaxPeakCurrentVoltageControlL3);
WriteRegs(GridFormingMode, c.GridFormingMode, c.DcLinkRefVoltage,
c.DcLinkMinVoltage, c.DcLinkMaxVoltage,
c.DcVoltageRefUs, c.DcMinVoltageUs, c.DcMaxVoltageUs);
WriteRegs(AcDcGcBypassMode, c.AcDcGcBypassMode);
WriteRegs(AcDcGcPMaxThresholdPercent, 0.01m, c.AcDcGcPMaxThresholdPercent);
WriteRegs(AcDcGcStartupRampEnable, c.AcDcGcStartupRampEnable);
WriteRegs(DcConfigModule, c.DcConfigModule);
WriteRegs(DcDcPowerDistribution, 0.1m, c.DcDcPowerDistribution);
WriteRegs(SystemControlRegisters.AcDcDistributionMode, c.AcDcDistributionMode);
}
private void WriteRegs (UInt16 a, Decimal res = 1.0m, params Decimal[] regs) => ModbusTcpClient.WriteRegisters(a, regs.ToUInt16(res));
private void WriteRegs (UInt16 a, params IConvertible[] regs) => ModbusTcpClient.WriteRegisters(a, regs.Select(v => v.ConvertTo<UInt16>()).ToArray());
private void WriteRegs (UInt16 a, params UInt16[] regs) => ModbusTcpClient.WriteRegisters(a, regs);
private void WriteCoils(UInt16 a, params Boolean[] coils) => ModbusTcpClient.WriteMultipleCoils(a, coils);
private static Decimal GetPhi(Decimal cosPhi) => cosPhi.Clamp(-1m, 1m).Apply(ACos);
public StatusRecord? ReadStatus()
public SystemControlDevice(Channel channel)
{
try
{
return TryReadStatus();
}
catch (Exception e)
{
ModbusTcpClient.CloseConnection();
Console.WriteLine("Failed to read inverter status");
e.Message.WriteLine();
return null;
}
Channel = channel;
var tcpClient = new ModbusTcpClient(channel, 0);
_SystemControlSlave = new ModbusDevice<SystemControlRegisters>(tcpClient);
}
private StatusRecord TryReadStatus()
{
// Console.WriteLine("Reading Ac Device");
var acSerialNumber = ModbusTcpClient.ReadInputRegisters(2009, 2);
var acActualMain = ModbusTcpClient.ReadInputRegisters(5001, 3);
var acActualAcDc = ModbusTcpClient.ReadInputRegisters(5021, 9);
var acActualAcDc2 = ModbusTcpClient.ReadInputRegisters(5031, 1);
var acActualAcDc3 = ModbusTcpClient.ReadInputRegisters(5131, 6);
var acActualMeasurement = ModbusTcpClient.ReadInputRegisters(5141, 3);
var acActualMeasurement1 = ModbusTcpClient.ReadInputRegisters(5151, 3);
var acActualMeasurement2 = ModbusTcpClient.ReadInputRegisters(5161, 3);
var acActualMeasurement3 = ModbusTcpClient.ReadInputRegisters(5171, 3);
var acActualMeasurement4 = ModbusTcpClient.ReadInputRegisters(5187, 2);
var acActualMeasurement5 = ModbusTcpClient.ReadInputRegisters(5189, 2);
var acActualMeasurement6 = ModbusTcpClient.ReadInputRegisters(5191, 2);
var acActualMeasurement7 = ModbusTcpClient.ReadInputRegisters(5201, 1);
var acActualMeasurement8 = ModbusTcpClient.ReadInputRegisters(5211, 4);
var acActualMeasurement9 = ModbusTcpClient.ReadInputRegisters(5221, 2);
var acActualTemp = ModbusTcpClient.ReadInputRegisters(5501, 1);
var acWarningValues = ModbusTcpClient.ReadInputRegisters(2402, 22);
var acAlarmValues = ModbusTcpClient.ReadInputRegisters(2809, 22);
var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1);
var warnings = Enumerable
.Range(2404, 20)
.Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo<WarningMessage>())
.ToArray();
var alarms = Enumerable
.Range(2811, 20)
.Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo<AlarmMessage>())
.Where(m => m != AlarmMessage.NoAlarm)
.ToArray();
var dcPower = acActualMeasurement.GetInt16(5141) * 1m + acActualMeasurement.GetInt16(5142) * 1m + acActualMeasurement.GetInt16(5143) * 1m;
var dcVoltage = acActualMeasurement8.GetUInt16(5214) + acActualMeasurement8.GetUInt16(5213);
var dcCurrent = dcVoltage != 0m
? dcPower / dcVoltage
: 0m;
// //acActualMeasurement
// PowerAcL1 = acActualMeasurement.GetInt16(5141) * 1m, // in Watt
// PowerAcL2 = acActualMeasurement.GetInt16(5142) * 1m, // in Watt
// PowerAcL3 = acActualMeasurement.GetInt16(5143) * 1m, // in Watt
//
//acActualMeasurement1
// PhaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m,
// PhaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m,
// PhaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m,
//acActualMeasurement2
// GridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m,
// GridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m,
// GridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m,
//acActualMeasurement3
// CosPhiL1 = acActualMeasurement3.GetInt16(5171) * 0.01m,
// CosPhiL2 = acActualMeasurement3.GetInt16(5172) * 0.01m,
// CosPhiL3 = acActualMeasurement3.GetInt16(5173) * 0.01m,
// //acActualMeasurement4
// SumPowerL1 = acActualMeasurement4.GetUInt32(5187) * 1m, // in Watt
// //acActualMeasurement5
// SumPowerL2 = acActualMeasurement5.GetUInt32(5189) * 1m, // in Watt
// //acActualMeasurement6
// SumPowerL3 = acActualMeasurement6.GetUInt32(5191) * 1m, // in Watt
// //acActualMeasurement9
// GridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m,
//acActualMeasurement11
// VoltageIntNtoPE = acActualMeasurement9.GetInt16(5221) * 0.1m,
// VoltageExtNtoPE = acActualMeasurement9.GetInt16(5222) * 0.1m,
//
// ApparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m, // in VA
// ApparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m, // in VA
// ApparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m, // in VA
var apparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m;
var apparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m;
var apparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m;
var powerAcL1 = acActualMeasurement.GetInt16(5141) * 1m; // in Watt
var powerAcL2 = acActualMeasurement.GetInt16(5142) * 1m; // in Watt
var powerAcL3 = acActualMeasurement.GetInt16(5143) * 1m; // in Watt
var phaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m;
var phaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m;
var phaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m;
var gridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m;
var gridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m;
var gridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m;
var gridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m;
return new StatusRecord
{
Ac = new Ac3Bus
{
Frequency = gridFrequency,
L1 = new AcPhase
{
Voltage = gridVoltageL1,
Current = phaseCurrentL1,
Phi = ACos(powerAcL1 / apparentPowerAcL1), // TODO: 2pi
},
L2 = new AcPhase
{
Voltage = gridVoltageL2,
Current = phaseCurrentL2,
Phi = ACos(powerAcL2 / apparentPowerAcL2), // TODO: 2pi
},
L3 = new AcPhase
{
Voltage = gridVoltageL3,
Current = phaseCurrentL3,
Phi = ACos(powerAcL3 / apparentPowerAcL3), // TODO: 2pi
}
},
Dc = new DcBus
{
Current = dcCurrent,
Voltage = dcVoltage,
},
MainState = acActualMain.GetInt16(5001).ConvertTo<MainState>(),
Alarms = alarms,
Warnings = warnings,
GridType = acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(),
SerialNumber = acSerialNumber.GetInt32(2009).ToString(), // TODO: why tostring ?
NumberOfConnectedSlaves = acActualMain.GetUInt16(5002),
NumberOfConnectedSubSlaves = acActualMain.GetUInt16(5003),
AcDcNominalGridFrequency = acActualAcDc.GetUInt16(5021) * 0.1m,
AcDcNominalGridVoltage = acActualAcDc.GetUInt16(5022),
AcDcActNominalPower = acActualAcDc.GetUInt16(5023),
AcDcPowerLimitingStatusAct = acActualAcDc.GetUInt16(5025),
AcDcDcVoltageReference = acActualAcDc.GetUInt16(5026), // DC link reference
AcDcDcLinkVoltageMinAct = acActualAcDc.GetUInt16(5027), // DC link min voltage
AcDcDcLinkVoltageMaxAct = acActualAcDc.GetUInt16(5028), // DC link max voltage
AcDcDcLinkChargedMinVoltage = acActualAcDc.GetUInt16(5029) * 0.01m,
AcDcStmActCustomer = acActualAcDc2.GetUInt16(5031), //need to check
AcDcOverloadIntegratorStatusL1 = acActualAcDc3.GetUInt16(5134) * 0.1m,
AcDcOverloadIntegratorStatusL2 = acActualAcDc3.GetUInt16(5135) * 0.1m,
AcDcOverloadIntegratorStatusL3 = acActualAcDc3.GetUInt16(5136) * 0.1m,
AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
ActualDcLinkVoltageUpperHalf = acActualMeasurement8.GetUInt16(5211),
ActualDcLinkVoltageLowerHalf = acActualMeasurement8.GetUInt16(5212),
ActualDcLinkVoltageUpperHalfExt = acActualMeasurement8.GetUInt16(5213),
ActualDcLinkVoltageLowerHalfExt = acActualMeasurement8.GetUInt16(5214),
VoltageIntNtoPe = acActualMeasurement9.GetInt16(5221) * 0.1m,
VoltageExtNtoPe = acActualMeasurement9.GetInt16(5222) * 0.1m,
InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m,
};
// (
// Ac: new Ac3Bus
// (
// new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)),
// new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)),
// new AcPhase(gridVoltageL3,phaseCurrentL3, ACos(powerAcL3/apparentPowerAcL3)),
// gridFrequency // Gird Frequency
// ),
// Dc: new DcConnection(dcVoltage, dcCurrent),
//
// SerialNumber : acSerialNumber.GetInt32(2009).ToString(),
//
// // acActualMainValues
// MainState : acActualMain.GetInt16(5001).ConvertTo<MainState>(),
// NumberOfConnectedSlaves : acActualMain.GetUInt16(5002),
// NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003),
//
// //acActualAcDc
// AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m,
// AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022),
// AcDcActNominalPower : acActualAcDc.GetUInt16(5023),
// AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(),
// AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025),
// AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference
// AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage
// AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage
// AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m,
//
// //ac Actual AcDc 2
// AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check
// AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m,
// AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m,
// AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m,
// AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
//
// //acActualMeasurement10
// ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211),
// ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212),
// ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213),
// ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214),
//
// VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m,
// VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m,
// //acActualTemp
// InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m,
//
// Warnings : warnings,
// Alarms : alarms
// );
}
public void Write(SystemControlRegisters c) => _SystemControlSlave.Write(c);
public SystemControlRegisters Read() => _SystemControlSlave.Read();
}

View File

@ -0,0 +1,41 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
#pragma warning disable CS0649
[SuppressMessage("ReSharper", "InconsistentNaming")]
public partial record SystemControlRegisters
{
private IEnumerable<AlarmMessage> GetAlarms()
{
yield return Alarm1;
yield return Alarm2;
yield return Alarm3;
yield return Alarm4;
yield return Alarm5;
yield return Alarm6;
yield return Alarm7;
yield return Alarm8;
yield return Alarm9;
yield return Alarm10;
yield return Alarm11;
yield return Alarm12;
yield return Alarm13;
yield return Alarm14;
yield return Alarm15;
yield return Alarm16;
yield return Alarm17;
yield return Alarm18;
yield return Alarm19;
yield return Alarm20;
}
public IReadOnlyList<AlarmMessage> Alarms => GetAlarms()
.Take(NumberOfAlarms)
.Where(IsSystemControlAlarm)
.ToList();
private static Boolean IsSystemControlAlarm(AlarmMessage alarm) => (UInt16)alarm is >= 40000 and < 50000;
}

View File

@ -0,0 +1,17 @@
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
public partial record SystemControlRegisters
{
public TimeSpan? CommunicationTimeout
{
get => _CommunicationTimeoutSeconds != NoTimeout
? TimeSpan.FromSeconds(_CommunicationTimeoutSeconds)
: null;
set => _CommunicationTimeoutSeconds = value is not null
? value.Value.TotalSeconds.ConvertTo<UInt16>()
: NoTimeout;
}
}

View File

@ -0,0 +1,90 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using SystemConfig = InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
#pragma warning disable CS0169
#pragma warning disable CS0649
// using the same record for status & control
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public partial record SystemControlRegisters
{
private const UInt16 NoTimeout = UInt16.MaxValue;
[HoldingRegister(1016)] private UInt16 _CommunicationTimeoutSeconds;
[HoldingRegister(1018)] public SystemConfig SystemConfig { get; set; }
//[Coil(4002)]
[HoldingRegister(4002)] public Boolean ResetAlarmsAndWarnings { get; set; }
[HoldingRegister(4007)] public UInt16 TargetSlave { get; set; }
//[Coil(4011)]
[HoldingRegister(4011)] public Boolean UseSlaveIdForAddressing { get; set; }
[HoldingRegister(4006)] public ReferenceFrame ReferenceFrame { get; set; }
[HoldingRegister(4008)] public SlaveErrorHandling SlaveErrorHandling { get; set; }
[HoldingRegister(4012)] public SubSlaveErrorHandling SubSlaveErrorHandling { get; set; }
[HoldingRegister(4182)] public PowerSetPointActivation PowerSetPointActivation { get; set; }
[HoldingRegister(4183)] public PowerSetPointTrigger PowerSetPointTrigger { get; set; }
[InputRegister(5000)] public DeviceState DeviceState { get; private set; }
[InputRegister(5001)] public UInt16 NumberOfConnectedSlaves { get; private set; }
[InputRegister(5002)] public UInt16 NumberOfConnectedSubSlaves { get; private set; }
[InputRegister(2402)] public UInt16 NumberOfWarnings;
[InputRegister(2403)] private WarningMessage Warning1;
[InputRegister(2404)] private WarningMessage Warning2;
[InputRegister(2405)] private WarningMessage Warning3;
[InputRegister(2406)] private WarningMessage Warning4;
[InputRegister(2407)] private WarningMessage Warning5;
[InputRegister(2408)] private WarningMessage Warning6;
[InputRegister(2409)] private WarningMessage Warning7;
[InputRegister(2410)] private WarningMessage Warning8;
[InputRegister(2411)] private WarningMessage Warning9;
[InputRegister(2412)] private WarningMessage Warning10;
[InputRegister(2413)] private WarningMessage Warning11;
[InputRegister(2414)] private WarningMessage Warning12;
[InputRegister(2415)] private WarningMessage Warning13;
[InputRegister(2416)] private WarningMessage Warning14;
[InputRegister(2417)] private WarningMessage Warning15;
[InputRegister(2418)] private WarningMessage Warning16;
[InputRegister(2419)] private WarningMessage Warning17;
[InputRegister(2420)] private WarningMessage Warning18;
[InputRegister(2421)] private WarningMessage Warning19;
[InputRegister(2422)] private WarningMessage Warning20;
[InputRegister(2809)] private UInt16 NumberOfAlarms;
[InputRegister(2810)] private AlarmMessage Alarm1;
[InputRegister(2811)] private AlarmMessage Alarm2;
[InputRegister(2812)] private AlarmMessage Alarm3;
[InputRegister(2813)] private AlarmMessage Alarm4;
[InputRegister(2814)] private AlarmMessage Alarm5;
[InputRegister(2815)] private AlarmMessage Alarm6;
[InputRegister(2816)] private AlarmMessage Alarm7;
[InputRegister(2817)] private AlarmMessage Alarm8;
[InputRegister(2818)] private AlarmMessage Alarm9;
[InputRegister(2819)] private AlarmMessage Alarm10;
[InputRegister(2820)] private AlarmMessage Alarm11;
[InputRegister(2821)] private AlarmMessage Alarm12;
[InputRegister(2822)] private AlarmMessage Alarm13;
[InputRegister(2823)] private AlarmMessage Alarm14;
[InputRegister(2824)] private AlarmMessage Alarm15;
[InputRegister(2825)] private AlarmMessage Alarm16;
[InputRegister(2826)] private AlarmMessage Alarm17;
[InputRegister(2827)] private AlarmMessage Alarm18;
[InputRegister(2828)] private AlarmMessage Alarm19;
[InputRegister(2829)] private AlarmMessage Alarm20;
}

View File

@ -0,0 +1,39 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
#pragma warning disable CS0649
[SuppressMessage("ReSharper", "InconsistentNaming")]
public partial record SystemControlRegisters
{
private IEnumerable<WarningMessage> GetWarnings()
{
yield return Warning1;
yield return Warning2;
yield return Warning3;
yield return Warning4;
yield return Warning5;
yield return Warning6;
yield return Warning7;
yield return Warning8;
yield return Warning9;
yield return Warning10;
yield return Warning11;
yield return Warning12;
yield return Warning13;
yield return Warning14;
yield return Warning15;
yield return Warning16;
yield return Warning17;
yield return Warning18;
yield return Warning19;
yield return Warning20;
}
public IReadOnlyList<WarningMessage> Warnings => GetWarnings()
.Take(NumberOfWarnings)
.Where(w => w != WarningMessage.NoWarning)
.ToList();
}

View File

@ -1,83 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl;
public static class SystemControlRegisters
{
// TODO
// public const UInt16 Date = 1001;
// public const UInt16 Time = 1003;
// public const UInt16 IpAddress = 1005;
// public const UInt16 Subnet = 1007;
// public const UInt16 Gateway = 1009;
// public const UInt16 ResetParamToDefault = 1011;
// public const UInt16 CommunicationTimeout = 1017;
// public const UInt16 RestartFlag = 1018;
// public const UInt16 ConnectedSystemConfig = 1019;
// public const UInt16 UpdateSwTrigger = 1027;
// public const UInt16 AutomaticSwUpdate = 1028;
// public const UInt16 CustomerValuesSaveReset = 1029;
// public const UInt16 SerialNumberSystemControl = 2001;
// public const UInt16 SerialNumberAcDc = 2009;
// public const UInt16 IntegrationLevel = 2051;
// public const UInt16 IlBuildnumber = 2052;
// public const UInt16 PowerStageConfig = 4001;
// public const UInt16 SetValueConfig = 4002;
// public const UInt16 ResetsAlarmAndWarning = 4003;
// public const UInt16 PreChargeDcLinkConfigR = 4006;
// public const UInt16 ReferenceFrameConvention = 4007;
// public const UInt16 SlaveAddress = 4008;
// public const UInt16 ErrorHandlingPolicy = 4009;
// public const UInt16 GridType = 4010;
// public const UInt16 SubSlaveAddress = 4011;
// public const UInt16 ModbusSlaveId = 4012;
// public const UInt16 SubSlaveErrorPolicy = 4013;
// public const UInt16 SignedPowerNominalValue = 4196;
// public const UInt16 SignedPowerSetValueL1 = 4197;
// public const UInt16 SignedPowerSetValueL2 = 4198;
// public const UInt16 SignedPowerSetValueL3 = 4199;
// public const UInt16 PowerSetValue = 4200;
// public const UInt16 PowerSetValueL1 = 4201;
// public const UInt16 PowerSetValueL2 = 4202;
// public const UInt16 PowerSetValueL3 = 4203;
// public const UInt16 MaximumGridCurrentRmsL1 = 4204;
// public const UInt16 MaximumGridCurrentRmsL2 = 4205;
// public const UInt16 MaximumGridCurrentRmsL3 = 4206;
// public const UInt16 CosPhiSetValueL1 = 4207;
// public const UInt16 CosPhiSetValueL2 = 4208;
// public const UInt16 CosPhiSetValueL3 = 4209;
// public const UInt16 PhaseL1IsCapacitive = 4214; // True = Capacitive, false = Inductive
// public const UInt16 PhaseL2IsCapacitive = 4215; // True = Capacitive, false = Inductive
// public const UInt16 PhaseL3IsCapacitive = 4216; // True = Capacitive, false = Inductive
// public const UInt16 PhasesAreCapacitive = 4217; // True = Capacitive, false = Inductive
// public const UInt16 SetPointCosPhi = 4218;
// public const UInt16 SetPointSinPhi = 4219;
// public const UInt16 SetPointSinPhiL1 = 4220;
// public const UInt16 SetPointSinPhiL2 = 4221;
// public const UInt16 SetPointSinPhiL3 = 4222;
// public const UInt16 FrequencyOffsetIm = 4223; //Im: Island mode
// public const UInt16 VoltageAdjustmentFactorIm = 4224; //Im: Island mode
// public const UInt16 PreChargeDcLinkVoltage = 4226;
// public const UInt16 MaxPeakCurrentVoltageControlL1 = 4227;
// public const UInt16 MaxPeakCurrentVoltageControlL2 = 4228;
// public const UInt16 MaxPeakCurrentVoltageControlL3 = 4229;
// public const UInt16 GridFormingMode = 4230;
// public const UInt16 DcLinkReferenceVoltage = 4231;
// public const UInt16 DcLinkMinVoltage = 4232;
// public const UInt16 DcLinkMaxVoltage = 4233;
// public const UInt16 AcDcDcVoltageRefUs = 4234;
// public const UInt16 AcDcMinDcLinkVoltageUs = 4235;
// public const UInt16 AcDcMaxDcLinkVoltageUs = 4236;
// // public const UInt16 FrequencySlopeIslandMode = 4237, // Function fN = f(active grid-power) of droop control
// // public const UInt16 VoltageSlopeIslandMode = 4238, // VN = f(reactive grid power) of droop control in island operation.
// public const UInt16 AcDcGcBypassMode = 4281;
// public const UInt16 AcDcGcPMaxThresholdPercent = 4282; // res
// public const UInt16 AcDcGcStartupRampEnable = 4283;
// public const UInt16 DcConfigModule = 4301; // 0 = DC module is off, battery voltage can be measured
// // 1 = DC module is active (DC link voltage control)
// // 2 = DC module is active(current source mode orin DC droop mode)
// public const UInt16 DcDcPowerDistribution = 4304;
// public const UInt16 AcDcDistributionMode = 4307;
}

View File

@ -1,13 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert;
public enum InverterAlarmState : UInt16
{
AlarmOff = 0,
ResetAlarmAc = 1,
}
public enum DcAlarmState : UInt16
{
AlarmOff = 0,
ResetAlarmDc = 1,
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert;
public static class Slave
{
public const UInt16 Broadcast = 0;
}

View File

@ -7,6 +7,7 @@
<ItemGroup>
<ProjectReference Include="../../../Utils/Utils.csproj" />
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert;
public static class Utils
{
public static UInt16[] ToUInt16(this IEnumerable<Decimal> regs, Decimal resolution)
{
// LINQ
return regs
.Select(v => (Int16)(v / resolution))
.Select(v => unchecked((UInt16)v))
.ToArray();
}
}

View File

@ -1,80 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public static class AcControlRegisters
{
public const UInt16 Date = 1001;
public const UInt16 Time = 1003;
public const UInt16 IpAddress = 1005;
public const UInt16 Subnet = 1007;
public const UInt16 Gateway = 1009;
public const UInt16 ResetParamToDefault = 1011;
public const UInt16 CommunicationTimeout = 1017;
public const UInt16 RestartFlag = 1018;
public const UInt16 ConnectedSystemConfig = 1019;
public const UInt16 UpdateSwTrigger = 1027;
public const UInt16 AutomaticSwUpdate = 1028;
public const UInt16 CustomerValuesSaveReset = 1029;
public const UInt16 SerialNumberSystemControl = 2001;
public const UInt16 SerialNumberAcDc = 2009;
public const UInt16 IntegrationLevel = 2051;
public const UInt16 IlBuildnumber = 2052;
public const UInt16 PowerStageConfig = 4001;
public const UInt16 SetValueConfig = 4002;
public const UInt16 ResetsAlarmAndWarning = 4003;
public const UInt16 PreChargeDcLinkConfigR = 4006;
public const UInt16 ReferenceFrameConvention = 4007;
public const UInt16 SlaveAddress = 4008;
public const UInt16 ErrorHandlingPolicy = 4009;
public const UInt16 GridType = 4010;
public const UInt16 SubSlaveAddress = 4011;
public const UInt16 ModbusSlaveId = 4012;
public const UInt16 SubSlaveErrorPolicy = 4013;
public const UInt16 SignedPowerNominalValue = 4196;
public const UInt16 SignedPowerSetValueL1 = 4197;
public const UInt16 SignedPowerSetValueL2 = 4198;
public const UInt16 SignedPowerSetValueL3 = 4199;
public const UInt16 PowerSetValue = 4200;
public const UInt16 PowerSetValueL1 = 4201;
public const UInt16 PowerSetValueL2 = 4202;
public const UInt16 PowerSetValueL3 = 4203;
public const UInt16 MaximumGridCurrentRmsL1 = 4204;
public const UInt16 MaximumGridCurrentRmsL2 = 4205;
public const UInt16 MaximumGridCurrentRmsL3 = 4206;
public const UInt16 CosPhiSetValueL1 = 4207;
public const UInt16 CosPhiSetValueL2 = 4208;
public const UInt16 CosPhiSetValueL3 = 4209;
public const UInt16 PhaseL1IsCapacitive = 4214; // True = Capacitive, false = Inductive
public const UInt16 PhaseL2IsCapacitive = 4215; // True = Capacitive, false = Inductive
public const UInt16 PhaseL3IsCapacitive = 4216; // True = Capacitive, false = Inductive
public const UInt16 PhasesAreCapacitive = 4217; // True = Capacitive, false = Inductive
public const UInt16 SetPointCosPhi = 4218;
public const UInt16 SetPointSinPhi = 4219;
public const UInt16 SetPointSinPhiL1 = 4220;
public const UInt16 SetPointSinPhiL2 = 4221;
public const UInt16 SetPointSinPhiL3 = 4222;
public const UInt16 FrequencyOffsetIm = 4223; //Im: Island mode
public const UInt16 VoltageAdjustmentFactorIm = 4224; //Im: Island mode
public const UInt16 PreChargeDcLinkVoltage = 4226;
public const UInt16 MaxPeakCurrentVoltageControlL1 = 4227;
public const UInt16 MaxPeakCurrentVoltageControlL2 = 4228;
public const UInt16 MaxPeakCurrentVoltageControlL3 = 4229;
public const UInt16 GridFormingMode = 4230;
public const UInt16 DcLinkReferenceVoltage = 4231;
public const UInt16 DcLinkMinVoltage = 4232;
public const UInt16 DcLinkMaxVoltage = 4233;
public const UInt16 AcDcDcVoltageRefUs = 4234;
public const UInt16 AcDcMinDcLinkVoltageUs = 4235;
public const UInt16 AcDcMaxDcLinkVoltageUs = 4236;
// public const UInt16 FrequencySlopeIslandMode = 4237, // Function fN = f(active grid-power) of droop control
// public const UInt16 VoltageSlopeIslandMode = 4238, // VN = f(reactive grid power) of droop control in island operation.
public const UInt16 AcDcGcBypassMode = 4281;
public const UInt16 AcDcGcPMaxThresholdPercent = 4282; // res
public const UInt16 AcDcGcStartupRampEnable = 4283;
public const UInt16 DcConfigModule = 4301; // 0 = DC module is off, battery voltage can be measured
// 1 = DC module is active (DC link voltage control)
// 2 = DC module is active(current source mode orin DC droop mode)
public const UInt16 DcDcPowerDistribution = 4304;
public const UInt16 AcDcDistributionMode = 4307;
}

View File

@ -0,0 +1,70 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.StatusApi.DeviceTypes;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public class AcDcDevicesRecord : IAcDc3
{
// private static readonly AcPhase NoAcPhase = Ac3Bus.FromPhasesAndFrequency()
// private static readonly Ac3Bus NoAcDevice = Ac3Bus.FromPhasesAndFrequency()
public AcDcDevicesRecord(SystemControlRegisters? systemControl, IReadOnlyList<AcDcRecord> devices)
{
SystemControl = systemControl;
Devices = devices;
}
public SystemControlRegisters? SystemControl { get; }
public IReadOnlyList<AcDcRecord> Devices { get; init; }
public IEnumerable<AlarmMessage> Alarms => Devices.SelectMany(d => d.Status.Alarms).Distinct();
public IEnumerable<WarningMessage> Warnings => Devices.SelectMany(d => d.Status.Warnings).Distinct();
public Ac3Bus Ac
{
get
{
if (Devices.Count == 0)
return Ac3Bus.Null;
var l1 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L1.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L1.Current),
activePower : Devices.Sum(d => d.Status.Ac.L1.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L1.Power.Reactive)
);
var l2 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L2.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L2.Current),
activePower : Devices.Sum(d => d.Status.Ac.L2.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L2.Power.Reactive)
);
var l3 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L3.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L3.Current),
activePower : Devices.Sum(d => d.Status.Ac.L3.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L3.Power.Reactive)
);
var f = Devices.Average(d => d.Status.Ac.Frequency);
return Ac3Bus.FromPhasesAndFrequency(l1, l2, l3, f);
}
}
public DcBus Dc => Devices.Count == 0
? DcBus.Null
: DcBus.FromVoltageCurrent
(
voltage: Devices.Average(d => d.Status.Dc.Voltage),
current: Devices.Sum(d => d.Status.Dc.Current)
);
}

View File

@ -0,0 +1,159 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using AlarmMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.AlarmMessage;
using WarningMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.WarningMessage;
#pragma warning disable CS0649
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public partial class AcDcRecord
{
[HoldingRegister(4000)] internal Boolean PowerStageEnable;
[HoldingRegister(4001)] internal PhaseControl PhaseControl;
[HoldingRegister(4002)] internal Boolean ResetAlarmsAndWarnings;
[HoldingRegister(4005)] internal DcPrechargeConfig DcPrechargeConfig;
[HoldingRegister(4009)] internal GridType GridType;
[HoldingRegister(4200)] internal Double PowerSetpointL1; // VA
[HoldingRegister(4201)] internal Double PowerSetpointL2; // VA
[HoldingRegister(4202)] internal Double PowerSetpointL3; // VA
[HoldingRegister<Int16>(4206)] internal Double CosPhiSetpointL1;
[HoldingRegister<Int16>(4207)] internal Double CosPhiSetpointL2;
[HoldingRegister<Int16>(4208)] internal Double CosPhiSetpointL3;
[HoldingRegister<Int16>(4219)] internal Double SinPhiSetpointL1;
[HoldingRegister<Int16>(4220)] internal Double SinPhiSetpointL2;
[HoldingRegister<Int16>(4221)] internal Double SinPhiSetpointL3;
[HoldingRegister(4213)] internal ReactivePowerKind ReactivePowerKindL1;
[HoldingRegister(4214)] internal ReactivePowerKind ReactivePowerKindL2;
[HoldingRegister(4215)] internal ReactivePowerKind ReactivePowerKindL3;
[HoldingRegister(4222, Scale = .01)] internal Double IslandModeFrequencyOffset;
[HoldingRegister(4223)] internal Double IslandModeVoltageAdjustmentFactor;
[HoldingRegister(4229)] internal GridMode GridMode;
[HoldingRegister(4230)] internal Double DcLinkReferenceVoltage380400VGrid;
[HoldingRegister(4231)] internal Double DcLinkMinVoltage380400VGrid;
[HoldingRegister(4232)] internal Double DcLinkMaxVoltage380400VGrid;
[HoldingRegister(4233)] internal Double DcLinkReferenceVoltage480VGrid;
[HoldingRegister(4234)] internal Double DcLinkMinVoltage480VGrid;
[HoldingRegister(4235)] internal Double DcLinkMaxVoltage480VGrid;
[InputRegister(5023)] internal readonly GridType ActiveGridType;
[InputRegister(5024)] internal readonly PowerLimit PowerLimitedBy;
[InputRegister(5030)] internal readonly InverterState InverterState;
[InputRegister(5031)] internal readonly InverterState StateOnLastAlarm;
[InputRegister(5025)] internal readonly Double DcReferenceVoltage;
[InputRegister(5026)] internal readonly Double DcMinVoltage;
[InputRegister(5027)] internal readonly Double DcMaxVoltage;
[InputRegister(5028, Scale = .01)] internal readonly Double DcHalfVoltageThreshold;
[InputRegister(5020, Scale = .1)] internal readonly Double NominalAcFrequency;
[InputRegister(5021)] internal readonly Double NominalAcVoltage;
[InputRegister(5022)] internal readonly Double NominalPower;
[InputRegister(5130)] internal readonly Double ApparentPowerL1;
[InputRegister(5131)] internal readonly Double ApparentPowerL2;
[InputRegister(5132)] internal readonly Double ApparentPowerL3;
[InputRegister(5133, Scale = .1)] internal readonly Double OverloadCapacityL1;
[InputRegister(5134, Scale = .1)] internal readonly Double OverloadCapacityL2;
[InputRegister(5135, Scale = .1)] internal readonly Double OverloadCapacityL3;
[InputRegister<Int16>(5140)] internal readonly Double ActivePowerL1;
[InputRegister<Int16>(5141)] internal readonly Double ActivePowerL2;
[InputRegister<Int16>(5142)] internal readonly Double ActivePowerL3;
[InputRegister(5231)] internal readonly Double ReactivePowerL1;
[InputRegister(5232)] internal readonly Double ReactivePowerL2;
[InputRegister(5233)] internal readonly Double ReactivePowerL3;
[InputRegister(5100, Scale = .01)] internal readonly Double BatteryVoltage;
[InputRegister(5110)] internal readonly Double BatteryCurrent;
[InputRegister(5150, Scale = .01)] internal readonly Double GridCurrentL1;
[InputRegister(5151, Scale = .01)] internal readonly Double GridCurrentL2;
[InputRegister(5152, Scale = .01)] internal readonly Double GridCurrentL3;
[InputRegister(5160, Scale = .1)] internal readonly Double GridVoltageL1;
[InputRegister(5161, Scale = .1)] internal readonly Double GridVoltageL2;
[InputRegister(5162, Scale = .1)] internal readonly Double GridVoltageL3;
[InputRegister<Int16>(5170, Scale = .01)] internal readonly Double CosPhiL1;// TODO: check that those agree with computed ones in AC
[InputRegister<Int16>(5171, Scale = .01)] internal readonly Double CosPhiL2;// TODO: remove
[InputRegister<Int16>(5172, Scale = .01)] internal readonly Double CosPhiL3;
[InputRegister(5200, Scale = .01)] internal readonly Double GridFrequency;// Grid freq in doc
[InputRegister(5210)] internal readonly Double InternDcVoltageUpperHalf;
[InputRegister(5211)] internal readonly Double InternDcVoltageLowerHalf;
[InputRegister(5220, Scale = .1)] internal readonly Double InternVoltageNToPe;
[InputRegister(5212)] internal readonly Double ExternDcVoltageUpperHalf;
[InputRegister(5213)] internal readonly Double ExternDcVoltageLowerHalf;
[InputRegister(5221, Scale = .1)] internal readonly Double ExternVoltageNToPe;
[InputRegister(5500, Scale = .1)] internal readonly Double InletAirTemperature;
[InputRegister(5501, Scale = .1)] internal readonly Double IgbtL1Temperature;
[InputRegister(5502, Scale = .1)] internal readonly Double IgbtL2Temperature;
[InputRegister(5503, Scale = .1)] internal readonly Double IgbtL3Temperature;
[InputRegister(5504, Scale = .1)] internal readonly Double IgbtBalancerTemperature;
[InputRegister(2809)] internal readonly UInt16 NumberOfAlarms;
[InputRegister(2810)] internal readonly AlarmMessage Alarm1;
[InputRegister(2811)] internal readonly AlarmMessage Alarm2;
[InputRegister(2812)] internal readonly AlarmMessage Alarm3;
[InputRegister(2813)] internal readonly AlarmMessage Alarm4;
[InputRegister(2814)] internal readonly AlarmMessage Alarm5;
[InputRegister(2815)] internal readonly AlarmMessage Alarm6;
[InputRegister(2816)] internal readonly AlarmMessage Alarm7;
[InputRegister(2817)] internal readonly AlarmMessage Alarm8;
[InputRegister(2818)] internal readonly AlarmMessage Alarm9;
[InputRegister(2819)] internal readonly AlarmMessage Alarm10;
[InputRegister(2820)] internal readonly AlarmMessage Alarm11;
[InputRegister(2821)] internal readonly AlarmMessage Alarm12;
[InputRegister(2822)] internal readonly AlarmMessage Alarm13;
[InputRegister(2823)] internal readonly AlarmMessage Alarm14;
[InputRegister(2824)] internal readonly AlarmMessage Alarm15;
[InputRegister(2825)] internal readonly AlarmMessage Alarm16;
[InputRegister(2826)] internal readonly AlarmMessage Alarm17;
[InputRegister(2827)] internal readonly AlarmMessage Alarm18;
[InputRegister(2828)] internal readonly AlarmMessage Alarm19;
[InputRegister(2829)] internal readonly AlarmMessage Alarm20;
[InputRegister(2402)] internal readonly UInt16 NumberOfWarnings;
[InputRegister(2403)] internal readonly WarningMessage Warning1;
[InputRegister(2404)] internal readonly WarningMessage Warning2;
[InputRegister(2405)] internal readonly WarningMessage Warning3;
[InputRegister(2406)] internal readonly WarningMessage Warning4;
[InputRegister(2407)] internal readonly WarningMessage Warning5;
[InputRegister(2408)] internal readonly WarningMessage Warning6;
[InputRegister(2409)] internal readonly WarningMessage Warning7;
[InputRegister(2410)] internal readonly WarningMessage Warning8;
[InputRegister(2411)] internal readonly WarningMessage Warning9;
[InputRegister(2412)] internal readonly WarningMessage Warning10;
[InputRegister(2413)] internal readonly WarningMessage Warning11;
[InputRegister(2414)] internal readonly WarningMessage Warning12;
[InputRegister(2415)] internal readonly WarningMessage Warning13;
[InputRegister(2416)] internal readonly WarningMessage Warning14;
[InputRegister(2417)] internal readonly WarningMessage Warning15;
[InputRegister(2418)] internal readonly WarningMessage Warning16;
[InputRegister(2419)] internal readonly WarningMessage Warning17;
[InputRegister(2420)] internal readonly WarningMessage Warning18;
[InputRegister(2421)] internal readonly WarningMessage Warning19;
[InputRegister(2422)] internal readonly WarningMessage Warning20;
}

View File

@ -0,0 +1,10 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public partial class AcDcRecord
{
public AcDcStatus Status => new(this);
public AcDcControl Control => new(this);
}

View File

@ -0,0 +1,35 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
public class AcControl
{
public AcPowerControl Power => new (_Self);
public PhaseControl PhaseControl
{
get => _Self.PhaseControl;
set => _Self.PhaseControl = value;
}
public GridType GridType
{
get => _Self.GridType;
set
{
_Self.GridType = value;
_Self.GridMode = value switch
{
GridType.Island400V50Hz => GridMode.Island,
GridType.Island480V60Hz => GridMode.Island,
_ => GridMode.GridTied
};
}
}
public IslandMode IslandMode => new(_Self);
internal AcControl(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,23 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
public class AcDcControl
{
public AcControl Ac => new (_Self);
public DcControl Dc => new (_Self);
public Boolean PowerStageEnable
{
get => _Self.PowerStageEnable;
set => _Self.PowerStageEnable = value;
}
public Boolean ResetAlarmsAndWarnings
{
get => _Self.ResetAlarmsAndWarnings;
set => _Self.ResetAlarmsAndWarnings = value;
}
internal AcDcControl(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,97 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
public class AcPowerControl
{
public AcPower L1
{
get
{
var s = _Self.PowerSetpointL1;
var cosPhi = _Self.CosPhiSetpointL1.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL1;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
}
set
{
_Self.PowerSetpointL1 = value.Apparent.Value;
_Self.CosPhiSetpointL1 = value.CosPhi;
_Self.SinPhiSetpointL1 = Math.Sin(value.Phi);
_Self.ReactivePowerKindL1 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;
}
}
public AcPower L2
{
get
{
var s = _Self.PowerSetpointL2;
var cosPhi = _Self.CosPhiSetpointL2.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL2;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
}
set
{
_Self.PowerSetpointL2 = value.Apparent.Value;
_Self.CosPhiSetpointL2 = value.CosPhi;
_Self.SinPhiSetpointL2 = Math.Sin(value.Phi);
_Self.ReactivePowerKindL2 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;
}
}
public AcPower L3
{
get
{
var s = _Self.PowerSetpointL3;
var cosPhi = _Self.CosPhiSetpointL3.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL3;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
}
set
{
_Self.PowerSetpointL3 = value.Apparent.Value;
_Self.CosPhiSetpointL3 = value.CosPhi;
_Self.SinPhiSetpointL3 = Math.Sin(value.Phi);
_Self.ReactivePowerKindL3 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;
}
}
internal AcPowerControl(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
// public IEnumerator<AcPower> GetEnumerator()
// {
// yield return L1;
// yield return L2;
// yield return L3;
// }
//
// IEnumerator IEnumerable.GetEnumerator()
// {
// return GetEnumerator();
// }
}

View File

@ -0,0 +1,45 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
public class DcControl
{
public Voltage ReferenceVoltage
{
get => Is480V ? _Self.DcLinkReferenceVoltage480VGrid : _Self.DcLinkReferenceVoltage380400VGrid;
set
{
_Self.DcLinkReferenceVoltage480VGrid = value;
_Self.DcLinkReferenceVoltage380400VGrid = value;
}
}
public Voltage MinVoltage
{
get => Is480V ? _Self.DcLinkMinVoltage480VGrid : _Self.DcLinkMinVoltage380400VGrid;
set
{
_Self.DcLinkMinVoltage480VGrid = value;
_Self.DcLinkMinVoltage380400VGrid = value;
}
}
public Voltage MaxVoltage
{
get => Is480V ? _Self.DcLinkMaxVoltage480VGrid : _Self.DcLinkMaxVoltage380400VGrid;
set
{
_Self.DcLinkMaxVoltage480VGrid = value;
_Self.DcLinkMaxVoltage380400VGrid = value;
}
}
public DcPrechargeConfig PrechargeConfig => _Self.DcPrechargeConfig;
private Boolean Is480V => _Self.GridType is GridType.GridTied480V60Hz or GridType.Island480V60Hz;
internal DcControl(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,21 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
public class IslandMode
{
public Frequency FrequencyOffset
{
get => _Self.IslandModeFrequencyOffset;
set => _Self.IslandModeFrequencyOffset = value;
}
public Percent VoltageAdjustmentFactor
{
get => _Self.IslandModeVoltageAdjustmentFactor;
set => _Self.IslandModeVoltageAdjustmentFactor = value;
}
internal IslandMode(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,80 @@
// namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
//
// public static class AcControlRegisters
// {
// public const UInt16 Date = 1001;
// public const UInt16 Time = 1003;
// public const UInt16 IpAddress = 1005;
// public const UInt16 Subnet = 1007;
// public const UInt16 Gateway = 1009;
// public const UInt16 ResetParamToDefault = 1011;
// public const UInt16 CommunicationTimeout = 1017;
// public const UInt16 RestartFlag = 1018;
// public const UInt16 ConnectedSystemConfig = 1019;
// public const UInt16 UpdateSwTrigger = 1027;
// public const UInt16 AutomaticSwUpdate = 1028;
// public const UInt16 CustomerValuesSaveReset = 1029;
// public const UInt16 SerialNumberSystemControl = 2001;
// public const UInt16 SerialNumberAcDc = 2009;
// public const UInt16 IntegrationLevel = 2051;
// public const UInt16 IlBuildnumber = 2052;
// public const UInt16 PowerStageConfig = 4001;
// public const UInt16 SetValueConfig = 4002;
// public const UInt16 ResetsAlarmAndWarning = 4003;
// public const UInt16 PreChargeDcLinkConfigR = 4006;
// public const UInt16 ReferenceFrameConvention = 4007;
// public const UInt16 SlaveAddress = 4008;
// public const UInt16 ErrorHandlingPolicy = 4009;
// public const UInt16 GridType = 4010;
// public const UInt16 SubSlaveAddress = 4011;
// public const UInt16 ModbusSlaveId = 4012;
// public const UInt16 SubSlaveErrorPolicy = 4013;
// public const UInt16 SignedPowerNominalValue = 4196;
// public const UInt16 SignedPowerSetValueL1 = 4197;
// public const UInt16 SignedPowerSetValueL2 = 4198;
// public const UInt16 SignedPowerSetValueL3 = 4199;
// public const UInt16 Powe0rSetValue = 4200;
// public const UInt16 PowerSetValueL1 = 4201;
// public const UInt16 PowerSetValueL2 = 4202;
// public const UInt16 PowerSetValueL3 = 4203;
// public const UInt16 MaximumGridCurrentRmsL1 = 4204;
// public const UInt16 MaximumGridCurrentRmsL2 = 4205;
// public const UInt16 MaximumGridCurrentRmsL3 = 4206;
// public const UInt16 CosPhiSetValueL1 = 4207;
// public const UInt16 CosPhiSetValueL2 = 4208;
// public const UInt16 CosPhiSetValueL3 = 4209;
// public const UInt16 PhaseL1IsCapacitive = 4214; // True = Capacitive, false = Inductive
// public const UInt16 PhaseL2IsCapacitive = 4215; // True = Capacitive, false = Inductive
// public const UInt16 PhaseL3IsCapacitive = 4216; // True = Capacitive, false = Inductive
// public const UInt16 PhasesAreCapacitive = 4217; // True = Capacitive, false = Inductive
// public const UInt16 SetPointCosPhi = 4218;
// public const UInt16 SetPointSinPhi = 4219;
// public const UInt16 SetPointSinPhiL1 = 4220;
// public const UInt16 SetPointSinPhiL2 = 4221;
// public const UInt16 SetPointSinPhiL3 = 4222;
// public const UInt16 FrequencyOffsetIm = 4223; //Im: Island mode
// public const UInt16 VoltageAdjustmentFactorIm = 4224; //Im: Island mode
// public const UInt16 PreChargeDcLinkVoltage = 4226;
// public const UInt16 MaxPeakCurrentVoltageControlL1 = 4227;
// public const UInt16 MaxPeakCurrentVoltageControlL2 = 4228;
// public const UInt16 MaxPeakCurrentVoltageControlL3 = 4229;
// public const UInt16 GridFormingMode = 4230;
// public const UInt16 DcLinkReferenceVoltage = 4231;
// public const UInt16 DcLinkMinVoltage = 4232;
// public const UInt16 DcLinkMaxVoltage = 4233;
// public const UInt16 AcDcDcVoltageRefUs = 4234;
// public const UInt16 AcDcMinDcLinkVoltageUs = 4235;
// public const UInt16 AcDcMaxDcLinkVoltageUs = 4236;
// // public const UInt16 FrequencySlopeIslandMode = 4237, // Function fN = f(active grid-power) of droop control
// // public const UInt16 VoltageSlopeIslandMode = 4238, // VN = f(reactive grid power) of droop control in island operation.
// public const UInt16 AcDcGcBypassMode = 4281;
// public const UInt16 AcDcGcPMaxThresholdPercent = 4282; // res
// public const UInt16 AcDcGcStartupRampEnable = 4283;
// public const UInt16 DcConfigModule = 4301; // 0 = DC module is off, battery voltage can be measured
// // 1 = DC module is active (DC link voltage control)
// // 2 = DC module is active(current source mode orin DC droop mode)
// public const UInt16 DcDcPowerDistribution = 4304;
// public const UInt16 AcDcDistributionMode = 4307;
// }
//
//

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum AcDcDistributionMode : UInt16
{

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum AcErrorPolicy : UInt16
{

View File

@ -1,22 +1,12 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum AlarmMessage
public enum AlarmMessage : UInt16
{
NoAlarm = 0,
BmsCommunicationTimeoutHasOccured = 40302, // BMS communication timeout has occured.
Rs485CommunicationAlarm1 = 40303, // RS-485 communication alarm.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch1 = 40412, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch2 = 40413, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch3 = 40414, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch4 = 40415, // Software versions of system control and module(s) do not match.
SoftwareVersionsOfSystemControlAndModulesDoNotMatch5 = 40416, // Software versions of system control and module(s) do not match.
NoSlaveModuleWasFoundPleaseCheckRs485Connection = 40304, // No slave module was found, please check RS-485 connection(s).
NumberOfOrCombinationOfConnectedSlaveTypesNotSupported = 40305, // Number of or combination of connected slave types not supported.
OvertemperatureIgbtBridge1 = 50000, // Overtemperature IGBT bridge 1.
OvertemperatureIgbtBridge2 = 50001, // Overtemperature IGBT bridge 2.
OvertemperatureIgbtBridge3 = 50002, // Overtemperature IGBT bridge 3.

View File

@ -0,0 +1,9 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum DcPrechargeConfig : UInt16
{
WaitForExternalPrecharge = 0,
PrechargeDcWithSystemCtl = 1,
PrechargeDcWithDcDcs = 2,
PrechargeDcWithSystemCtlAndWait = 3,
}

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum DcStageConfiguration : UInt16
{

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum GridMode
{
GridTied = 0,
Island = 1
}

View File

@ -0,0 +1,13 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum InverterState : UInt16
{
Idle = 0,
DcLinkChargeDischargeTest = 1,
DcLinkSyncToExt = 2,
DcLinkCharge = 3,
AcSyncToGrid = 4,
AcCloseContactor = 5,
AcConnected = 6,
Alarm = 99
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum PhaseControl : Byte
{
Asymmetric = 0,
Symmetric = 1,
}

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum PowerFactorConvention : UInt16
{

View File

@ -0,0 +1,10 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum PowerLimit : UInt16
{
Nothing = 0,
DcLink = 1,
GridCode = 2,
Overload = 3,
Temperature = 4,
}

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum PreChargeDcLinkConfig : UInt16
{

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum ReactivePowerKind
{
Inductive = 0,
Capacitive = 1
}

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
public enum SymmetricAcOperationMode : UInt16
{

View File

@ -0,0 +1,32 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum WarningMessage : UInt16
{
NoWarning = 00000,
/*
// these warnings are not official (not in the manual), and they seem to collide with the DCDC warnings
// so I commented them
Fan = 10500, //AC-DC module warning
IOffset = 10503, //AC-DC module warning
VgOffset = 10504, //AC-DC module warning
VcOffset = 10505, //AC-DC module warning
DcOffset = 10506, //AC-DC module warning
NtcProtect = 10507, //DC-link circuit need more time for cool down
AirTemp = 10508, //Overtemperature inlet air: power is derated
SurgeDetected = 10509, //Temporary overvoltage in grid measurement detected (surge)
TempDerating = 11021, //Temperature derating active
Overload = 11022, //Overload handling is active
RuntimeEeprom = 11023, //AC-DC module warning
Overcurrent = 11024 //Overcurrent handling is active
*/
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
public enum SubSlavesErrorPolicy : UInt16
{
Strict = 0, // (AC-DC module switches to error state if at least one submodules is in error state
Relaxed = 1, // (AC-DC module switches to error state if all submodules are in error state.)
Off = 2, // (If possible AC-DC module continues operation even if all submodules are in error state.
}

View File

@ -0,0 +1,61 @@
// using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
// using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
// using InnovEnergy.Lib.Units;
// using InnovEnergy.Lib.Utils;
//
// namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
//
// // TODO :remove
//
// public static class Program
// {
// public static void Main(String[] args)
// {
// var sc = new SystemControlDevice("localhost", 5001);
// var acDc1 = sc.AcDcSlave(1);
// var acDc2 = sc.AcDcSlave(2);
//
//
// while (true)
// {
// "================================================".WriteLine();
//
// var r = sc.Read();
//
// Console.WriteLine(DateTime.Now);
// r.ToString().Replace(",", "\n").Replace(" {", "\n").WriteLine("\n");
//
// var c = r with
// {
// UseSlaveIdForAddressing = true,
// ReferenceFrame = ReferenceFrame.Consumer,
// GridType = GridType.GridTied400V50Hz,
// SystemConfig = SystemConfig.AcDcAndDcDc,
// CommunicationTimeout = null,
// SlaveErrorHandling = SlaveErrorHandling.Relaxed,
// SubSlaveErrorHandling = SubSlaveErrorHandling.Off
// };
//
// sc.Write(c);
//
// var s1 = acDc1.Read();
//
// s1.ToCsv().Replace(",", "\n").Replace(" {", "\n").WriteLine("\n");
//
//
// s1.ResetAlarmsAndWarnings = true;
// s1.PowerStageEnable = true;
//
// acDc1.Write(s1);
//
// var s2 = acDc2.Read();
//
//
// s2.ToString().Replace(",", "\n").Replace(" {", "\n").WriteLine("\n");
//
// acDc2.Write(s2 with { ResetAlarmsAndWarnings = true, PowerStageEnable = true });
// }
//
//
// }
// }

View File

@ -0,0 +1,110 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
using AlarmMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.AlarmMessage;
using WarningMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.WarningMessage;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class AcDcStatus
{
public Ac3Bus Ac => Ac3Bus.FromPhasesAndFrequency(L1, L2, L3, _Self.GridFrequency);
public DcBus Dc => DcBus.FromVoltageCurrent(_Self.BatteryVoltage, _Self.BatteryCurrent);
public PowerLimit PowerLimitedBy => _Self.PowerLimitedBy;
public InverterStates InverterState => new(_Self);
public GridType ActiveGridType => _Self.ActiveGridType;
public Voltages Voltage => new(_Self);
public Temperatures Temperature => new(_Self);
public OverloadCapacity OverloadCapacity => new(_Self);
public Nominals Nominal => new(_Self);
public IReadOnlyList<AlarmMessage> Alarms => GetAlarms ().Take(_Self.NumberOfAlarms ).Where(IsAcDcAlarm ).ToList();
public IReadOnlyList<WarningMessage> Warnings => GetWarnings().Take(_Self.NumberOfWarnings).Where(IsAcDcWarning).ToList();
private IEnumerable<AlarmMessage> GetAlarms()
{
yield return _Self.Alarm1;
yield return _Self.Alarm2;
yield return _Self.Alarm3;
yield return _Self.Alarm4;
yield return _Self.Alarm5;
yield return _Self.Alarm6;
yield return _Self.Alarm7;
yield return _Self.Alarm8;
yield return _Self.Alarm9;
yield return _Self.Alarm10;
yield return _Self.Alarm11;
yield return _Self.Alarm12;
yield return _Self.Alarm13;
yield return _Self.Alarm14;
yield return _Self.Alarm15;
yield return _Self.Alarm16;
yield return _Self.Alarm17;
yield return _Self.Alarm18;
yield return _Self.Alarm19;
yield return _Self.Alarm20;
}
private static Boolean IsAcDcAlarm(AlarmMessage alarm) => (UInt16)alarm is >= 50000 and < 60000;
private IEnumerable<WarningMessage> GetWarnings()
{
yield return _Self.Warning1;
yield return _Self.Warning2;
yield return _Self.Warning3;
yield return _Self.Warning4;
yield return _Self.Warning5;
yield return _Self.Warning6;
yield return _Self.Warning7;
yield return _Self.Warning8;
yield return _Self.Warning9;
yield return _Self.Warning10;
yield return _Self.Warning11;
yield return _Self.Warning12;
yield return _Self.Warning13;
yield return _Self.Warning14;
yield return _Self.Warning15;
yield return _Self.Warning16;
yield return _Self.Warning17;
yield return _Self.Warning18;
yield return _Self.Warning19;
yield return _Self.Warning20;
}
// TODO: there are no AcDc Warnings defined in doc
private static Boolean IsAcDcWarning(WarningMessage warning) => warning != WarningMessage.NoWarning;
private AcPhase L1 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL1,
currentRms : _Self.GridCurrentL1,
activePower : _Self.ActivePowerL1,
reactivePower: _Self.ReactivePowerL1,
apparentPower: _Self.ApparentPowerL1
);
private AcPhase L2 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL2,
currentRms : _Self.GridCurrentL2,
activePower : _Self.ActivePowerL2,
reactivePower: _Self.ReactivePowerL2,
apparentPower: _Self.ApparentPowerL2
);
private AcPhase L3 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL3,
currentRms : _Self.GridCurrentL3,
activePower : _Self.ActivePowerL3,
reactivePower: _Self.ReactivePowerL3,
apparentPower: _Self.ApparentPowerL3
);
internal AcDcStatus(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,13 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class ExternVoltages
{
public Voltage DcUpperHalf => _Self.ExternDcVoltageUpperHalf;
public Voltage DcLowerHalf => _Self.ExternDcVoltageLowerHalf;
public Voltage NToPe => _Self.ExternVoltageNToPe;
internal ExternVoltages(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,13 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class InternVoltages
{
public Voltage DcUpperHalf => _Self.InternDcVoltageUpperHalf;
public Voltage DcLowerHalf => _Self.InternDcVoltageLowerHalf;
public Voltage NToPe => _Self.InternVoltageNToPe;
private readonly AcDcRecord _Self;
internal InternVoltages(AcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,12 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class InverterStates
{
public InverterState Current => _Self.InverterState;
public InverterState OnLastAlarm => _Self.StateOnLastAlarm;
internal InverterStates(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,14 @@
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Power;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class Nominals
{
public Frequency AcFrequency => _Self.NominalAcFrequency;
public Voltage AcVoltage => _Self.NominalAcVoltage;
public DcPower Power => _Self.NominalPower;
private readonly AcDcRecord _Self;
internal Nominals(AcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,13 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class OverloadCapacity
{
public Percent L1 => _Self.OverloadCapacityL1;
public Percent L2 => _Self.OverloadCapacityL2;
public Percent L3 => _Self.OverloadCapacityL3;
internal OverloadCapacity(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -0,0 +1,15 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class Temperatures
{
public Temperature InletAir => _Self.InletAirTemperature;
public Temperature IgbtL1 => _Self.IgbtL1Temperature;
public Temperature IgbtL2 => _Self.IgbtL2Temperature;
public Temperature IgbtL3 => _Self.IgbtL3Temperature;
public Temperature IgbtBalancer => _Self.IgbtBalancerTemperature;
private readonly AcDcRecord _Self;
internal Temperatures(AcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,11 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class Voltages
{
public InternVoltages Intern => new(_Self);
public ExternVoltages Extern => new(_Self);
internal Voltages(AcDcRecord self) => _Self = self;
private readonly AcDcRecord _Self;
}

View File

@ -5,10 +5,12 @@
</PropertyGroup>
<Import Project="../../../InnovEnergy.Lib.props" />
<!-- <Import Project="../../../../App/InnovEnergy.App.props" />-->
<ItemGroup>
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../../../StatusApi/StatusApi.csproj" />
<ProjectReference Include="../TruConvert/TruConvert.csproj" />
<ProjectReference Include="../SystemControl/SystemControl.csproj" />
</ItemGroup>
</Project>

View File

@ -1,85 +0,0 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public record TruConvertAcControl
{
private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromSeconds(10);
public UInt32 Date { get; init;}
public UInt32 Time { get; init;}
public UInt32 IpAddress { get; init;} //= 0x C0A80102;
public UInt32 Subnet { get; init;} //= 0x FFFFFF00;
public UInt32 Gateway { get; init;} //= 0x C0A80102;
public Boolean ResetParamToDefault { get; init;} = false ; // Coil
public TimeSpan CommunicationTimeout { get; init;} = DefaultCommunicationTimeOut;
public Boolean FactoryResetParameters { get; init;} = false;
public SystemConfig ConnectedSystemConfig { get; init;} = 0;
public UInt16 UpdateSwTrigger { get; init;} = 0;
public UInt16 AutomaticSwUpdate { get; init;} = 0;
public UInt16 CustomerValuesSaveReset { get; init;} = 0;
public UInt16 SerialNumberSystemControl { get; init;} = 0;
public UInt16 SerialNumberAcDc { get; init;} = 0;
public UInt16 IntegrationLevel { get; init;} = 0;
public UInt16 IlBuildnumber { get; init;} = 0;
public Boolean PowerStageEnable { get; init;} = true;
public SymmetricAcOperationMode SetValueConfig { get; init;} = 0;
public Boolean ResetsAlarmAndWarning { get; init;} = false;
public PreChargeDcLinkConfig PreChargeDcLinkConfig { get; init;} = (PreChargeDcLinkConfig)0;
public PowerFactorConvention PowerFactorConvention { get; init;} = 0; //0 = producer
public UInt16 SlaveAddress { get; init;} = Slave.Broadcast;
public AcErrorPolicy ErrorHandlingPolicy { get; init;} = 0;
public AcDcGridType GridType { get; init;} = 0;
public UInt16 SubSlaveAddress { get; init;} = 0;
public Boolean UseModbusSlaveIdForAddressing { get; init;} = false;
public UInt16 SubSlaveErrorPolicy { get; init;} = 0; // must be an enum
public Decimal SignedPowerNominalValue { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal SignedPowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal SignedPowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal SignedPowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal PowerSetValue { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal PowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal PowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal PowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal MaximumGridCurrentRmsL1 { get; init;} = 0; // resolution : 0.01
public Decimal MaximumGridCurrentRmsL2 { get; init;} = 0; // resolution : 0.01
public Decimal MaximumGridCurrentRmsL3 { get; init;} = 0; // resolution : 0.01
public Decimal CosPhiSetValueL1 { get; init;} = 0; // resolution : 0.01
public Decimal CosPhiSetValueL2 { get; init;} = 0; // resolution : 0.01
public Decimal CosPhiSetValueL3 { get; init;} = 0; // resolution : 0.01
public Boolean PhaseL1IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
public Boolean PhaseL2IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
public Boolean PhaseL3IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
public Boolean PhasesAreCapacitive { get; init;} = true; // True = Capacitive, false = Inductive
public Double SetPointCosPhi { get; init;} = 0; // resolution 0.01
public Double SetPointSinPhi { get; init;} = 0; // resolution 0.01
public Double SetPointSinPhiL1 { get; init;} = 0; // resolution 0.01
public Double SetPointSinPhiL2 { get; init;} = 0; // resolution 0.01
public Double SetPointSinPhiL3 { get; init;} = 0; // resolution 0.01
public Decimal FrequencyOffsetIm { get; init;} = 0; // resolution 0.01
public UInt16 VoltageAdjustmentFactorIm { get; init;} = 0;
public UInt16 PreChargeDcLinkVoltage { get; init;} = 0;
public Decimal MaxPeakCurrentVoltageControlL1 { get; init;} = 0; // resolution 0.01
public Decimal MaxPeakCurrentVoltageControlL2 { get; init;} = 0; // resolution 0.01
public Decimal MaxPeakCurrentVoltageControlL3 { get; init;} = 0; // resolution 0.01
public UInt16 GridFormingMode { get; init;} = 1; // 0 = not grid-forming (grid-tied) ,1 = grid-forming
public UInt16 DcLinkRefVoltage { get; init;} = 800;
public UInt16 DcLinkMinVoltage { get; init;} = 780;
public UInt16 DcLinkMaxVoltage { get; init;} = 820;
public UInt16 DcVoltageRefUs { get; init;} = 900;
public UInt16 DcMinVoltageUs { get; init;} = 880;
public UInt16 DcMaxVoltageUs { get; init;} = 920;
// Need to discuss this with Ivo
// public UInt16 FrequencySlopeIslandMode { get; init;} = 200; // resolution 0.01
// public UInt16 VoltageSlopeIslandMode { get; init;} = 500; // resolution 0.01
public UInt16 AcDcGcBypassMode { get; init;} = 0;
public UInt16 AcDcGcPMaxThresholdPercent { get; init;} = 0; // resolution 0.01
public UInt16 AcDcGcStartupRampEnable { get; init;} = 0;
public DcStageConfiguration DcConfigModule { get; init;} = 0; // this must be an enum
public UInt16 DcDcPowerDistribution { get; init;} = 0; // 0.1 resolution
public AcDcDistributionMode AcDcDistributionMode { get; init;} = 0;
}

View File

@ -0,0 +1,75 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Protocols.Modbus.Channels;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
public class TruConvertAcDcDevices
{
private readonly ModbusDevice<SystemControlRegisters> _SystemControl;
private readonly IEnumerable<ModbusDevice<AcDcRecord>> _AcDcs;
public TruConvertAcDcDevices(String hostname, UInt16 port) : this(new TcpChannel(hostname, port))
{
}
public TruConvertAcDcDevices(Channel transport)
{
var modbusClient = new ModbusTcpClient(transport, 0);
_SystemControl = new ModbusDevice<SystemControlRegisters>(modbusClient);
_AcDcs = Enumerable
.Range(1, Byte.MaxValue - 1)
.Memoize(CreateAcDc);
ModbusDevice<AcDcRecord> CreateAcDc(Int32 i)
{
var mb = new ModbusTcpClient(transport, (Byte)i);
return new ModbusDevice<AcDcRecord>(mb);
}
}
public AcDcDevicesRecord Read()
{
try
{
var scStatus = _SystemControl.Read();
var n = scStatus.NumberOfConnectedSlaves;
var acDcRecords = _AcDcs
.Take(n)
.Select(acDc => acDc.Read())
.ToArray(n);
return new AcDcDevicesRecord(scStatus, acDcRecords);
}
catch
{
return new AcDcDevicesRecord(null, Array.Empty<AcDcRecord>());
}
}
public void Write(AcDcDevicesRecord r)
{
if (r.SystemControl is not null)
_SystemControl.Write(r.SystemControl); // must run BEFORE the attached devices
foreach (var (ctrl, device) in r.Devices.Zip(_AcDcs))
{
try
{
device.Write(ctrl);
}
catch (Exception e)
{
Console.WriteLine(e);
// TODO: log
}
}
}
}

View File

@ -1,330 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
using static DecimalMath.DecimalEx;
using static InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.AcControlRegisters;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using UInt16s = IReadOnlyList<UInt16>;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class TruConvertAcDevice
{
private ModbusTcpClient ModbusTcpClient { get; }
public TruConvertAcDevice(String hostname, UInt16 port = ModbusTcpClient.DefaultPort, Byte slaveAddress = 0)
{
var connection = new ModbusTcpConnection(hostname, port);
ModbusTcpClient = new ModbusTcpClient(connection, slaveAddress);
}
public void WriteControl(TruConvertAcControl c)
{
/*
WriteRegs(AcControlRegisters.Date, new List<UInt16> { c.Date.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Time, new List<UInt16> { c.Time.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.IpAddress, new List<UInt16> { c.IpAddress.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Subnet, new List<UInt16> { c.Subnet.ConvertTo<UInt16>()});
WriteRegs(AcControlRegisters.Gateway, new List<UInt16> { c.Gateway.ConvertTo<UInt16>()});
WriteCoils(AcControlRegisters.ResetParamToDefault, c.ResetParamToDefault);
WriteCoils(AcControlRegisters.FactoryResetParameters, c.FactoryResetParameters);
ModbusTcpClient.WriteRegisters(AcControlRegisters.UpdateSwTrigger, c.UpdateSwTrigger, c.AutomaticSwUpdate, c.CustomerValuesSaveReset);
*/
WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo<UInt16>());
WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig);
WriteCoils(PowerStageConfig, c.PowerStageEnable,
c.SetValueConfig.ConvertTo<Boolean>(),
c.ResetsAlarmAndWarning);
WriteRegs(PreChargeDcLinkConfigR, c.PreChargeDcLinkConfig,
c.PowerFactorConvention, c.SlaveAddress,
c.ErrorHandlingPolicy,
c.GridType, c.SubSlaveAddress);
WriteCoils(ModbusSlaveId, c.UseModbusSlaveIdForAddressing);
WriteRegs(SubSlaveErrorPolicy, c.SubSlaveErrorPolicy);
WriteRegs(SignedPowerNominalValue, -1.0m, c.SignedPowerNominalValue);/*, c.SignedPowerSetValueL1,
c.SignedPowerSetValueL2, c.SignedPowerSetValueL3,
c.PowerSetValue, c.PowerSetValueL1,
c.PowerSetValueL2, c.PowerSetValuesL3);*/
WriteRegs(MaximumGridCurrentRmsL1, 0.01m, c.MaximumGridCurrentRmsL1, c.MaximumGridCurrentRmsL2,
c.MaximumGridCurrentRmsL3, c.CosPhiSetValueL1,
c.CosPhiSetValueL2, c.CosPhiSetValueL3);
WriteCoils(PhaseL1IsCapacitive, c.PhaseL1IsCapacitive,
c.PhaseL2IsCapacitive,
c.PhaseL3IsCapacitive,
c.PhasesAreCapacitive);
/* WriteRegs(SetPointCosPhi, 0.01m, c.SetPointCosPhi.ConvertTo<UInt16>(),
c.SetPointSinPhi.ConvertTo<UInt16>(),
c.SetPointSinPhiL1.ConvertTo<UInt16>(),
c.SetPointSinPhiL2.ConvertTo<UInt16>(),
c.SetPointSinPhiL3.ConvertTo<UInt16>(),
c.FrequencyOffsetIm);*/
WriteRegs(VoltageAdjustmentFactorIm, c.VoltageAdjustmentFactorIm);
WriteRegs(PreChargeDcLinkVoltage, c.PreChargeDcLinkVoltage);
WriteRegs(MaxPeakCurrentVoltageControlL1, 0.01m, c.MaxPeakCurrentVoltageControlL1,
c.MaxPeakCurrentVoltageControlL2,
c.MaxPeakCurrentVoltageControlL3);
WriteRegs(GridFormingMode, c.GridFormingMode, c.DcLinkRefVoltage,
c.DcLinkMinVoltage, c.DcLinkMaxVoltage,
c.DcVoltageRefUs, c.DcMinVoltageUs, c.DcMaxVoltageUs);
WriteRegs(AcDcGcBypassMode, c.AcDcGcBypassMode);
WriteRegs(AcDcGcPMaxThresholdPercent, 0.01m, c.AcDcGcPMaxThresholdPercent);
WriteRegs(AcDcGcStartupRampEnable, c.AcDcGcStartupRampEnable);
WriteRegs(DcConfigModule, c.DcConfigModule);
WriteRegs(DcDcPowerDistribution, 0.1m, c.DcDcPowerDistribution);
WriteRegs(AcControlRegisters.AcDcDistributionMode, c.AcDcDistributionMode);
}
private void WriteRegs (UInt16 a, Decimal res = 1.0m, params Decimal[] regs) => ModbusTcpClient.WriteRegisters(a, regs.ToUInt16(res));
private void WriteRegs (UInt16 a, params IConvertible[] regs) => ModbusTcpClient.WriteRegisters(a, regs.Select(v => v.ConvertTo<UInt16>()).ToArray());
private void WriteRegs (UInt16 a, params UInt16[] regs) => ModbusTcpClient.WriteRegisters(a, regs);
private void WriteCoils(UInt16 a, params Boolean[] coils) => ModbusTcpClient.WriteMultipleCoils(a, coils);
private static Decimal GetPhi(Decimal cosPhi) => cosPhi.Clamp(-1m, 1m).Apply(ACos);
public TruConvertAcStatus? ReadStatus()
{
try
{
return TryReadStatus();
}
catch (Exception e)
{
ModbusTcpClient.CloseConnection();
Console.WriteLine("Failed to read inverter status");
e.Message.WriteLine();
return null;
}
}
private TruConvertAcStatus TryReadStatus()
{
// Console.WriteLine("Reading Ac Device");
var acSerialNumber = ModbusTcpClient.ReadInputRegisters(2009, 2);
var acActualMain = ModbusTcpClient.ReadInputRegisters(5001, 3);
var acActualAcDc = ModbusTcpClient.ReadInputRegisters(5021, 9);
var acActualAcDc2 = ModbusTcpClient.ReadInputRegisters(5031, 1);
var acActualAcDc3 = ModbusTcpClient.ReadInputRegisters(5131, 6);
var acActualMeasurement = ModbusTcpClient.ReadInputRegisters(5141, 3);
var acActualMeasurement1 = ModbusTcpClient.ReadInputRegisters(5151, 3);
var acActualMeasurement2 = ModbusTcpClient.ReadInputRegisters(5161, 3);
var acActualMeasurement3 = ModbusTcpClient.ReadInputRegisters(5171, 3);
var acActualMeasurement4 = ModbusTcpClient.ReadInputRegisters(5187, 2);
var acActualMeasurement5 = ModbusTcpClient.ReadInputRegisters(5189, 2);
var acActualMeasurement6 = ModbusTcpClient.ReadInputRegisters(5191, 2);
var acActualMeasurement7 = ModbusTcpClient.ReadInputRegisters(5201, 1);
var acActualMeasurement8 = ModbusTcpClient.ReadInputRegisters(5211, 4);
var acActualMeasurement9 = ModbusTcpClient.ReadInputRegisters(5221, 2);
var acActualTemp = ModbusTcpClient.ReadInputRegisters(5501, 1);
var acWarningValues = ModbusTcpClient.ReadInputRegisters(2402, 22);
var acAlarmValues = ModbusTcpClient.ReadInputRegisters(2809, 22);
var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1);
var warnings = Enumerable
.Range(2404, 20)
.Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo<WarningMessage>())
.ToArray();
var alarms = Enumerable
.Range(2811, 20)
.Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo<AlarmMessage>())
.Where(m => m != AlarmMessage.NoAlarm)
.ToArray();
var dcPower = acActualMeasurement.GetInt16(5141) * 1m + acActualMeasurement.GetInt16(5142) * 1m + acActualMeasurement.GetInt16(5143) * 1m;
var dcVoltage = acActualMeasurement8.GetUInt16(5214) + acActualMeasurement8.GetUInt16(5213);
var dcCurrent = dcVoltage != 0m
? dcPower / dcVoltage
: 0m;
// //acActualMeasurement
// PowerAcL1 = acActualMeasurement.GetInt16(5141) * 1m, // in Watt
// PowerAcL2 = acActualMeasurement.GetInt16(5142) * 1m, // in Watt
// PowerAcL3 = acActualMeasurement.GetInt16(5143) * 1m, // in Watt
//
//acActualMeasurement1
// PhaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m,
// PhaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m,
// PhaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m,
//acActualMeasurement2
// GridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m,
// GridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m,
// GridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m,
//acActualMeasurement3
// CosPhiL1 = acActualMeasurement3.GetInt16(5171) * 0.01m,
// CosPhiL2 = acActualMeasurement3.GetInt16(5172) * 0.01m,
// CosPhiL3 = acActualMeasurement3.GetInt16(5173) * 0.01m,
// //acActualMeasurement4
// SumPowerL1 = acActualMeasurement4.GetUInt32(5187) * 1m, // in Watt
// //acActualMeasurement5
// SumPowerL2 = acActualMeasurement5.GetUInt32(5189) * 1m, // in Watt
// //acActualMeasurement6
// SumPowerL3 = acActualMeasurement6.GetUInt32(5191) * 1m, // in Watt
// //acActualMeasurement9
// GridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m,
//acActualMeasurement11
// VoltageIntNtoPE = acActualMeasurement9.GetInt16(5221) * 0.1m,
// VoltageExtNtoPE = acActualMeasurement9.GetInt16(5222) * 0.1m,
//
// ApparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m, // in VA
// ApparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m, // in VA
// ApparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m, // in VA
var apparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m;
var apparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m;
var apparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m;
var powerAcL1 = acActualMeasurement.GetInt16(5141) * 1m; // in Watt
var powerAcL2 = acActualMeasurement.GetInt16(5142) * 1m; // in Watt
var powerAcL3 = acActualMeasurement.GetInt16(5143) * 1m; // in Watt
var phaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m;
var phaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m;
var phaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m;
var gridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m;
var gridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m;
var gridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m;
var gridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m;
return new TruConvertAcStatus
{
Ac = new Ac3Bus
{
Frequency = gridFrequency,
L1 = new AcPhase
{
Voltage = gridVoltageL1,
Current = phaseCurrentL1,
Phi = ACos(powerAcL1 / apparentPowerAcL1), // TODO: 2pi
},
L2 = new AcPhase
{
Voltage = gridVoltageL2,
Current = phaseCurrentL2,
Phi = ACos(powerAcL2 / apparentPowerAcL2), // TODO: 2pi
},
L3 = new AcPhase
{
Voltage = gridVoltageL3,
Current = phaseCurrentL3,
Phi = ACos(powerAcL3 / apparentPowerAcL3), // TODO: 2pi
}
},
Dc = new DcBus
{
Current = dcCurrent,
Voltage = dcVoltage,
},
MainState = acActualMain.GetInt16(5001).ConvertTo<MainState>(),
Alarms = alarms,
Warnings = warnings,
GridType = acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(),
SerialNumber = acSerialNumber.GetInt32(2009).ToString(), // TODO: why tostring ?
NumberOfConnectedSlaves = acActualMain.GetUInt16(5002),
NumberOfConnectedSubSlaves = acActualMain.GetUInt16(5003),
AcDcNominalGridFrequency = acActualAcDc.GetUInt16(5021) * 0.1m,
AcDcNominalGridVoltage = acActualAcDc.GetUInt16(5022),
AcDcActNominalPower = acActualAcDc.GetUInt16(5023),
AcDcPowerLimitingStatusAct = acActualAcDc.GetUInt16(5025),
AcDcDcVoltageReference = acActualAcDc.GetUInt16(5026), // DC link reference
AcDcDcLinkVoltageMinAct = acActualAcDc.GetUInt16(5027), // DC link min voltage
AcDcDcLinkVoltageMaxAct = acActualAcDc.GetUInt16(5028), // DC link max voltage
AcDcDcLinkChargedMinVoltage = acActualAcDc.GetUInt16(5029) * 0.01m,
AcDcStmActCustomer = acActualAcDc2.GetUInt16(5031), //need to check
AcDcOverloadIntegratorStatusL1 = acActualAcDc3.GetUInt16(5134) * 0.1m,
AcDcOverloadIntegratorStatusL2 = acActualAcDc3.GetUInt16(5135) * 0.1m,
AcDcOverloadIntegratorStatusL3 = acActualAcDc3.GetUInt16(5136) * 0.1m,
AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
ActualDcLinkVoltageUpperHalf = acActualMeasurement8.GetUInt16(5211),
ActualDcLinkVoltageLowerHalf = acActualMeasurement8.GetUInt16(5212),
ActualDcLinkVoltageUpperHalfExt = acActualMeasurement8.GetUInt16(5213),
ActualDcLinkVoltageLowerHalfExt = acActualMeasurement8.GetUInt16(5214),
VoltageIntNtoPe = acActualMeasurement9.GetInt16(5221) * 0.1m,
VoltageExtNtoPe = acActualMeasurement9.GetInt16(5222) * 0.1m,
InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m,
};
// (
// Ac: new Ac3Bus
// (
// new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)),
// new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)),
// new AcPhase(gridVoltageL3,phaseCurrentL3, ACos(powerAcL3/apparentPowerAcL3)),
// gridFrequency // Gird Frequency
// ),
// Dc: new DcConnection(dcVoltage, dcCurrent),
//
// SerialNumber : acSerialNumber.GetInt32(2009).ToString(),
//
// // acActualMainValues
// MainState : acActualMain.GetInt16(5001).ConvertTo<MainState>(),
// NumberOfConnectedSlaves : acActualMain.GetUInt16(5002),
// NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003),
//
// //acActualAcDc
// AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m,
// AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022),
// AcDcActNominalPower : acActualAcDc.GetUInt16(5023),
// AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(),
// AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025),
// AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference
// AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage
// AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage
// AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m,
//
// //ac Actual AcDc 2
// AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check
// AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m,
// AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m,
// AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m,
// AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
//
// //acActualMeasurement10
// ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211),
// ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212),
// ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213),
// ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214),
//
// VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m,
// VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m,
// //acActualTemp
// InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m,
//
// Warnings : warnings,
// Alarms : alarms
// );
}
}

View File

@ -1,45 +0,0 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
using InnovEnergy.Lib.StatusApi;
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using AlarmMessages = IReadOnlyList<AlarmMessage>;
using WarningMessages = IReadOnlyList<WarningMessage>;
// ReSharper disable UnusedAutoPropertyAccessor.Global
#pragma warning disable CS8618
public record TruConvertAcStatus : ThreePhaseInverterStatus
{
public MainState MainState { get; init; }
public String SerialNumber { get; init; }
public AcDcGridType GridType { get; init; }
public WarningMessages Warnings { get; init; }
public AlarmMessages Alarms { get; init; }
public Decimal NumberOfConnectedSlaves { get; init; }
public Decimal NumberOfConnectedSubSlaves { get; init; }
public Frequency AcDcNominalGridFrequency { get; init; }
public Voltage AcDcNominalGridVoltage { get; init; }
public Power AcDcActNominalPower { get; init; }
public Decimal AcDcPowerLimitingStatusAct { get; init; } // TODO: enum
public Voltage AcDcDcVoltageReference { get; init; }
public Voltage AcDcDcLinkVoltageMinAct { get; init; }
public Voltage AcDcDcLinkVoltageMaxAct { get; init; }
public Voltage AcDcDcLinkChargedMinVoltage { get; init; }
public Decimal AcDcStmActCustomer { get; init; }
public Decimal AcDcOverloadIntegratorStatusL1 { get; init; }
public Decimal AcDcOverloadIntegratorStatusL2 { get; init; }
public Decimal AcDcOverloadIntegratorStatusL3 { get; init; }
public Power AcSignedPowerValue { get; init; }
public Voltage ActualDcLinkVoltageUpperHalf { get; init; }
public Voltage ActualDcLinkVoltageLowerHalf { get; init; }
public Voltage ActualDcLinkVoltageUpperHalfExt { get; init; }
public Voltage ActualDcLinkVoltageLowerHalfExt { get; init; }
public Voltage VoltageIntNtoPe { get; init; }
public Voltage VoltageExtNtoPe { get; init; }
public Temperature InletAirTemperature { get; init; }
}

View File

@ -1,24 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum WarningMessage
{
ERR_WARN_FAN = 10500, //AC-DC module warning
ERR_WARN_I_OFFSET = 10503, //AC-DC module warning
ERR_WARN_VG_OFFSET = 10504, //AC-DC module warning
ERR_WARN_VC_OFFSET = 10505, //AC-DC module warning
ERR_WARN_DC_OFFSET = 10506, //AC-DC module warning
ERR_WARN_NTC_PROTECT = 10507, //DC-link circuit need more time for cool down
ERR_WARN_AIR_TEMP = 10508, //Overtemperature inlet air: power is derated
SurgeDetected = 10509, //Temporary overvoltage in grid measurement detected (surge)
ERR_WARN_TEMP_DERATING = 11021, //Temperature derating active
ERR_WARN_OVERLOAD = 11022, //Overload handling is active
ERR_WARN_RUNTIME_EEPROM = 11023, //AC-DC module warning
ERR_WARN_OVERCURRENT = 11024 //Overcurrent handling is active
}

View File

@ -1,45 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum AlarmMessage
{
NoAlarm = 0, // No Alarm
Iboosterhv = 60081, // DC-DC power module alarm
Iboosterhv1 = 60082, // wildcard to allocate TypeMessageNumber
Iboosterhv2 = 60083, // wildcard to allocate TypeMessageNumber
Ibat = 60084, // DC-DC power module alarm
Ibat1 = 60085, // wildcard to allocate TypeMessageNumber
Ibat2 = 60086, // wildcard to allocate TypeMessageNumber
Itrafolv = 60087, // DC-DC power module alarm
Itrafolv1 = 60088, // wildcard to allocate TypeMessageNumber
Itrafolv2 = 60089, // wildcard to allocate TypeMessageNumber
UbatHigh = 60090, // Battery overvoltage
UbatHigh1 = 60091, // wildcard to allocate TypeMessageNumber
UbatHigh2 = 60092, // wildcard to allocate TypeMessageNumber
Udclp = 60093, // DC link overvoltage
Udclp1 = 60094, // wildcard to allocate TypeMessageNumber
Udclp2 = 60095, // wildcard to allocate TypeMessageNumber
Udcln = 60096, // DC link overvoltage (lower half)
Udcln1 = 60097, // wildcard to allocate TypeMessageNumber
Udcln2 = 60098, // wildcard to allocate TypeMessageNumber
Udclllc = 60099, // DC-DC power module alarm
Udclllc1 = 60100, // wildcard to allocate TypeMessageNumber
Udclllc2 = 60101, // wildcard to allocate TypeMessageNumber
UdclLow = 60102, // DC link voltage too low for operation
UdclLow1 = 60103, // wildcard to allocate TypeMessageNumber
UdclLow2 = 60104, // wildcard to allocate TypeMessageNumber
VauxHigh = 60700, // Auxiliary supply overvoltage
VauxHigh1 = 60701, // wildcard to allocate TypeMessageNumber
VauxHigh2 = 60702, // wildcard to allocate TypeMessageNumber
UbatLow = 60142, // Battery undervoltage
UbatLow1 = 60143, // wildcard to allocate TypeMessageNumber
UbatLow2 = 60144, // wildcard to allocate TypeMessageNumber
VauxLow = 60703, // Auxiliary supply undervoltage
VauxLow1 = 60704, // wildcard to allocate TypeMessageNumber
VauxLow2 = 60705, // wildcard to allocate TypeMessageNumber
IbatIboosterPlausi = 60197, // DC-DC power module alarm
}

View File

@ -0,0 +1,22 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
public class CurrentControl
{
public Current CurrentSetpoint
{
get => _Self.DcDcCurrentSetpoint;
set => _Self.DcDcCurrentSetpoint = value.Value;
}
public Current MaxCurrentChangePerMs
{
get => _Self.MaxCurrentChangePerMs;
set => _Self.MaxCurrentChangePerMs = value.Value;
}
private readonly DcDcRecord _Self;
internal CurrentControl(DcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
public enum DcControlMode : UInt16
{
CurrentSetpoint = 0,
VoltageDroop = 1
}

View File

@ -0,0 +1,43 @@
using InnovEnergy.Lib.Units.Power;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
// https://stackoverflow.com/q/63724308
public class DcDcControl
{
public Vcc Vcc => new(_Self);
public VoltageLimits VoltageLimits => new(_Self);
public DroopControl DroopControl => new(_Self);
public CurrentControl CurrentControl => new(_Self);
public ActivePower MaxDcPower
{
get => _Self.MaxDcPower;
set => _Self.MaxDcPower = value.Value;
}
public DcControlMode ControlMode
{
get => _Self.DcControlMode;
set => _Self.DcControlMode = value;
}
public Boolean ResetAlarmsAndWarnings
{
get => _Self.ResetAlarmsAndWarnings;
set => _Self.ResetAlarmsAndWarnings = value;
}
public Boolean PowerStageEnable
{
get => _Self.PowerStageEnable;
set => _Self.PowerStageEnable = value;
}
private readonly DcDcRecord _Self;
internal DcDcControl(DcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,33 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
public class DroopControl
{
public Voltage ReferenceVoltage
{
get => _Self.DroopControlReferenceVoltage;
set => _Self.DroopControlReferenceVoltage = value.Value;
}
public Voltage LowerVoltage
{
get => _Self.DroopControlLowerVoltage;
set => _Self.DroopControlLowerVoltage = value.Value;
}
public Voltage UpperVoltage
{
get => _Self.DroopControlUpperVoltage;
set => _Self.DroopControlUpperVoltage = value.Value;
}
public Voltage VoltageDeadband
{
get => _Self.DroopControlVoltageDeadband;
set => _Self.DroopControlVoltageDeadband = value.Value;
}
private readonly DcDcRecord _Self;
internal DroopControl(DcDcRecord self) => _Self = self;
};

View File

@ -0,0 +1,27 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
public class Vcc
{
public Current EndPointCurrent
{
get => _Self.VccEndPointCurrent;
set => _Self.VccEndPointCurrent = value.Value;
}
public Voltage EndPointVoltage
{
get => _Self.VccEndPointCurrent;
set => _Self.VccEndPointCurrent = value.Value;
}
public Current StartPointCurrent
{
get => _Self.VccStartPointCurrent;
set => _Self.VccStartPointCurrent = value.Value;
}
private readonly DcDcRecord _Self;
internal Vcc(DcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,33 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
public class VoltageLimits
{
public Voltage MinBatteryVoltageAlarm
{
get => _Self.MinVoltageAlarm;
set => _Self.MinVoltageAlarm = value.Value;
}
public Voltage MaxBatteryVoltageAlarm
{
get => _Self.MaxVoltageAlarm;
set => _Self.MaxVoltageAlarm = value.Value;
}
public Voltage MinBatteryVoltage
{
get => _Self.MinBatteryVoltage;
set => _Self.MinBatteryVoltage = value.Value;
}
public Voltage MaxBatteryVoltage
{
get => _Self.MaxBatteryVoltage;
set => _Self.MaxBatteryVoltage = value.Value;
}
private readonly DcDcRecord _Self;
internal VoltageLimits(DcDcRecord self) => _Self = self;
}

View File

@ -1,48 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
public static class DcControlRegisters
{
public const UInt16 Date = 1001;
public const UInt16 Time = 1003;
public const UInt16 IpAddress = 1005;
public const UInt16 Subnet = 1007;
public const UInt16 Gateway = 1009;
public const UInt16 ResetParamToDefault = 1011;
public const UInt16 TimeoutCommunication = 1017;
public const UInt16 RestartFlag = 1018;
public const UInt16 ConnectedSystemConfig = 1019;
public const UInt16 UpdateSwTrigger = 1027;
public const UInt16 AutomaticSwUpdate = 1028;
public const UInt16 CustomerValuesSaveReset = 1029;
public const UInt16 SerialNumberSystemControl = 2001;
public const UInt16 SerialNumberDcDc = 2003;
public const UInt16 MaterialNumberDcDc = 2005;
public const UInt16 PowerStageOperation = 4001;
public const UInt16 ResetsAlarmAndWarning = 4003;
public const UInt16 SlaveAddress = 4008;
public const UInt16 SlaveAlarmPolicy = 4009;
public const UInt16 SubSlaveAddress = 4011;
public const UInt16 ModbusSlaveId = 4012;
public const UInt16 MaximumBatteryVoltage = 4101;
public const UInt16 MinimumBatteryVoltage = 4102;
public const UInt16 MaximumBatteryVoltageR = 4103; // same as the two previous ones just Different resolution// not sure
public const UInt16 MinimumBatteryVoltageR = 4104; // same as the two previous ones just Different resolution// not sure
public const UInt16 MaximumBatteryChargingCurrent = 4107;
public const UInt16 MaximumBatteryDischargingCurrent = 4110;
public const UInt16 MaximumVoltageOfVcc = 4113;
public const UInt16 MaximumCurrentOfVcc = 4116;
public const UInt16 StartCurrentOfVcc = 4119;
public const UInt16 MaximalPowerAtDc = 4122;
public const UInt16 MaximumVoltageAlarmThreshold = 4125;
public const UInt16 MinimumVoltageAlarmThreshold = 4128;
//DcDc operation only
public const UInt16 BatteryCurrentSet = 4501;
public const UInt16 DynamicCurrentPerMillisecond = 4502;
public const UInt16 DcLinkControlMode = 4505;
public const UInt16 ReferenceVoltage = 4506;
public const UInt16 UpperVoltageWindow = 4507;
public const UInt16 LowerVoltageWindow = 4508;
public const UInt16 VoltageDeadBand = 4509;
}

View File

@ -1,12 +0,0 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[Flags]
public enum DcCurrentLimitState : UInt16
{
PMax = 0b_00001,
MaxChargingCurrent = 0b_00010,
MaxDischargingCurrent = 0b_00100,
MaxBatteryVoltage = 0b_01000,
MinBatteryVoltage = 0b_10000,
}

View File

@ -0,0 +1,42 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
public class DcDcDevicesRecord
{
private static readonly DcBus NoDevice = DcBus.FromVoltageCurrent(0, 0);
public DcDcDevicesRecord(SystemControlRegisters? systemControl, IReadOnlyList<DcDcRecord> devices)
{
SystemControl = systemControl;
Devices = devices;
}
public DcStatus Dc => new DcStatus
{
Battery = Devices.Count == 0 ? NoDevice
: DcBus.FromVoltageCurrent
(
Devices.Average(r => r.Status.Dc.Battery.Voltage.Value),
Devices.Sum(r => r.Status.Dc.Battery.Current.Value)
),
Link = Devices.Count == 0
? NoDevice
: DcBus.FromVoltageCurrent
(
Devices.Average(r => r.Status.Dc.Link.Voltage.Value),
Devices.Sum(r => r.Status.Dc.Link.Current.Value)
)
};
public SystemControlRegisters? SystemControl { get; }
public IReadOnlyList<DcDcRecord> Devices { get; }
public IEnumerable<AlarmMessage> Alarms => Devices.SelectMany(d => d.Status.Alarms ).Distinct();
public IEnumerable<WarningMessage> Warnings => Devices.SelectMany(d => d.Status.Warnings).Distinct();
public static DcDcDevicesRecord Null { get; } = new DcDcDevicesRecord(null, Array.Empty<DcDcRecord>());
}

View File

@ -0,0 +1,51 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
#pragma warning disable CS0649
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
public partial class DcDcRecord
{
private IEnumerable<AlarmMessage> GetAlarms()
{
yield return Alarm1;
yield return Alarm2;
yield return Alarm3;
yield return Alarm4;
yield return Alarm5;
yield return Alarm6;
yield return Alarm7;
yield return Alarm8;
yield return Alarm9;
yield return Alarm10;
yield return Alarm11;
yield return Alarm12;
yield return Alarm13;
yield return Alarm14;
yield return Alarm15;
yield return Alarm16;
yield return Alarm17;
yield return Alarm18;
yield return Alarm19;
yield return Alarm20;
}
internal IReadOnlyList<AlarmMessage> Alarms => GetAlarms()
.Take(NumberOfAlarms)
.Where(IsDcDcAlarm)
.ToList();
private static Boolean IsDcDcAlarm(AlarmMessage alarm) => (UInt16)alarm >= 60000;
}

View File

@ -0,0 +1,116 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
#pragma warning disable CS0649
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
public partial class DcDcRecord
{
//[Coil(4000)]
[HoldingRegister(4000)] internal Boolean PowerStageEnable ;
//[Coil(4002)]
[HoldingRegister(4002)] internal Boolean ResetAlarmsAndWarnings ;
[HoldingRegister(4100, Scale = .01)] internal Double MaxBatteryVoltage ;
[HoldingRegister(4101, Scale = .01)] internal Double MinBatteryVoltage ;
[HoldingRegister(4112, Scale = .1)] internal Double VccEndPointVoltage ;
[HoldingRegister(4115)] internal Double VccEndPointCurrent ;
[HoldingRegister(4118)] internal Double VccStartPointCurrent ;
[HoldingRegister(4118)] internal Double MaxDcPower ;
[HoldingRegister(4124, Scale = .1)] internal Double MaxVoltageAlarm ;
[HoldingRegister(4127, Scale = .1)] internal Double MinVoltageAlarm ;
[HoldingRegister(4500)] internal Double DcDcCurrentSetpoint ;
[HoldingRegister(4501, Scale = .01)] internal Double MaxCurrentChangePerMs ;
[HoldingRegister(4504)] internal DcControlMode DcControlMode ;
[HoldingRegister(4505, Scale = .1)] internal Double DroopControlReferenceVoltage ;
[HoldingRegister(4506, Scale = .1)] internal Double DroopControlUpperVoltage ;
[HoldingRegister(4507, Scale = .1)] internal Double DroopControlLowerVoltage ;
[HoldingRegister(4508, Scale = .1)] internal Double DroopControlVoltageDeadband ;
[InputRegister(5100, Scale = .1)] internal Double BatteryVoltage ;
[InputRegister(5110)] internal Double BatteryCurrent ;
[InputRegister(5123)] internal BatteryPowerLimit BatteryPowerLimit ;
[InputRegister(5126, Scale = .1)] internal Double OverloadCapacity ;
[InputRegister(5127)] internal Double DcLinkVoltage;
// TODO: [InputRegister(5300)]
[InputRegister(5510)] internal Double InletAirTemperature ;
[InputRegister(5511)] internal Double HighVoltageModuleTemperature ;
[InputRegister(5512)] internal Double LowVoltageModuleTemperature ;
[InputRegister(2402)] internal UInt16 NumberOfWarnings;
[InputRegister(2403)] internal WarningMessage Warning1;
[InputRegister(2404)] internal WarningMessage Warning2;
[InputRegister(2405)] internal WarningMessage Warning3;
[InputRegister(2406)] internal WarningMessage Warning4;
[InputRegister(2407)] internal WarningMessage Warning5;
[InputRegister(2408)] internal WarningMessage Warning6;
[InputRegister(2409)] internal WarningMessage Warning7;
[InputRegister(2410)] internal WarningMessage Warning8;
[InputRegister(2411)] internal WarningMessage Warning9;
[InputRegister(2412)] internal WarningMessage Warning10;
[InputRegister(2413)] internal WarningMessage Warning11;
[InputRegister(2414)] internal WarningMessage Warning12;
[InputRegister(2415)] internal WarningMessage Warning13;
[InputRegister(2416)] internal WarningMessage Warning14;
[InputRegister(2417)] internal WarningMessage Warning15;
[InputRegister(2418)] internal WarningMessage Warning16;
[InputRegister(2419)] internal WarningMessage Warning17;
[InputRegister(2420)] internal WarningMessage Warning18;
[InputRegister(2421)] internal WarningMessage Warning19;
[InputRegister(2422)] internal WarningMessage Warning20;
[InputRegister(2809)] internal UInt16 NumberOfAlarms;
[InputRegister(2810)] internal AlarmMessage Alarm1;
[InputRegister(2811)] internal AlarmMessage Alarm2;
[InputRegister(2812)] internal AlarmMessage Alarm3;
[InputRegister(2813)] internal AlarmMessage Alarm4;
[InputRegister(2814)] internal AlarmMessage Alarm5;
[InputRegister(2815)] internal AlarmMessage Alarm6;
[InputRegister(2816)] internal AlarmMessage Alarm7;
[InputRegister(2817)] internal AlarmMessage Alarm8;
[InputRegister(2818)] internal AlarmMessage Alarm9;
[InputRegister(2819)] internal AlarmMessage Alarm10;
[InputRegister(2820)] internal AlarmMessage Alarm11;
[InputRegister(2821)] internal AlarmMessage Alarm12;
[InputRegister(2822)] internal AlarmMessage Alarm13;
[InputRegister(2823)] internal AlarmMessage Alarm14;
[InputRegister(2824)] internal AlarmMessage Alarm15;
[InputRegister(2825)] internal AlarmMessage Alarm16;
[InputRegister(2826)] internal AlarmMessage Alarm17;
[InputRegister(2827)] internal AlarmMessage Alarm18;
[InputRegister(2828)] internal AlarmMessage Alarm19;
[InputRegister(2829)] internal AlarmMessage Alarm20;
// #region IDcDc
//
// internal DcBus DcLeft => DcBus.FromVoltageCurrent(DcLinkVoltage, Double.NaN); // HV current not measured
// internal DcBus DcRight => DcBus.FromVoltageCurrent(BatteryVoltage, BatteryCurrent);
//
// #endregion IDcDc
}

View File

@ -0,0 +1,52 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
#pragma warning disable CS0649
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
public partial class DcDcRecord
{
private IEnumerable<WarningMessage> GetWarnings()
{
yield return Warning1;
yield return Warning2;
yield return Warning3;
yield return Warning4;
yield return Warning5;
yield return Warning6;
yield return Warning7;
yield return Warning8;
yield return Warning9;
yield return Warning10;
yield return Warning11;
yield return Warning12;
yield return Warning13;
yield return Warning14;
yield return Warning15;
yield return Warning16;
yield return Warning17;
yield return Warning18;
yield return Warning19;
yield return Warning20;
}
internal IReadOnlyList<WarningMessage> Warnings => GetWarnings()
.Take(NumberOfWarnings)
.Where(IsDcDcWarning)
.ToList();
private static Boolean IsDcDcWarning(WarningMessage warning) => (UInt16)warning is >= 11000 and < 12000;
}

View File

@ -0,0 +1,10 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
public partial class DcDcRecord
{
public DcDcStatus Status => new(this);
public DcDcControl Control => new(this);
}

View File

@ -0,0 +1,73 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum AlarmMessage
{
NoAlarm = 0,
Iboosterhv = 60081,
Iboosterhv1 = 60082,
Iboosterhv2 = 60083,
Ibat = 60084,
Ibat1 = 60085,
Ibat2 = 60086,
Itrafolv = 60087,
Itrafolv2 = 60089,
BatteryVoltageTooHigh = 60090,
BatteryVoltageTooHigh1 = 60091,
BatteryVoltageTooHigh2 = 60092,
DcLinkVoltageTooHigh = 60093,
DcLinkVoltageTooHigh1 = 60094,
DcLinkVoltageTooHigh2 = 60095,
Udcln = 60096,
Udcln1 = 60097,
Udcln2 = 60098,
Udclllc = 60099,
Udclllc1 = 60100,
Udclllc2 = 60101,
DcLinkVoltageTooLow = 60102,
DcLinkVoltageTooLow1 = 60103,
DcLinkVoltageTooLow2 = 60104,
BatteryVoltageUnderTresholdSetting = 60129,
Rs485CommunicationAlarm = 60132,
BatteryVoltageTooLow = 60142,
BatteryVoltageTooLow1 = 60143,
BatteryVoltageTooLow2 = 60144,
WrongDcPolarity = 60145,
BatteryVoltageOverTresholdSetting = 60150,
AmbientTemperatureTooHigh = 60168,
AmbientTemperatureTooLow = 60186,
FanDefectiveOrStuck = 60192,
IbatIboosterPlausi = 60197,
PreChargeConditionsCouldNotBeMet = 60200,
AttachedLoadOnDcLinkCannotBeHandled = 60201,
DcLinkCouldNotBeCharged = 60202,
AuxiliarySupplyOvervoltage = 60700,
AuxiliarySupplyOvervoltage1 = 60701,
AuxiliarySupplyOvervoltage2 = 60702,
AuxiliarySupplyUndervoltage = 60703,
AuxiliarySupplyUndervoltage1 = 60704,
AuxiliarySupplyUndervoltage2 = 60705,
DcDcPrecharge = 60200, // DC-DC Precharge Conditions could not be met.
}

View File

@ -0,0 +1,11 @@
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
[Flags]
public enum BatteryPowerLimit : UInt16
{
MaxPower = 0b_00001,
MaxChargeCurrent = 0b_00010,
MaxDischargeCurrent = 0b_00100,
MaxVoltage = 0b_01000,
MinVoltage = 0b_10000,
}

View File

@ -0,0 +1,118 @@
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
public class DcDcStatus
{
public DcStatus Dc
{
get
{
// if battery voltage is 0, Trumpf reports a nonsensical battery current
var batteryCurrent = _Self.BatteryVoltage == 0
? 0
: _Self.BatteryCurrent;
// link current is not measured by trumpf, calculate it assuming 0 losses
// TODO: calculate losses
var linkCurrent = batteryCurrent == 0
? 0
: _Self.BatteryVoltage * _Self.BatteryCurrent / _Self.DcLinkVoltage;
return new()
{
Link = DcBus.FromVoltageCurrent
(
voltage: _Self.DcLinkVoltage,
current: linkCurrent
),
Battery = DcBus.FromVoltageCurrent
(
voltage: _Self.BatteryVoltage,
current: batteryCurrent
)
};
}
}
public Percent OverloadCapacity => _Self.OverloadCapacity;
public Temperatures Temperature => new(_Self);
public IReadOnlyList<BatteryPowerLimit> PowerLimitedBy => ListActivePowerLimits();
public IReadOnlyList<AlarmMessage> Alarms => ListAlarms();
public IReadOnlyList<WarningMessage> Warnings => ListWarnings();
///////////////////////////////////////////////////////////////////////////////
private AlarmMessage[] ListAlarms() => EnumerateAlarms()
.Take(_Self.NumberOfAlarms)
.ToArray(_Self.NumberOfAlarms);
private WarningMessage[] ListWarnings() => EnumerateWarnings()
.Take(_Self.NumberOfWarnings)
.ToArray(_Self.NumberOfWarnings);
private IEnumerable<WarningMessage> EnumerateWarnings()
{
yield return _Self.Warning1;
yield return _Self.Warning2;
yield return _Self.Warning3;
yield return _Self.Warning4;
yield return _Self.Warning5;
yield return _Self.Warning6;
yield return _Self.Warning7;
yield return _Self.Warning8;
yield return _Self.Warning9;
yield return _Self.Warning10;
yield return _Self.Warning11;
yield return _Self.Warning12;
yield return _Self.Warning13;
yield return _Self.Warning14;
yield return _Self.Warning15;
yield return _Self.Warning16;
yield return _Self.Warning17;
yield return _Self.Warning18;
yield return _Self.Warning19;
yield return _Self.Warning20;
}
private IEnumerable<AlarmMessage> EnumerateAlarms()
{
yield return _Self.Alarm1;
yield return _Self.Alarm2;
yield return _Self.Alarm3;
yield return _Self.Alarm4;
yield return _Self.Alarm5;
yield return _Self.Alarm6;
yield return _Self.Alarm7;
yield return _Self.Alarm8;
yield return _Self.Alarm9;
yield return _Self.Alarm10;
yield return _Self.Alarm11;
yield return _Self.Alarm12;
yield return _Self.Alarm13;
yield return _Self.Alarm14;
yield return _Self.Alarm15;
yield return _Self.Alarm16;
yield return _Self.Alarm17;
yield return _Self.Alarm18;
yield return _Self.Alarm19;
yield return _Self.Alarm20;
}
private List<BatteryPowerLimit> ListActivePowerLimits()
{
return Utils
.Utils
.GetEnumValues<BatteryPowerLimit>()
.Where(t => _Self.BatteryPowerLimit.HasFlag(t))
.ToList();
}
private readonly DcDcRecord _Self;
internal DcDcStatus(DcDcRecord self) => _Self = self;
}

View File

@ -0,0 +1,9 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
public class DcStatus
{
public DcBus Link { get; init; }
public DcBus Battery { get; init; }
}

View File

@ -0,0 +1,14 @@
using InnovEnergy.Lib.Units;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
public class Temperatures
{
public Temperature InletAir => _Self.InletAirTemperature;
public Temperature HighVoltageModule => _Self.HighVoltageModuleTemperature;
public Temperature LowVoltageModule => _Self.LowVoltageModuleTemperature;
internal Temperatures(DcDcRecord self) => _Self = self;
private readonly DcDcRecord _Self;
}

View File

@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
@ -29,5 +29,4 @@ public enum WarningMessage
HveepromWrite1 = 11018, //DC-DC module warning
HveepromWrite2 = 11019, //DC-DC module warning
HveepromWrite3 = 11020 //DC-DC module warning
}

View File

@ -7,8 +7,8 @@
<ItemGroup>
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../TruConvert/TruConvert.csproj" />
<ProjectReference Include="../../../StatusApi/StatusApi.csproj" />
<ProjectReference Include="../SystemControl/SystemControl.csproj" />
</ItemGroup>

View File

@ -1,44 +0,0 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
public record TruConvertDcControl
{
public UInt32 Date { get; init;}
public UInt32 Time { get; init;}
public UInt32 IpAddress { get; init;} //= 0x C0A80102;
public UInt32 Subnet { get; init;} //= 0x FFFFFF00;
public UInt32 Gateway { get; init;} //= 0x C0A80102;
public Boolean ResetParamToDefault { get; init;} = false ; // Coil
public TimeSpan TimeoutForCommunication { get; init;} = DefaultCommunicationTimeOut;
public Boolean RestartFlag { get; init;} = false ; // Coil
public SystemConfig ConnectedSystemConfig { get; init;} = SystemConfig.NoConfig ;
public UInt16 UpdateSwTrigger { get; init;} = 0 ;
public UInt16 AutomaticSwUpdate { get; init;} = 0 ;
public UInt16 CustomerValuesSaveReset { get; init;} = 0 ;
public UInt32 SerialNumberSystemControl { get; init;}
public UInt32 SerialNumberDcDc { get; init;}
public UInt32 MaterialNumberDcDc { get; init;}
public Boolean PowerStageEnable { get; init;} = true; //Coil
public Boolean ResetsAlarmAndWarning { get; init;} = false; //Coil
public UInt16 SlaveAddress { get; init;} = Slave.Broadcast;
public UInt16 SlaveAlarmPolicy { get; init;} = 0; // this is must be a an enum
public UInt16 SubSlaveAddress { get; init;} = 0;
public Boolean ModbusSlaveId { get; init;} = false; // Coil
public Decimal MaximumBatteryVoltage { get; init;} = 0; // resolution 0.01
public Decimal MinimumBatteryVoltage { get; init;} = 0; // resolution 0.01
public Decimal MaximumBatteryChargingCurrent { get; init;} = 0; // resolution 0.1
public Decimal MaximumBatteryDischargingCurrent { get; init;} = 0; // resolution 0.1
public Decimal MaximalPowerAtDc { get; init;} = 0;
public Decimal MaximumVoltageAlarmThreshold { get; init;} = 55; // resolution 0.1
public Decimal MinimumVoltageAlarmThreshold { get; init;} = 0; // resolution 0.1
public Decimal BatteryCurrentSet { get; init;} = 0; // resolution 1.0
public Decimal DynamicCurrentPerMillisecond { get; init;} = 0; // resolution : 0.01
public Decimal DcLinkControlMode { get; init;} = 0; // Parameter aktiviert/deaktiviert "DC link voltage droop mode"
public Decimal ReferenceVoltage { get; init;} = 800; // resolution : 0.1
public Decimal UpperVoltageWindow { get; init;} = 40; // resolution : 0.1
public Decimal LowerVoltageWindow { get; init;} = 40; // resolution : 0.1
public Decimal VoltageDeadBand { get; init;} = 0; // resolution : 0.1
private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromMinutes(10);
}

View File

@ -0,0 +1,88 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Protocols.Modbus.Channels;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
public class TruConvertDcDcDevices
{
private readonly ModbusDevice<SystemControlRegisters> _SystemControl;
private readonly IEnumerable<ModbusDevice<DcDcRecord>> _DcDcs;
public TruConvertDcDcDevices(String hostname, UInt16 port) : this(new TcpChannel(hostname, port))
{
}
public TruConvertDcDcDevices(Channel transport)
{
var modbusClient = new ModbusTcpClient(transport, 0);
_SystemControl = new ModbusDevice<SystemControlRegisters>(modbusClient);
_DcDcs = Enumerable
.Range(1, Byte.MaxValue - 1)
.Memoize(CreateDcDc);
ModbusDevice<DcDcRecord> CreateDcDc(Int32 i)
{
var mb = new ModbusTcpClient(transport, (Byte)i);
return new ModbusDevice<DcDcRecord>(mb);
}
}
public DcDcDevicesRecord Read()
{
SystemControlRegisters? scStatus;
try
{
scStatus = _SystemControl.Read();
}
catch (Exception e)
{
Console.WriteLine(e);
return DcDcDevicesRecord.Null;
}
var n = scStatus.NumberOfConnectedSlaves;
try
{
var dcDcRecords = _DcDcs
.Take(n)
.Select(dcdc => dcdc.Read())
.ToArray(n);
return new DcDcDevicesRecord(scStatus, dcDcRecords);
}
catch (Exception e)
{
Console.WriteLine(e);
return new DcDcDevicesRecord(scStatus, Array.Empty<DcDcRecord>());
}
}
public void Write(DcDcDevicesRecord r)
{
if (r.SystemControl is not null)
_SystemControl.Write(r.SystemControl); // must run BEFORE the attached devices
foreach (var (ctrl, device) in r.Devices.Zip(_DcDcs))
{
try
{
device.Write(ctrl);
}
catch (Exception e)
{
Console.WriteLine(e);
// TODO: log
}
}
}
}

View File

@ -1,168 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
using static InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.DcControlRegisters;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class TruConvertDcDevice
{
private ModbusTcpClient ModbusTcpClient { get; }
public TruConvertDcDevice(String hostname, UInt16 port = ModbusTcpClient.DefaultPort, Byte slaveAddress = 0)
{
var connection = new ModbusTcpConnection(hostname, port);
ModbusTcpClient = new ModbusTcpClient(connection, slaveAddress);
}
public void WriteControl(TruConvertDcControl c)
{
/*
TODO: maybe later
ModbusTcpClient.WriteRegisters(Date, new[] { dcControl.Date.ConvertTo<UInt16>() });
ModbusTcpClient.WriteRegisters(Time, new[] { dcControl.Time.ConvertTo<UInt16>() });
ModbusTcpClient.WriteRegisters(IpAddress, dcControl.IpAddress.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(Subnet, dcControl.Subnet.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(Gateway, dcControl.Gateway.ConvertTo<UInt16>());
ModbusTcpClient.WriteMultipleCoils(ResetParamToDefault, dcControl.ResetParamToDefault);
ModbusTcpClient.WriteMultipleCoils(RestartFlag, dcControl.RestartFlag);
ModbusTcpClient.WriteRegisters(DcControlRegisters.TimeoutCommunication, dcControl.TimeoutForCommunication.TotalSeconds.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(ConnectedSystemConfig, dcControl.ConnectedSystemConfig.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(UpdateSwTrigger, dcControl.UpdateSwTrigger, dcControl.AutomaticSwUpdate, dcControl.CustomerValuesSaveReset);
ModbusTcpClient.WriteRegisters(SerialNumberSystemControl, dcControl.SerialNumberSystemControl.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(SerialNumberDcDc, dcControl.SerialNumberDcDc.ConvertTo<UInt16>());
ModbusTcpClient.WriteRegisters(MaterialNumberDcDc, dcControl.MaterialNumberDcDc.ConvertTo<UInt16>());
*/
// TODO starting from 4000, evaluate what/if needs updating below 4000
WriteRegs(TimeoutCommunication, c.TimeoutForCommunication.TotalSeconds.ConvertTo<UInt16>());
WriteCoils(PowerStageOperation, c.PowerStageEnable);
WriteCoils(ResetsAlarmAndWarning, c.ResetsAlarmAndWarning);
WriteRegs (SlaveAddress, c.SlaveAddress,
c.SlaveAlarmPolicy);
WriteRegs (SubSlaveAddress, c.SubSlaveAddress);
WriteCoils(ModbusSlaveId, c.ModbusSlaveId);
WriteRegs(MaximumBatteryVoltage, 0.01m, c.MaximumBatteryVoltage,
c.MinimumBatteryVoltage);
WriteRegs(MaximumBatteryChargingCurrent, 0.1m, c.MaximumBatteryChargingCurrent);
WriteRegs(MaximumBatteryDischargingCurrent, 0.1m, c.MaximumBatteryDischargingCurrent);
WriteRegs(MaximalPowerAtDc, 1.0m, c.MaximalPowerAtDc);
WriteRegs(MaximumVoltageAlarmThreshold, 0.1m, c.MaximumVoltageAlarmThreshold);
WriteRegs(MinimumVoltageAlarmThreshold, 0.1m, c.MinimumVoltageAlarmThreshold);
WriteRegs(BatteryCurrentSet, 1.0m, c.BatteryCurrentSet);
WriteRegs(DynamicCurrentPerMillisecond, 0.01m, c.DynamicCurrentPerMillisecond);
WriteRegs(DcLinkControlMode, 1.0m, c.DcLinkControlMode);
WriteRegs(ReferenceVoltage, 0.1m, c.ReferenceVoltage,
c.UpperVoltageWindow,
c.LowerVoltageWindow,
c.VoltageDeadBand);
}
private void WriteRegs (UInt16 a, Decimal res = 1.0m, params Decimal[] regs) => ModbusTcpClient.WriteRegisters(a, regs.ToUInt16(res));
private void WriteRegs (UInt16 a, params UInt16[] regs) => ModbusTcpClient.WriteRegisters(a, regs);
private void WriteCoils(UInt16 a, params Boolean[] coils) => ModbusTcpClient.WriteMultipleCoils(a, coils);
public TruConvertDcStatus? ReadStatus()
{
try
{
return TryReadStatus();
}
catch (Exception)
{
ModbusTcpClient.CloseConnection();
return null;
}
}
private static IEnumerable<DcCurrentLimitState> GetFlags(UInt16 input)
{
var ls = (DcCurrentLimitState)input;
return Enum
.GetValues<DcCurrentLimitState>()
.Where(f => ls.HasFlag(f));
}
private TruConvertDcStatus TryReadStatus()
{
// Console.WriteLine("Reading DC Device");
var dcPrValMain = ModbusTcpClient.ReadInputRegisters(5001, 3);
var dcBatteryValue = ModbusTcpClient.ReadInputRegisters(5101, 1);
var dcBatteryValue2 = ModbusTcpClient.ReadInputRegisters(5111, 1);
var dcBatteryValue3 = ModbusTcpClient.ReadInputRegisters(5114, 2);
var dcBatteryValue4 = ModbusTcpClient.ReadInputRegisters(5121, 1);
var dcPrValDcDc = ModbusTcpClient.ReadInputRegisters(5124, 1);
var dcPrValDcDc2 = ModbusTcpClient.ReadInputRegisters(5127, 2);
var dcTempValue = ModbusTcpClient.ReadInputRegisters(5511, 1);
var dcWarningValues = ModbusTcpClient.ReadInputRegisters(2404, 20);
var dcAlarmValues = ModbusTcpClient.ReadInputRegisters(2811, 20);
var dcSetValues = ModbusTcpClient.ReadInputRegisters(4001, 1);
var warnings = Enumerable
.Range(2404, 20)
.Select(n => dcWarningValues.GetUInt16((UInt16)n).ConvertTo<WarningMessage>())
.Where(m => m != WarningMessage.NoWarning)
.ToArray();
var alarms = Enumerable
.Range(2811, 20)
.Select(n => dcAlarmValues.GetUInt16((UInt16)n).ConvertTo<AlarmMessage>())
.Where(m => m != AlarmMessage.NoAlarm)
.ToArray();
var dcCurrentLimitState = GetFlags(dcPrValDcDc.GetUInt16(5124)).ToArray();
var dcLinkVoltage = dcPrValDcDc2.GetUInt16(5128);
var dcPower = dcBatteryValue4.GetInt16(5121) * 1m;
var dcCurrent = dcLinkVoltage != 0m ? dcPower / dcLinkVoltage : 0m;
return new TruConvertDcStatus
{
Left = new DcBus()
{
Current = dcCurrent,
Voltage = dcLinkVoltage
},
Right = new DcBus()
{
Current = dcBatteryValue2.GetInt16(5111),
Voltage =dcBatteryValue.GetUInt16(5101) * 0.1m,
},
MainState = (MainState)dcPrValMain.GetInt16(5001),
NumberOfConnectedSlaves = dcPrValMain.GetUInt16(5002),
NumberOfConnectedSubSlaves = dcPrValMain.GetUInt16(5003),
TotalDcPower = dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W
StatusOfCurrentLimiting = dcCurrentLimitState,
OverloadCapacity = dcPrValDcDc2.GetUInt16(5127) * 0.1m,
DcDcInletTemperature = dcTempValue.GetInt16(5511),
Warnings = warnings,
Alarms = alarms,
PowerOperation = dcSetValues.GetBoolean(4001),
};
}
}

View File

@ -1,29 +0,0 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.StatusApi;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
using AlarmMessages = IReadOnlyList<AlarmMessage>;
using WarningMessages = IReadOnlyList<WarningMessage>;
using DcCurrentLimitStates = IReadOnlyList<DcCurrentLimitState>;
public record TruConvertDcStatus : DcDcConverterStatus
{
public MainState MainState { get; init; }
public Power TotalDcPower { get; init; } // TODO: necessary?
public DcCurrentLimitStates StatusOfCurrentLimiting { get; init; }
public Decimal OverloadCapacity { get; init; }
public Temperature DcDcInletTemperature { get; init; }
public AlarmMessages Alarms { get; init; } = Array.Empty<AlarmMessage>();
public WarningMessages Warnings { get; init; } = Array.Empty<WarningMessage>();
public Boolean PowerOperation { get; init; }
public Decimal NumberOfConnectedSlaves { get; init; } // TODO: necessary?
public Decimal NumberOfConnectedSubSlaves { get; init; } // TODO: necessary?
}
// {
// public static TruConvertDcStatus operator |(TruConvertDcStatus left, TruConvertDcStatus right) => OpParallel(left, right);
// private static readonly Func<TruConvertDcStatus, TruConvertDcStatus, TruConvertDcStatus> OpParallel = Operators.Op<TruConvertDcStatus>("|");
// }