SOH Cycle Controller

This controller runs a defined State-of-Health (SOH) test cycle on an ESS (battery storage system). It executes an optional reference cycle and a measurement cycle, then evaluates the result to determine the SOH of the ESS.

The purpose of this README is to store useful technical information about the controller logic and states. This information is primarily needed for developers (e.g., to answer questions from product management).


Configuration

The following configuration parameters are available:

  • id
    Component-ID – Unique ID of this component (default: ctrlEssSohCycle0)

  • ess_id
    ID of the ESS device to monitor (e.g., ess0)

  • alias
    Human-readable name of this component; defaults to Component-ID

  • enabled
    Whether this component is enabled (default: true)

  • mode
    Operating mode – Select MANUAL_ON to activate the cycle logic; MANUAL_OFF disables the cycle (default: MANUAL_OFF)

  • logVerbosity
    Sets the logging verbosity level (default: NONE)

    • NONE: No logs

    • DEBUG_LOG: Detailed logging to Controller.Debug.Log

  • referenceCycleEnabled
    Enables the optional reference cycle measurement (default: false)

    • If false: cycle skips directly to the measurement cycle

    • If true: full cycle with reference measurements included


Monitoring

Typical channels can be followed from Grafana or online monitoring (names may differ depending on configuration).

Core state and results

  • ctrlEssSohCycle0/StateMachine
    Current state of the SOH state machine:
    IDLE, PREPARE, REFERENCE_CYCLE_CHARGING, REFERENCE_CYCLE_CHARGING_WAIT,
    REFERENCE_CYCLE_DISCHARGING, REFERENCE_CYCLE_DISCHARGING_WAIT,
    MEASUREMENT_CYCLE_CHARGING, MEASUREMENT_CYCLE_CHARGING_WAIT, CHECK_BALANCING,
    MEASUREMENT_CYCLE_DISCHARGING, MEASUREMENT_CYCLE_DISCHARGING_WAIT,
    EVALUATE_RESULT, DONE, ERROR_ABORT.

  • ctrlEssSohCycle0/SohPercent
    Calculated SOH result of the last completed cycle in percent (0–100).

  • ctrlEssSohCycle0/SohRawDebug
    Raw calculated SOH value without clamping to 100. May exceed 100 and is intended for debugging.

  • ctrlEssSohCycle0/MeasuredCapacity
    Last measured capacity of the ESS in Watt-hours (Wh).

Battery balancing status and diagnostics

  • ctrlEssSohCycle0/IsBatteryBalanced
    Indicates whether the battery cells are sufficiently balanced.
    Values: NOT_MEASURED, BALANCED, NOT_BALANCED, ERROR.

  • ctrlEssSohCycle0/BalancingDeltaMvDebug
    Cell voltage delta (max − min) in millivolts. Persisted for debugging long-running cycles.
    null if delta cannot be calculated.

  • ctrlEssSohCycle0/BalancingReason
    Explains why the balance check results in NOT_MEASURED or NOT_BALANCED.
    Typical values:
    NONE, BASELINE_MIN_MISSING, MAX_VOLTAGE_UNDEFINED, MIN_VOLTAGE_UNDEFINED,
    DELTA_NEGATIVE, DELTA_ABOVE_THRESHOLD, TIMEOUT, INTERNAL_ERROR.

Note: exact enum values depend on the controller version.

Voltage monitoring

  • ctrlEssSohCycle0/VoltageDelta
    Cell voltage delta (in mV) used for balancing evaluation and diagnostics.


Algorithm logic

The SOH Cycle Controller is implemented as a state machine with the following phases:

1) Idle & preparation

  • IDLE – Waits for activation via MANUAL_ON mode.

  • PREPARE – Prepares the ESS by discharging to minimum SOC (0%).

2) Reference cycle (optional)

  • REFERENCE_CYCLE_CHARGING – Charges the battery to maximum SOC (100%) at 0.2C rate.

  • REFERENCE_CYCLE_CHARGING_WAIT – Waits for voltage stabilization.

  • REFERENCE_CYCLE_DISCHARGING – Discharges the battery to minimum SOC (0%) at 0.2C rate.

  • REFERENCE_CYCLE_DISCHARGING_WAIT – Waits for voltage stabilization.

3) Measurement cycle (always executed)

  • MEASUREMENT_CYCLE_CHARGING – Charges the battery to maximum SOC (100%) at 0.2C rate.
    During this phase the controller continuously collects cell voltage range data for balancing diagnostics.

  • MEASUREMENT_CYCLE_CHARGING_WAIT – Waits for voltage stabilization.

  • CHECK_BALANCING – Evaluates battery cell balancing status using the measured cell voltage delta.
    Sets:

    • IsBatteryBalanced

    • BalancingDeltaMvDebug

    • BalancingReason

      Threshold: 100 mV.

  • MEASUREMENT_CYCLE_DISCHARGING – Discharges the battery to minimum SOC (0%) at 0.2C rate while measuring energy for capacity calculation.

  • MEASUREMENT_CYCLE_DISCHARGING_WAIT – Waits for voltage stabilization.

4) Result evaluation

  • EVALUATE_RESULT – Calculates SOH from measured capacity; sets:

    • SohPercent

    • SohRawDebug

    • MeasuredCapacity

  • DONE – Cycle finished successfully.

5) Error handling

  • ERROR_ABORT – Fatal error occurred; manual reset required via mode change to MANUAL_OFF.


Battery balancing check: how voltage delta is measured

What is measured?

The balancing check uses the cell voltage delta:

delta_mV = maxCellVoltage_mV - minCellVoltage_mV

The value is written to BalancingDeltaMvDebug and used to determine IsBatteryBalanced.

How are min and max voltages captured?

During the measurement charging phase and again at CHECK_BALANCING, the controller calls:

refreshMeasurementChargingVoltageRange()

This method reads:

  • ess.getMinCellVoltage()

  • ess.getMaxCellVoltage()

and stores them internally.

Important: min and max may be captured at different times

Min and max voltages are updated independently:

The stored minimum voltage is actually the highest observed minimum during charging:

if (stored == null || current > stored) {
    stored = current;
}

The stored maximum voltage is the highest observed maximum:

if (stored == null || current > stored) {
    stored = current;
}

As a result, the voltage delta may combine values measured at different points in time. It represents a range envelope observed during charging, not necessarily an instantaneous snapshot.

Implications

  • The delta is a diagnostic indicator of imbalance.

  • It may be slightly conservative, but helps answer:

    • “Did a large spread occur during charging?”

    • “Is the spread still significant near the end of charging?”

If an instantaneous delta at a single timestamp is required, min and max would need to be sampled together and evaluated immediately.


CHECK_BALANCING behavior and diagnostics

In CHECK_BALANCING, the controller: 1. Refreshes voltage range data 3. Calculates voltage delta and diagnostic reason 5. Sets: * BalancingDeltaMvDebug * BalancingReason * IsBatteryBalanced 13. Continues the cycle even if the battery is not balanced

Diagnostics are persisted as channels, enabling root-cause analysis without relying on logs.