using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Utils; using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.SystemControlRegisters; namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public class SystemControlDevice { private ModbusTcpClient ModbusTcpClient { get; } public SystemControlDevice(String hostname, UInt16 port = ModbusTcpClient.DefaultPort, Byte slaveAddress = 0) { var connection = new ModbusTcpConnection(hostname, port); ModbusTcpClient = new ModbusTcpClient(connection, slaveAddress); } public void WriteControl(ControlRecord c) { /* WriteRegs(AcControlRegisters.Date, new List { c.Date.ConvertTo()}); WriteRegs(AcControlRegisters.Time, new List { c.Time.ConvertTo()}); WriteRegs(AcControlRegisters.IpAddress, new List { c.IpAddress.ConvertTo()}); WriteRegs(AcControlRegisters.Subnet, new List { c.Subnet.ConvertTo()}); WriteRegs(AcControlRegisters.Gateway, new List { c.Gateway.ConvertTo()}); 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()); WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig); WriteCoils(PowerStageConfig, c.PowerStageEnable, c.SetValueConfig.ConvertTo(), 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(), c.SetPointSinPhi.ConvertTo(), c.SetPointSinPhiL1.ConvertTo(), c.SetPointSinPhiL2.ConvertTo(), c.SetPointSinPhiL3.ConvertTo(), 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()).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() { try { return TryReadStatus(); } catch (Exception e) { ModbusTcpClient.CloseConnection(); Console.WriteLine("Failed to read inverter status"); e.Message.WriteLine(); return null; } } 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()) .ToArray(); var alarms = Enumerable .Range(2811, 20) .Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo()) .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(), Alarms = alarms, Warnings = warnings, GridType = acActualAcDc.GetUInt16(5024).ConvertTo(), 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(), // 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(), // 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 // ); } }