Cell balance monitor¶
Tracks the voltage spread between the highest and lowest cell at the top of a full charge. The reading is used to show whether the battery pack is staying balanced over time and to trigger imbalance alerts when the spread becomes high.
Why this is needed on LFP batteries¶
Marstek Venus batteries use LFP cells. LFP is very stable and long-lived, but its voltage curve is almost flat through most of the usable SOC range. Around the middle of the charge, two cells can have noticeably different SOC while still reporting almost the same voltage. That makes mid-SOC voltage readings poor indicators of cell balance.
The useful balance window is near the top of charge. Above roughly 3.45 V per cell, the LFP voltage curve rises much faster, so differences between cells become visible. That is also the area where the battery BMS is expected to perform passive balancing by bleeding the highest cells.
In practice, the Marstek BMS does not always balance the cells well by itself. If the pack reaches 100% quickly and then immediately returns to normal operation, weak balancing can leave one cell consistently higher than the rest. This integration therefore does two things:
- it slows the final part of a 100% charge so the BMS has time to work in the top-balance window;
- it measures imbalance only at a repeatable top-voltage point, instead of using noisy mid-SOC readings.
The LFP charge curve in detail¶
LFP (LiFePO4) chemistry has a charge/discharge curve that is fundamentally different from Li-ion NMC or NCA. Understanding it is what justifies every voltage threshold this integration uses.
A typical 3.2 V nominal LFP cell behaves like this during a constant-current charge:
| SOC range | Cell voltage range | Slope |
|---|---|---|
| 0 – 10 % | 2.50 V → 3.20 V | Steep entry knee |
| 10 – 90 % | 3.20 V → 3.30 V | Almost flat — about 1 mV per % SOC |
| 90 – 97 % | 3.30 V → 3.45 V | Mild rise begins |
| 97 – 99 % | 3.45 V → 3.55 V | Knee — voltage starts climbing sharply |
| 99 – 100 % | 3.55 V → 3.65 V | Steep top knee — full-charge cliff |
That long flat plateau is the reason LFP voltage tells you almost nothing about state of charge in the middle of the curve. Two cells that look identical at 3.28 V can in reality have 5 – 10 % SOC of difference between them, which is huge.
The plateau also means the BMS cannot do meaningful passive balancing in the middle of the curve. Passive balancing works by bleeding current off the highest cell through a resistor. To even detect which cell is "highest", the BMS needs the spread between cells to rise above measurement noise. On the plateau, all cells read essentially the same number, so the BMS has nothing to act on.
Only when the pack enters the upper knee (above roughly 3.45 V) do cell voltages spread apart enough for the BMS to identify the leader. A 10 mV spread on the plateau might correspond to a 5 % SOC difference, but the same 10 mV spread above 3.50 V represents a tiny SOC delta — which is exactly what you want at the end of charge.
So balancing on LFP is only effective in a narrow window: roughly the last 1 – 3 % of charge, above 3.45 V. Outside that window the BMS is essentially blind to imbalance, and any time the pack spends below the knee is time the cells are not getting balanced.
Availability¶
The cell balance monitor is always active. There is no separate configuration option because the readings are useful battery health data and do not change normal operation by themselves.
There is one integrated control that decides when the battery is taken to the top-voltage measurement window:
- 100% charge voltage taper: per battery option. When the charge target is 100%, the integration slows the final charge and records a top-voltage balance reading.
The weekly full charge feature can temporarily set the battery max SOC to 100%. Once it does that, the same 100% charge voltage taper rules are used.
Venus A/D batteries with coupled packs are the exception to the top-voltage stop: they still reduce charge to 200 W from 3.48 V, but reaching 3.60 V does not stop the integration or start the 60-second measurement. The reduced charge continues until the BMS confirms its cutoff, so the first full pack cannot prevent the remaining coupled packs from filling.
For active recovery of a pack with a persistent imbalance, use the optional Marstek active-balance blueprint. The blueprint is an external Home Assistant automation: it takes one battery through Battery Manual Mode, discovers the standard entities from the selected Omnibattery device (with manual ID overrides for renamed entities), and leaves manual ownership asserted if cleanup cannot be confirmed.
100% charge voltage taper¶
This path is used whenever the 100% charge voltage taper option is enabled for a battery. It is voltage-driven: it engages once max_cell_voltage reaches the thresholds below, regardless of the configured max_soc. In practice that happens when:
- the user configured that battery with
max_soc = 100, or - the weekly full charge temporarily raised the battery to 100%, or
- a high
max_socbelow 100% still lets the cells reach 3.48 V.
The weekly full charge does not use a different balance profile. It only changes the target SOC to 100%; voltage thresholds, charge power and measurement logic are the same.
Charge profile¶
flowchart TD
A([100% charge voltage taper start]) --> B(Charge with configured charge limit)
B --> C{max_cell_voltage < 3.48 V}
C -->|Yes| A
C -->|No| D([Limit charging])
D --> E(Charge with 200 W)
E --> F{max_cell_voltage < 3.60 V}
F -->|Yes| D
F -->|No, Venus E| G([Stop charge and latch])
G --> H(Stay stopped until charge hysteresis releases)
G --> I(Wait 60s)
I --> J("Record cell_delta = (cell_Vmax - cell_Vmin) * 1000")
F -->|No, Venus A/D| K([Continue at 200 W])
K --> L{BMS cutoff confirmed?}
L -->|No| K
L -->|Yes| M([Stop charge and wait 60s])
M --> N("Record cell_delta = (cell_Vmax - cell_Vmin) * 1000")
| Condition for one battery | Action |
|---|---|
max_cell_voltage below 3.48 V |
Normal configured charge limit |
max_cell_voltage at or above 3.48 V |
Limit charge to 200 W |
max_cell_voltage reaches 3.60 V on Venus E |
The configured charge hysteresis takes ownership of the stop/recharge threshold |
max_cell_voltage reaches 3.60 V on Venus A/D |
Keep charging at 200 W until the BMS cutoff; do not apply the integration stop |
| After the 60 s wait on Venus E | Record delta_mV = (Vmax - Vmin) * 1000 |
| After the confirmed BMS cutoff on Venus A/D | Wait 60 s without charging, then record delta_mV = (Vmax - Vmin) * 1000 |
Starting the taper is voltage based: SOC is deliberately not used to decide when tapering begins, because SOC can be less reliable near the top than the cell-voltage registers.
On Venus E, reaching 3.60 V lets the configured charge hysteresis prevent
recharging until its SOC threshold is crossed. The 60-second delta-V
measurement still runs as a best-effort diagnostic; if it did not finish
before completion, a one-shot snapshot is captured at completion time under
phase top_charge_taper_complete. Venus A/D skip this integration hold and
measurement before the BMS cutoff; once the cutoff is confirmed, they wait 60
seconds without charging and record the delta-V measurement once.
In a multi-battery system, this is evaluated per battery. One battery can be limited by the taper while another continues charging normally.
SOC recalibration on a stuck top voltage (Venus E)¶
Some Venus E packs reach the 3.60 V top-voltage threshold while the BMS still reports a SOC well below full (for example 60–70%). That gap can mean the BMS coulomb counter has drifted, but reaching the voltage threshold does not prove that the reported SOC is wrong.
When this happens, holding at 3.60 V never gives the BMS a chance to finish its own top-of-charge sequence. So instead of pausing, the integration keeps charging at the 200 W tapered power until the BMS itself cuts off, attempting to make it recalibrate SOC.
This is a best-effort attempt, not a guaranteed fix. Whether a top-of-curve cutoff actually resets the reported SOC depends on the BMS firmware: some packs snap to 100% on an over-voltage cutoff, others do not. The integration only creates the conditions for a recalibration — it cannot force the BMS to apply one.
The override triggers automatically whenever all of these are true:
- the 100% voltage taper is active (so
max_cell_voltageis in the top zone), and max_cell_voltagehas reached the 3.60 V top-voltage threshold, and- the BMS still reports SOC below 99%.
It is self-limiting:
- charging continues at 200 W only (the gentle taper power), not full power;
- a BMS cutoff is detected when battery power collapses to ≤ 10 W and the inverter reports Standby for 5 consecutive cycles (~10 s). If that first cutoff happened above 3.60 V while SOC is still below 100%, the battery waits for the cell to relax to 3.57 V and makes one 200 W retry; when the BMS cuts again, the override latches off permanently;
- if SOC reaches 100% during the wait or retry, no further attempt is made;
- if the SOC reads 99% or more before the first cutoff, the initial condition no longer matches, so the override does not fire;
- the latch only re-arms after the battery leaves the top zone (
max_cell_voltagebelow 3.48 V), so a later full charge can recalibrate again if needed.
Reaching the 3.60 V threshold normally only happens on a 100% charge, so this rarely affects daily cycling at a lower max_soc. It does not run during the weekly full charge — there the normal charge hysteresis is suppressed and the BMS cutoff alone ends the cycle (see that page). Venus A/D use the BMS-owned path on every tapered 100% charge, not this SOC-recalibration retry. The optional active-balance blueprint takes ownership through Battery Manual Mode, so the normal controller naturally excludes that battery while the automation is running.
Cell imbalance
The override does not check the cell spread first. On a badly imbalanced pack the highest cell can hit the BMS over-voltage cutoff before the pack is full, so the recalibration is correct but balancing is left to later cycles. The BMS still protects each cell individually.
Optional active-balance blueprint¶
The Marstek active-balance blueprint is the supported recovery path when passive balancing during normal or weekly charging is not enough. It is deliberately outside the integration's automatic control loop and must be configured once per battery.
Its default profile is: configured maximum charge power until max_cell_voltage >= 3.49 V, regulated charge at 95 W until 3.60 V, a 60-second rest measurement, 200 W discharge retries toward 3.49 V until delta_V <= 0.03 V, and a final 200 W discharge to 3.48 V. If the BMS rejects a new charge leg, the blueprint waits 10 seconds and requires three approximately-zero-power samples before lowering the retry target by 0.01 V, down to 3.40 V.
The automation validates every resolved entity and voltage/power relationship before writing. It sets both setpoints to 0 W before changing the force mode, temporarily writes 100% SOC, and converges every cancellation, restart or error through the same cleanup. It restores the configured SOC maximum and turns Battery Manual Mode off only after idle and SOC writes are confirmed; otherwise the switch remains ON as a safety hold.
Why these voltage thresholds¶
Every voltage cutoff used by the 100 % taper and the optional active-balance blueprint was picked against the LFP curve described above. None of these numbers are arbitrary.
| Threshold | Where it is used | Why this value |
|---|---|---|
| 3.45 V | Reference for the start of the upper knee | This is roughly where the LFP curve leaves the plateau. Below this, balancing decisions cannot be trusted because cell voltages are too close together to distinguish. |
| 3.48 V | Trigger for tapering normal charge to 200 W | A little above the knee. The small margin confirms the pack is genuinely in the balance window — and not just on a brief voltage bounce caused by a load step — before reducing power. |
| 3.49 V | Blueprint discharge floor between retries; switch-over from coarse to regulated charge | Sits just inside the balance window. Stopping the discharge here keeps the pack in the zone where the BMS can still see and bleed the high cell. Going lower would push the pack off the knee and waste the time already spent balancing. |
| 3.60 V | Top measurement point; stop charge and wait 60 s before reading the delta | High enough to let supported BMS firmware reach its native top-charge behaviour while retaining about 50 mV of nominal headroom below the usual 3.65 V LFP ceiling. The battery BMS remains the final cutoff and may stop charge earlier. |
| 3.48 V (again) | End-of-cycle discharge floor — the 200 W final discharge in the blueprint stops here | The same threshold used to enter the taper is reused to leave the balance window. Stopping at 3.48 V brings the pack just off the upper knee without dropping it back onto the deep plateau. Sitting at 3.55 – 3.60 V for long periods accelerates calendar ageing, so the automation deliberately bleeds the pack down to the lower edge of the window before releasing control. |
| 3.40 V | Lower bound for the blueprint retry voltage when charge rejection is detected | The automation gives each new charge leg 10 s to engage and, if charge power has not yet been observed, then requires 3 consecutive ~0 W cycles before declaring rejection. It drops the retry voltage by 0.01 V, but never below 3.40 V. Going further down exits the balance window entirely and forces a long, wasteful re-climb up the curve. |
| 0.03 V (30 mV) | Blueprint completion threshold | Considered "balanced enough" for an LFP pack at the top of the knee. Pushing for tighter values (10 mV or less) is rarely productive because passive balancing currents are tiny — see the next section. |
| 0.05 V (50 mV) | Green / yellow status boundary | A pack reading below 50 mV at the top is considered healthy. This is more conservative than typical LFP vendor specs (often 80 – 100 mV) because the measurement is taken in the balance window, where differences between cells are exaggerated. |
The normal taper uses 200 W so the cell voltage remains excited enough to advance through the top zone without returning to full power. The optional blueprint uses a gentler 95 W charge leg. Measurements are always taken at rest after charge and discharge stop for 60 seconds, so neither charge power contaminates the recorded delta.
Why this takes so long¶
Cell balancing is not a fast process — and Marstek Venus packs are no exception. There are two reasons.
1. Passive balancing current is small. A typical LFP BMS bleeds the highest cell through a balance resistor at somewhere between 30 mA and 150 mA. The Marstek Venus packs sit at the low end of that range. For a 100 Ah cell, a 50 mA bleed removes only about 0.05 % SOC per hour from the high cell. Equalising even small SOC differences between cells therefore requires many hours of continuous time in the balance window.
2. The balance window itself is narrow. The BMS can only bleed when the pack is above ~3.45 V and the highest cell is detectably above the rest. As soon as charging stops or the pack drops back below the knee, balancing stops. A normal charge cycle that hits 100 % and immediately returns to discharge spends only minutes in the useful window — far too little for any visible effect.
The practical consequence:
Reducing the top-of-charge cell delta by roughly 5 mV typically takes around 24 hours of cumulative time at the top of the balance window.
That figure is consistent both with the bleed-current arithmetic above and with observations on real Venus packs. Bigger imbalances (50 mV or more) can take multiple days of repeated top-balance sessions before the delta starts dropping consistently. Packs that have been left chronically unbalanced for months may take a week or more to recover.
This is also why the active-balance blueprint does not have a "fast" path:
- the 95 W charge cap above 3.48 V is set so the pack stays in the knee long enough for the BMS to make progress, rather than ramming through it in seconds;
- the 200 W discharge between retries brings the pack back down to the retry voltage without dropping out of the window;
- the automation is allowed to run indefinitely, because anything short of "many hours" is unlikely to move the needle.
If the goal is to restore a noticeably unbalanced pack, import the blueprint, create one automation for that battery and leave it running overnight (or longer) before checking the result. Watching the cell delta in real time and expecting movement within minutes will only cause frustration.
How imbalance is measured¶
The only reading that feeds the balance status, alerts and trend is the explicit top-voltage measurement:
- the battery reaches
max_cell_voltage >= 3.60 V; - charge is stopped;
- the integration waits 60 seconds;
- it records the spread between
max_cell_voltageandmin_cell_voltage.
Older OCV-style readings, opportunistic readings and long passive-hold readings are no longer used. Measuring at the same top-voltage point makes readings more comparable from one full charge to the next.
Thresholds¶
| Status | Delta range | Meaning |
|---|---|---|
| Green | < 50 mV | Good balance |
| Yellow | 50-99 mV | Minor imbalance; monitor over time |
| Orange | 100-149 mV | Moderate imbalance |
| Red | >= 150 mV | High imbalance |
Thresholds are fixed and apply equally to all supported LFP packs.
Notifications¶
The integration sends Home Assistant persistent notifications for these events:
| Event | Notification title |
|---|---|
| Orange or red top-voltage reading | Cell imbalance - {battery name} |
| Red on 2 or more consecutive full charges | Possible degraded cell - {battery name} |
| Rising trend with average above 75 mV | Rising imbalance trend - {battery name} |
Sensor entities¶
Five sensor entities are created per battery when the feature is enabled:
| Entity | Description | Unit |
|---|---|---|
sensor.*_cell_delta |
Voltage spread between max and min cell | mV |
sensor.*_balance_status |
Balance result: green / yellow / orange / red |
- |
sensor.*_delta_trend |
Trend over recent readings: rising / stable / falling |
- |
sensor.*_last_balance_read |
Timestamp of the last reading | timestamp |
sensor.*_delta_avg_4w |
Rolling average of the last 4 readings | mV |
Values are restored from persistent storage after a Home Assistant restart so sensors show the last known state immediately on startup.
Diagnostics¶
The Integration Status sensor exposes a normal_balance_protection attribute with per-battery details:
| Attribute | Meaning |
|---|---|
enabled |
Whether 100% voltage taper is enabled for that battery |
in_zone |
Whether max_cell_voltage is in the top-balance window |
max_cell_voltage / min_cell_voltage |
Current cell voltage extremes |
delta_V |
Current voltage spread in volts |
voltage_taper_latched |
Whether the 200 W normal-charge taper is currently active |
bms_cutoff_charge_active |
Whether Venus A/D are being kept charge-eligible until their BMS cutoff |
bms_cutoff_measurement |
Venus A/D post-cutoff measurement state: pending or done |
soc_recal_active |
Whether the charge is being kept past 3.60 V to attempt recalibration of a low reported SOC |
soc_recal_bms_cutoff |
Whether the BMS cutoff has been reached during recalibration (override latched off) |
soc_recal_retry_pending |
Whether the battery is waiting for 3.57 V before the one-shot retry |
soc_recal_retry_active |
Whether the one-shot 200 W retry is in progress |
soc_recal_first_cutoff_voltage |
Highest voltage observed during the first BMS cutoff |
charge_limit_w |
Effective per-battery charge limit before allocation |
The blueprint's phase, retry voltage and cleanup result are reported in its persistent notifications; they are not integration status attributes. Each settled rest measurement is also recorded in the existing Cell Delta history with source: blueprint, using the integration's own coordinator telemetry.
Info
Cell voltage registers (max_cell_voltage, min_cell_voltage) are read from all supported battery versions (v2, v3, vA, vD).