using InnovEnergy.Lib.Devices.Kaco92L3.DataType; namespace InnovEnergy.Lib.Devices.Kaco92L3; public partial class KacoRecord { private static float ScaleSunspec(Int16 value, Int16 sf) { // -32768 is SunSpec "not implemented" if (value == -32768) return float.NaN; if (sf == 0) return value; return (float)(value * Math.Pow(10, sf)); } private static float ScaleSunspec(UInt16 value, Int16 sf) { // interpret unsigned as signed when applying SF; range is the same return ScaleSunspec(unchecked((Int16)value), sf); } private static Int16 UnscaleSunspecToInt16(float value, Int16 sf) { if (float.IsNaN(value) || float.IsInfinity(value)) return -32768; // "not implemented" / invalid if (sf == 0) return (Int16)Math.Round(value); var raw = value / (float)Math.Pow(10, sf); return (Int16)Math.Round(raw); } private static UInt16 UnscaleSunspecToUInt16(float value, Int16 sf) { var raw = UnscaleSunspecToInt16(value, sf); return unchecked((UInt16)raw); } /****************************** High-level API for Model 64201 ****************************/ // ─────────────────────────────────────────────── // States & control // ─────────────────────────────────────────────── // Header public UInt16 BattCharId => _battCharId; // ID = 64202 public UInt16 BattCharLength => _battCharLength; // L = 6 + (RBCount * 8) public ReuqestedState RequestedState { get => (ReuqestedState)_requestedState; set => _requestedState = (UInt16)value; } public CurrentState CurrentState => (CurrentState)_currentState; public ControlMode ControlMode { get => (ControlMode)_controlMode; set => _controlMode = (UInt16)value; } public bool IsGridConnected => CurrentState == CurrentState.GridConnected; public bool IsStandby => CurrentState == CurrentState.Standby; public bool IsOff => CurrentState == CurrentState.Off; // Watchdog seconds (no scale factor) public UInt16 WatchdogSeconds { get => _watchdog; set => _watchdog = value; } // ─────────────────────────────────────────────── // Setpoints (scaled) // ─────────────────────────────────────────────── /// Active power setpoint in percent of WMax [%]. public float ActivePowerSetPercent { get => ScaleSunspec(_wSetPct, _wSetPctSf); set => _wSetPct = UnscaleSunspecToInt16(value, _wSetPctSf); } /// Reactive power setpoint in percent of SMax [%]. public float ReactivePowerSetPercent { get => ScaleSunspec(_varWMaxSetPct, _varSetPctSf); set => _varWMaxSetPct = UnscaleSunspecToInt16(value, _varSetPctSf); } // ─────────────────────────────────────────────── // Ramp parameters (scaled) // ─────────────────────────────────────────────── /// Active power PT1 ramp time [s]. public float ActivePowerRampTimeSeconds { get => ScaleSunspec(_wParamRmpTms, _rmpTmsSf); set => _wParamRmpTms = UnscaleSunspecToUInt16(value, _rmpTmsSf); } /// Active power ramp-down rate [% ref / min]. public float ActivePowerRampDownPercentPerMin { get => ScaleSunspec(_wParamRmpDecTmn, _rmpIncDecSf); set => _wParamRmpDecTmn = UnscaleSunspecToUInt16(value, _rmpIncDecSf); } /// Active power ramp-up rate [% ref / min]. public float ActivePowerRampUpPercentPerMin { get => ScaleSunspec(_wParamRmpIncTmn, _rmpIncDecSf); set => _wParamRmpIncTmn = UnscaleSunspecToUInt16(value, _rmpIncDecSf); } /// Reactive power PT1 ramp time [s]. public float ReactivePowerRampTimeSeconds { get => ScaleSunspec(_varParamRmpTms, _rmpTmsSf); set => _varParamRmpTms = UnscaleSunspecToUInt16(value, _rmpTmsSf); } /// Reactive power ramp-down rate [% ref / min]. public float ReactivePowerRampDownPercentPerMin { get => ScaleSunspec(_varParamRmpDecTmn, _rmpIncDecSf); set => _varParamRmpDecTmn = UnscaleSunspecToUInt16(value, _rmpIncDecSf); } /// Reactive power ramp-up rate [% ref / min]. public float ReactivePowerRampUpPercentPerMin { get => ScaleSunspec(_varParamRmpIncTmn, _rmpIncDecSf); set => _varParamRmpIncTmn = UnscaleSunspecToUInt16(value, _rmpIncDecSf); } // Ramp enable flags public EnableDisableEnum ActivePowerRampEnable { get => (EnableDisableEnum)_wParamEna; set => _wParamEna = (UInt16)value; } public EnableDisableEnum ReactivePowerRampEnable { get => (EnableDisableEnum)_varParamEna; set => _varParamEna = (UInt16)value; } // ─────────────────────────────────────────────── // Status / error (read-only enum views) // ─────────────────────────────────────────────── //public VendorStateEnum VendorState => (VendorStateEnum)_stVnd; //public PuStateEnum PuState => (PuStateEnum)_stPu; public StatePcu PcuState => (StatePcu)_stPcu; public ErrorPcu PcuError => (ErrorPcu)_errPcu; public UInt16 BatteryCharVersion => _battCharVersion; public UInt16 BatteryCharMinorVersion => _battCharVerMinor; /// /// Scale factor for battery voltages (V_SF). /// public Int16 BatteryVoltageScaleFactor => _battCharVSf; /// /// Scale factor for battery currents (A_SF). /// public Int16 BatteryCurrentScaleFactor => _battCharASf; public Int16 ActivePowerW => _activePowerW; public Int16 ReactivePowerVar => _reactivePowerVar; public Int16 LineFrequencyHz => _lineFrequencyHz; // Helper wrappers for scaled values private float ScaleBattVoltage(UInt16 raw) => ScaleSunspec(raw, _battCharVSf); private float ScaleBattCurrent(UInt16 raw) => ScaleSunspec(raw, _battCharASf); private UInt16 UnscaleBattVoltage(float value) => UnscaleSunspecToUInt16(value, _battCharVSf); private UInt16 UnscaleBattCurrent(float value) => UnscaleSunspecToUInt16(value, _battCharASf); // ─────────────────────────────────────────────── // Battery discharge limits (scaled, RW) // ─────────────────────────────────────────────── /// Minimum discharge voltage [V]. public float MinDischargeVoltage { get => ScaleBattVoltage(_disMinVRaw); set => _disMinVRaw = UnscaleBattVoltage(value); } /// Maximum discharge current [A]. public float MaxDischargeCurrent { get => ScaleBattCurrent(_disMaxARaw); set => _disMaxARaw = UnscaleBattCurrent(value); } /// Discharge cutoff current [A]. If discharge current falls below this, it disconnects (optional according to sheet). public float DischargeCutoffCurrent { get => ScaleBattCurrent(_disCutoffARaw); set => _disCutoffARaw = UnscaleBattCurrent(value); } // ─────────────────────────────────────────────── // Battery charge limits (scaled, RW) // ─────────────────────────────────────────────── /// Maximum charge voltage [V]. public float MaxChargeVoltage { get => ScaleBattVoltage(_chaMaxVRaw); set => _chaMaxVRaw = UnscaleBattVoltage(value); } /// Maximum charge current [A]. public float MaxChargeCurrent { get => ScaleBattCurrent(_chaMaxARaw); set => _chaMaxARaw = UnscaleBattCurrent(value); } /// Charge cutoff current [A]. If charge current falls below this, it disconnects. public float ChargeCutoffCurrent { get => ScaleBattCurrent(_chaCutoffARaw); set => _chaCutoffARaw = UnscaleBattCurrent(value); } // ─────────────────────────────────────────────── // Limit enable flag // ─────────────────────────────────────────────── /// /// When EnLimit = 1, new battery limits are activated. /// public EnableDisableEnum BatteryLimitsEnable { get => (EnableDisableEnum)_enLimitRaw; set => _enLimitRaw = (UInt16)value; } /// Convenience bool wrapper for EnLimit. public bool BatteryLimitsEnabled { get => BatteryLimitsEnable == EnableDisableEnum.Enabled; set => BatteryLimitsEnable = value ? EnableDisableEnum.Enabled : EnableDisableEnum.Disabled; } }