Kaco project updated states and register number

This commit is contained in:
atef 2026-04-10 15:20:59 +02:00
parent 0e0e23e401
commit d34b226b6e
4 changed files with 44 additions and 244 deletions

View File

@ -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<String, Object> jsonDict, String[] keys, String value)

View File

@ -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;
}
}*/

View File

@ -175,9 +175,8 @@ public partial class KacoRecord
/// Scale factor for battery currents (A_SF).
/// </summary>
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;

View File

@ -36,42 +36,41 @@ public partial class KacoRecord
[HoldingRegister<UInt16>(41074)] private UInt16 _reserved13; // 0xA072
[HoldingRegister<UInt16>(41075)] private UInt16 _reserved14; // 0xA073
[HoldingRegister<UInt16>(41076)] private UInt16 _reserved15; // 0xA074
[HoldingRegister<UInt16>(41077)] private UInt16 _reserved16; // 0xA075
// Status / error
[HoldingRegister<UInt16>(41078)] private UInt16 _stVnd; // 0xA076 StVnd (enum16, R) PrologState
[HoldingRegister<UInt16>(41079)] private UInt16 _stPu; // 0xA077 StPu (enum16, R) Power Unit State (DSP)
[HoldingRegister<UInt16>(41080)] private UInt16 _stPcu; // 0xA078 StPcu (enum16, R) pcu state
[HoldingRegister<UInt16>(41081)] private UInt16 _errPcu; // 0xA079 ErrPcu (enum16, R) pcu error
[HoldingRegister<UInt16>(41077)] private UInt16 _stVnd; // 0xA076 StVnd (enum16, R) PrologState
[HoldingRegister<UInt16>(41078)] private UInt16 _stPu; // 0xA077 StPu (enum16, R) Power Unit State (DSP)
[HoldingRegister<UInt16>(41079)] private UInt16 _stPcu; // 0xA078 StPcu (enum16, R) pcu state
[HoldingRegister<UInt16>(41080)] private UInt16 _errPcu; // 0xA079 ErrPcu (enum16, R) pcu error
// Active power ramp parameters
[HoldingRegister<UInt16>(41082, writable: true)] private UInt16 _wParamRmpTms; // 0xA07A WParamRmpTms (uint16, RW, s)
[HoldingRegister<UInt16>(41083, writable: true)] private UInt16 _wParamRmpDecTmn; // 0xA07B WParamRmpDecTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41084, writable: true)] private UInt16 _wParamRmpIncTmn; // 0xA07C WParamRmpIncTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41081, writable: true)] private UInt16 _wParamRmpTms; // 0xA07A WParamRmpTms (uint16, RW, s)
[HoldingRegister<UInt16>(41082, writable: true)] private UInt16 _wParamRmpDecTmn; // 0xA07B WParamRmpDecTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41083, writable: true)] private UInt16 _wParamRmpIncTmn; // 0xA07C WParamRmpIncTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41085)] private UInt16 _reserved24; // 0xA07D Reserved
[HoldingRegister<UInt16>(41086)] private UInt16 _reserved25; // 0xA07E Reserved
[HoldingRegister<UInt16>(41084)] private UInt16 _reserved24; // 0xA07D Reserved
[HoldingRegister<UInt16>(41085)] private UInt16 _reserved25; // 0xA07E Reserved
[HoldingRegister<UInt16>(41087, writable: true)] private UInt16 _wParamEna; // 0xA07F WParam_Ena (enum16, RW) WSet_Ena control 0 or 1
[HoldingRegister<UInt16>(41086, writable: true)] private UInt16 _wParamEna; // 0xA07F WParam_Ena (enum16, RW) WSet_Ena control 0 or 1
// Reactive power ramp parameters
[HoldingRegister<UInt16>(41088, writable: true)] private UInt16 _varParamRmpTms; // 0xA080 VarParamRmpTms (uint16, RW, s)
[HoldingRegister<UInt16>(41089, writable: true)] private UInt16 _varParamRmpDecTmn; // 0xA081 VarParamRmpDecTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41090, writable: true)] private UInt16 _varParamRmpIncTmn; // 0xA082 VarParamRmpIncTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41087, writable: true)] private UInt16 _varParamRmpTms; // 0xA080 VarParamRmpTms (uint16, RW, s)
[HoldingRegister<UInt16>(41088, writable: true)] private UInt16 _varParamRmpDecTmn; // 0xA081 VarParamRmpDecTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41089, writable: true)] private UInt16 _varParamRmpIncTmn; // 0xA082 VarParamRmpIncTmn (uint16, RW, %ref/min)
[HoldingRegister<UInt16>(41091)] private UInt16 _reserved30; // 0xA083 Reserved
[HoldingRegister<UInt16>(41092)] private UInt16 _reserved31; // 0xA084 Reserved
[HoldingRegister<UInt16>(41090)] private UInt16 _reserved30; // 0xA083 Reserved
[HoldingRegister<UInt16>(41091)] private UInt16 _reserved31; // 0xA084 Reserved
[HoldingRegister<UInt16>(41093, writable: true)] private UInt16 _varParamEna; // 0xA085 VarParam_Ena (enum16, RW) Enumerated valued. Percent limit VAr enable/disable control.
[HoldingRegister<UInt16>(41092, writable: true)] private UInt16 _varParamEna; // 0xA085 VarParam_Ena (enum16, RW) Enumerated valued. Percent limit VAr enable/disable control.
// Measurements (read-only)
[HoldingRegister<UInt16>(41094)] private UInt16 _phaseVoltageAN; // 0xA086 PhVphA (uint16, R, V, V_SF)
[HoldingRegister<UInt16>(41095)] private UInt16 _phaseVoltageBN; // 0xA087 PhVphB (uint16, R, V, V_SF)
[HoldingRegister<UInt16>(41096)] private UInt16 _phaseVoltageCN; // 0xA088 PhVphC (uint16, R, V, V_SF)
[HoldingRegister<UInt16>(41093)] private UInt16 _phaseVoltageAN; // 0xA086 PhVphA (uint16, R, V, V_SF)
[HoldingRegister<UInt16>(41094)] private UInt16 _phaseVoltageBN; // 0xA087 PhVphB (uint16, R, V, V_SF)
[HoldingRegister<UInt16>(41095)] private UInt16 _phaseVoltageCN; // 0xA088 PhVphC (uint16, R, V, V_SF)
[HoldingRegister<Int16> (41097)] private Int16 _activePowerW; // 0xA089 W (int16, R, W, W_SF)
[HoldingRegister<Int16> (41098)] private Int16 _reactivePowerVar; // 0xA08A VAR (int16, R, var, Var_SF)
[HoldingRegister<Int16> (41099)] private Int16 _lineFrequencyHz; // 0xA08B Hz (int16, R, Hz, Hz_SF)
[HoldingRegister<Int16> (41096)] private Int16 _activePowerW; // 0xA089 W (int16, R, W, W_SF)
[HoldingRegister<Int16> (41097)] private Int16 _reactivePowerVar; // 0xA08A VAR (int16, R, var, Var_SF)
[HoldingRegister<Int16> (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<Int16>(41109)] private Int16 _rmpTmsSf; // 0xA0F5 RmpTms_SF
// Scale factor for increment and decrement ramps.
[HoldingRegister<Int16>(41110)] private Int16 _rmpIncDecSf; // 0xA0F6 RmpIncDec_SF
[HoldingRegister<Int16>(41112)] private Int16 _wSf; // W_SF
// Header
[HoldingRegister<UInt16>(41115)] private UInt16 _battCharId; // ID = 64202
[HoldingRegister<UInt16>(41116)] private UInt16 _battCharLength; // L = 6 + (RBCount * 8)