From d34b226b6e9e738181415ee6e86d6a14eddec880 Mon Sep 17 00:00:00 2001 From: atef Date: Fri, 10 Apr 2026 15:20:59 +0200 Subject: [PATCH] Kaco project updated states and register number --- csharp/App/KacoCommunication/Program.cs | 42 ++-- .../KacoCommunication/System/Controller.cs | 196 +----------------- csharp/Lib/Devices/Kaco92L3/KacoRecord.Api.cs | 3 +- .../Lib/Devices/Kaco92L3/KacoRecord.modbus.cs | 47 ++--- 4 files changed, 44 insertions(+), 244 deletions(-) diff --git a/csharp/App/KacoCommunication/Program.cs b/csharp/App/KacoCommunication/Program.cs index 6f9c3b956..ba74d9246 100644 --- a/csharp/App/KacoCommunication/Program.cs +++ b/csharp/App/KacoCommunication/Program.cs @@ -142,11 +142,11 @@ internal static class Program return new StatusRecord { - InverterRecord = kacoRecord, - GridMeterRecord = gridRecord, - DcDc = dcDcRecord, + InverterRecord = kacoRecord, + GridMeterRecord = gridRecord, + DcDc = dcDcRecord, ListOfBatteriesRecord = listOfBatteriesRecord, - StateMachine = StateMachine.Default, + StateMachine = StateMachine.Default, Config = config // load from disk every iteration, so config can be changed while running }; @@ -179,7 +179,7 @@ internal static class Program // the order matter of the next three lines var statusrecord = ReadStatus(); statusrecord?.CreateSimpleTopologyTextBlock().WriteLine(); - + statusrecord?.StateMachine.State.WriteLine(" state"); statusrecord?.StateMachine.Message.WriteLine(" Message"); @@ -194,6 +194,7 @@ internal static class Program Console.WriteLine(" ********************************* Kaco Inverter *********************************"); statusrecord?.InverterRecord?.ActivePowerW.WriteLine(" Inverter Power"); + statusrecord?.InverterRecord?.CurrentState.WriteLine(" CurrentState"); statusrecord?.InverterRecord?.RequestedState.WriteLine(" RequestedState"); statusrecord?.InverterRecord?.PcuError.WriteLine(" PcuError"); @@ -206,31 +207,20 @@ internal static class Program statusrecord?.InverterRecord?.MaxChargeVoltage.WriteLine(" MaxChargeVoltage"); statusrecord?.InverterRecord?.MaxChargeCurrent.WriteLine(" MaxChargeCurrent"); statusrecord?.InverterRecord?.ChargeCutoffCurrent.WriteLine(" ChargeCutoffCurrent"); - statusrecord?.InverterRecord?.ActivePowerSetPercent.WriteLine( "ActivePowerSetPercent"); + statusrecord?.InverterRecord?.ActivePowerSetPercent.WriteLine( "ActivePowerSetPercent"); statusrecord?.ControlSystemState(); - var i = 0; - foreach (var d in statusrecord.DcDc.Devices) - { - i++; - Console.WriteLine("before DcDc is " + i + d.Control.PowerStageEnable); - d.Control.ResetAlarmsAndWarnings = true; - d.Control.PowerStageEnable = true; - } - - - statusrecord?.DcDc?.SystemControl.ApplyDcDcDefaultSettings(); + //Maybe Introduce a condition to run it only when it's not in a runing mode InitializeKacoStartup(statusrecord); - foreach (var d in statusrecord.DcDc.Devices) - { - Console.WriteLine("After DcDc is " + d.Control.PowerStageEnable); - } - + Console.WriteLine(" ************************************ We are writing ************************************"); statusrecord?.Config.Save(); // save the config file - if (statusrecord?.InverterRecord != null) kacoDevice.Write(statusrecord.InverterRecord); + + kacoDevice.Write(statusrecord.InverterRecord); + dcDcDevices.Write(statusrecord.DcDc); + return statusrecord; } @@ -578,6 +568,10 @@ internal static class Program statusRecord?.DcDc?.Devices .Select(d => d.Control ) .ForAll(c => c.ControlMode = DcControlMode.VoltageDroop); + + //Add the DcDc configuration + statusRecord?.DcDc?.SystemControl.ApplyDcDcDefaultSettings(); + // // // 2. Send valid battery limits (Model 64202) // All values temporarily set to "1" as requested. @@ -659,7 +653,7 @@ internal static class Program sc.SlaveErrorHandling = SlaveErrorHandling.Relaxed; sc.SubSlaveErrorHandling = SubSlaveErrorHandling.Off; sc.TargetSlave = 0; - sc.ResetAlarmsAndWarnings = true; + sc.ResetAlarmsAndWarnings = true; // is this enough or shoud reset in each device } private static void InsertIntoJson(Dictionary jsonDict, String[] keys, String value) diff --git a/csharp/App/KacoCommunication/System/Controller.cs b/csharp/App/KacoCommunication/System/Controller.cs index ef14e4eb7..0e002a6ca 100644 --- a/csharp/App/KacoCommunication/System/Controller.cs +++ b/csharp/App/KacoCommunication/System/Controller.cs @@ -135,8 +135,10 @@ public static class KacoCurrentStateController private static bool State_Throttled(StatusRecord s) { + s.StateMachine.Message = "THROTTLED: still running. Power writes allowed."; s.InverterRecord.RequestedState = ReuqestedState.GridConnected; + s.InverterRecord.ActivePowerSetPercent = s.Config.ActivePowerPercent; // Power writes allowed here too return true; @@ -180,197 +182,3 @@ public static class KacoCurrentStateController return false; } } - - -/* - -public static class Controller -{ - private static UInt16 GetSystemState(this StatusRecord r) - { - if (r.InverterRecord != null) - { - return (UInt16)r.InverterRecord.CurrentState; - } - else - { - return (UInt16)StateMachine.Default.State; - } - - } - - public static Boolean ControlSystemState(this StatusRecord s) - { - s.StateMachine.State = s.GetSystemState(); - - var cs = s.InverterRecord?.CurrentState; // 64201.CurrentState (1..12) - s.StateMachine.State = (UInt16)cs; - - return s.StateMachine.State switch - { - 1 => State_Off(s), - 2 => State_Sleeping(s), - 3 => State_Starting(s), - 4 => State_Mppt(s), - 5 => State_Throttled(s), - 6 => State_ShuttingDown(s), - 7 => State_Fault(s), - 8 => State_Standby(s), - 9 => State_Precharge(s), - 10 => State_GridPreConnected(s), - 11 => State_GridConnected(s), - 12 => State_NoErrorPending(s), - _ => UnknownState(s) - }; - } - - // ───────────────────────────────────────────── - // Global rule: only allow power writes in 11 or 5 - // ───────────────────────────────────────────── - private static void EnforcePowerRules(StatusRecord s) - { - var cs = s.InverterRecord?.CurrentState; - - // must be 0 outside (11) or (5) - s.InverterRecord.ActivePowerSetPercent = 0f; - s.InverterRecord.ReactivePowerSetPercent = 0f; } - } - - // ───────────────────────────────────────────── - // State handlers (based purely on CurrentState) - // ───────────────────────────────────────────── - - private static Boolean State_Off(StatusRecord s) - { - s.StateMachine.Message = "OFF: write limits (once) and request connect (11)."; - EnforcePowerRules(s); - - // Write limits (ignore details) - s.InverterRecord.WriteLimits(); - - // Always aim for running - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - - private static bool State_Sleeping(StatusRecord s) - { - s.StateMachine.Message = "SLEEPING: write limits (once) and request connect (11)."; - EnforcePowerRules(s); - - s.InverterRecord.WriteLimits(); - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_Standby(StatusRecord s) - { - s.StateMachine.Message = "STANDBY: write limits (once) and request connect (11)."; - EnforcePowerRules(s); - - s.InverterRecord.WriteLimits(); - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_Mppt(StatusRecord s) - { - s.StateMachine.Message = "MPPT: keep requesting connect (11)."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_Starting(StatusRecord s) - { - s.StateMachine.Message = "STARTING: keep requesting connect (11), wait for 10/11/5."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_Precharge(StatusRecord s) - { - s.StateMachine.Message = "PRECHARGE: keep requesting connect (11), wait."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_GridPreConnected(StatusRecord s) - { - s.StateMachine.Message = "GRID_PRE_CONNECTED: keep requesting connect (11), wait for 11/5."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_GridConnected(StatusRecord s) - { - s.StateMachine.Message = "GRID_CONNECTED: running. Power writes allowed."; - - // Keep request latched - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - - // Here you may write power setpoints (your own targets) - // Example: - // s.InverterRecord.ControlMode = ControlModeEnum.RpcRemote; - // s.InverterRecord.ActivePowerSetPercent = s.Targets.ActivePowerPercent; - // s.InverterRecord.ReactivePowerSetPercent = s.Targets.ReactivePowerPercent; - - return true; // end goal reached - } - - private static bool State_Throttled(StatusRecord s) - { - s.StateMachine.Message = "THROTTLED: still running. Power writes allowed."; - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - - // Power writes allowed here too - return true; - } - - private static bool State_ShuttingDown(StatusRecord s) - { - s.StateMachine.Message = "SHUTTING_DOWN: keep requesting connect (11); will reconnect after reaching 8/1."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - - private static bool State_Fault(StatusRecord s) - { - s.StateMachine.Message = "FAULT: power=0 and acknowledge with RequestedState=1 (OFF)."; - EnforcePowerRules(s); - - // Per doc: acknowledge uses RequestedState=1 - s.InverterRecord.RequestedState = ReuqestedState.Off; - return false; - } - - private static bool State_NoErrorPending(StatusRecord s) - { - s.StateMachine.Message = "NO_ERROR_PENDING: acknowledge with RequestedState=1 then controller will request 11 next cycles."; - EnforcePowerRules(s); - - // Per doc Step 8: set RequestedState to 1 to acknowledge - s.InverterRecord.RequestedState = ReuqestedState.Off; - return false; - } - - private static bool UnknownState(StatusRecord s) - { - s.StateMachine.Message = $"UNKNOWN CurrentState={s.InverterRecord.CurrentState}. For safety, power=0 and request 11."; - EnforcePowerRules(s); - - s.InverterRecord.RequestedState = ReuqestedState.GridConnected; - return false; - } - -}*/ \ No newline at end of file diff --git a/csharp/Lib/Devices/Kaco92L3/KacoRecord.Api.cs b/csharp/Lib/Devices/Kaco92L3/KacoRecord.Api.cs index 2118b7941..b4ce04063 100644 --- a/csharp/Lib/Devices/Kaco92L3/KacoRecord.Api.cs +++ b/csharp/Lib/Devices/Kaco92L3/KacoRecord.Api.cs @@ -175,9 +175,8 @@ public partial class KacoRecord /// Scale factor for battery currents (A_SF). /// public Int16 BatteryCurrentScaleFactor => _battCharASf; - + public Single ActivePowerW => ScaleSunspec( (Int16)(_activePowerW * -1), _wSf); // this to correct the sign to fit in our sign system - public Int16 ActivePowerW => _activePowerW; public Int16 ReactivePowerVar => _reactivePowerVar; public Int16 LineFrequencyHz => _lineFrequencyHz; diff --git a/csharp/Lib/Devices/Kaco92L3/KacoRecord.modbus.cs b/csharp/Lib/Devices/Kaco92L3/KacoRecord.modbus.cs index 16e382af1..2bf510f12 100644 --- a/csharp/Lib/Devices/Kaco92L3/KacoRecord.modbus.cs +++ b/csharp/Lib/Devices/Kaco92L3/KacoRecord.modbus.cs @@ -36,42 +36,41 @@ public partial class KacoRecord [HoldingRegister(41074)] private UInt16 _reserved13; // 0xA072 [HoldingRegister(41075)] private UInt16 _reserved14; // 0xA073 [HoldingRegister(41076)] private UInt16 _reserved15; // 0xA074 - [HoldingRegister(41077)] private UInt16 _reserved16; // 0xA075 // Status / error - [HoldingRegister(41078)] private UInt16 _stVnd; // 0xA076 – StVnd (enum16, R) PrologState - [HoldingRegister(41079)] private UInt16 _stPu; // 0xA077 – StPu (enum16, R) Power Unit State (DSP) - [HoldingRegister(41080)] private UInt16 _stPcu; // 0xA078 – StPcu (enum16, R) pcu state - [HoldingRegister(41081)] private UInt16 _errPcu; // 0xA079 – ErrPcu (enum16, R) pcu error + [HoldingRegister(41077)] private UInt16 _stVnd; // 0xA076 – StVnd (enum16, R) PrologState + [HoldingRegister(41078)] private UInt16 _stPu; // 0xA077 – StPu (enum16, R) Power Unit State (DSP) + [HoldingRegister(41079)] private UInt16 _stPcu; // 0xA078 – StPcu (enum16, R) pcu state + [HoldingRegister(41080)] private UInt16 _errPcu; // 0xA079 – ErrPcu (enum16, R) pcu error // Active power ramp parameters - [HoldingRegister(41082, writable: true)] private UInt16 _wParamRmpTms; // 0xA07A – WParamRmpTms (uint16, RW, s) - [HoldingRegister(41083, writable: true)] private UInt16 _wParamRmpDecTmn; // 0xA07B – WParamRmpDecTmn (uint16, RW, %ref/min) - [HoldingRegister(41084, writable: true)] private UInt16 _wParamRmpIncTmn; // 0xA07C – WParamRmpIncTmn (uint16, RW, %ref/min) + [HoldingRegister(41081, writable: true)] private UInt16 _wParamRmpTms; // 0xA07A – WParamRmpTms (uint16, RW, s) + [HoldingRegister(41082, writable: true)] private UInt16 _wParamRmpDecTmn; // 0xA07B – WParamRmpDecTmn (uint16, RW, %ref/min) + [HoldingRegister(41083, writable: true)] private UInt16 _wParamRmpIncTmn; // 0xA07C – WParamRmpIncTmn (uint16, RW, %ref/min) - [HoldingRegister(41085)] private UInt16 _reserved24; // 0xA07D – Reserved - [HoldingRegister(41086)] private UInt16 _reserved25; // 0xA07E – Reserved + [HoldingRegister(41084)] private UInt16 _reserved24; // 0xA07D – Reserved + [HoldingRegister(41085)] private UInt16 _reserved25; // 0xA07E – Reserved - [HoldingRegister(41087, writable: true)] private UInt16 _wParamEna; // 0xA07F – WParam_Ena (enum16, RW) WSet_Ena control 0 or 1 + [HoldingRegister(41086, writable: true)] private UInt16 _wParamEna; // 0xA07F – WParam_Ena (enum16, RW) WSet_Ena control 0 or 1 // Reactive power ramp parameters - [HoldingRegister(41088, writable: true)] private UInt16 _varParamRmpTms; // 0xA080 – VarParamRmpTms (uint16, RW, s) - [HoldingRegister(41089, writable: true)] private UInt16 _varParamRmpDecTmn; // 0xA081 – VarParamRmpDecTmn (uint16, RW, %ref/min) - [HoldingRegister(41090, writable: true)] private UInt16 _varParamRmpIncTmn; // 0xA082 – VarParamRmpIncTmn (uint16, RW, %ref/min) + [HoldingRegister(41087, writable: true)] private UInt16 _varParamRmpTms; // 0xA080 – VarParamRmpTms (uint16, RW, s) + [HoldingRegister(41088, writable: true)] private UInt16 _varParamRmpDecTmn; // 0xA081 – VarParamRmpDecTmn (uint16, RW, %ref/min) + [HoldingRegister(41089, writable: true)] private UInt16 _varParamRmpIncTmn; // 0xA082 – VarParamRmpIncTmn (uint16, RW, %ref/min) - [HoldingRegister(41091)] private UInt16 _reserved30; // 0xA083 – Reserved - [HoldingRegister(41092)] private UInt16 _reserved31; // 0xA084 – Reserved + [HoldingRegister(41090)] private UInt16 _reserved30; // 0xA083 – Reserved + [HoldingRegister(41091)] private UInt16 _reserved31; // 0xA084 – Reserved - [HoldingRegister(41093, writable: true)] private UInt16 _varParamEna; // 0xA085 – VarParam_Ena (enum16, RW) Enumerated valued. Percent limit VAr enable/disable control. + [HoldingRegister(41092, writable: true)] private UInt16 _varParamEna; // 0xA085 – VarParam_Ena (enum16, RW) Enumerated valued. Percent limit VAr enable/disable control. // Measurements (read-only) - [HoldingRegister(41094)] private UInt16 _phaseVoltageAN; // 0xA086 – PhVphA (uint16, R, V, V_SF) - [HoldingRegister(41095)] private UInt16 _phaseVoltageBN; // 0xA087 – PhVphB (uint16, R, V, V_SF) - [HoldingRegister(41096)] private UInt16 _phaseVoltageCN; // 0xA088 – PhVphC (uint16, R, V, V_SF) + [HoldingRegister(41093)] private UInt16 _phaseVoltageAN; // 0xA086 – PhVphA (uint16, R, V, V_SF) + [HoldingRegister(41094)] private UInt16 _phaseVoltageBN; // 0xA087 – PhVphB (uint16, R, V, V_SF) + [HoldingRegister(41095)] private UInt16 _phaseVoltageCN; // 0xA088 – PhVphC (uint16, R, V, V_SF) - [HoldingRegister (41097)] private Int16 _activePowerW; // 0xA089 – W (int16, R, W, W_SF) - [HoldingRegister (41098)] private Int16 _reactivePowerVar; // 0xA08A – VAR (int16, R, var, Var_SF) - [HoldingRegister (41099)] private Int16 _lineFrequencyHz; // 0xA08B – Hz (int16, R, Hz, Hz_SF) + [HoldingRegister (41096)] private Int16 _activePowerW; // 0xA089 – W (int16, R, W, W_SF) + [HoldingRegister (41097)] private Int16 _reactivePowerVar; // 0xA08A – VAR (int16, R, var, Var_SF) + [HoldingRegister (41098)] private Int16 _lineFrequencyHz; // 0xA08B – Hz (int16, R, Hz, Hz_SF) // Scale factors (SunSpec sunsf) // Scale factor for active power percent. @@ -82,7 +81,7 @@ public partial class KacoRecord [HoldingRegister(41109)] private Int16 _rmpTmsSf; // 0xA0F5 – RmpTms_SF // Scale factor for increment and decrement ramps. [HoldingRegister(41110)] private Int16 _rmpIncDecSf; // 0xA0F6 – RmpIncDec_SF - + [HoldingRegister(41112)] private Int16 _wSf; // W_SF // Header [HoldingRegister(41115)] private UInt16 _battCharId; // ID = 64202 [HoldingRegister(41116)] private UInt16 _battCharLength; // L = 6 + (RBCount * 8)