Battery State of Health (SoH)
State of Health is the answer to "how much useful life does this pack have left?" State of Charge tells you what's in the tank right now; SoH tells you whether the tank itself is shrinking.
Levy Swap calculates SoH for every deployed pack nightly. The result is a single dashboard-facing number between 0 and 100, plus the individual signals that produced it.
The Levy SoH Index
| SoH Range | What It Means | Recommended Action |
|---|---|---|
| 90 – 100 | New or near-new | Use anywhere; ignore |
| 75 – 89 | Healthy | Use anywhere; keep an eye on temperature exposure |
| 60 – 74 | Aging | Rotate into lower-demand vehicles |
| 40 – 59 | End-of-life warning | Retire from high-mileage vehicles; plan replacement |
| Below 40 | Forced retirement | Pack is automatically flagged for retirement on the next swap |
The index is a weighted blend of the signals below. No single signal can push a pack to retirement on its own — but combined, they catch packs that look fine on a single dimension and rotten on another.
What Goes Into the Index
1. Equivalent Full Cycles (EFC)
Cumulative depth-of-discharge expressed as the equivalent number of full charge/discharge cycles. Two 50% discharges count as one EFC. This is the cleanest "how worked has this pack been?" signal and is comparable across vehicle types and ride patterns.
EFC is computed from the long-running SoC telemetry stream — every drop in battery_level is treated as a partial discharge and accumulated. The job is idempotent: re-running it doesn't double-count.
2. Capacity Fade Percentage
Derived from voltage-under-known-load measurements. Each vehicle model has a rated voltage (stored on the vehicle_model), and the nightly job compares observed voltage at low-load conditions to the rated baseline. A pack that consistently sags below its rated voltage at rest is losing usable capacity.
This is the most chemistry-sensitive signal — LFP packs hold flat for most of their life and fall off a cliff; NMC packs decline more linearly. The model accounts for the chemistry stored on the pack row.
3. Temperature Exposure Score
Two accumulators are tracked per pack:
- Hot minutes — minutes spent above 45 °C battery temperature
- Cold minutes — minutes spent below 0 °C battery temperature
Both are weighted heavily in the SoH formula because both materially accelerate fade. A pack that lives in a summer-Phoenix garage with no cooling will degrade roughly twice as fast as the same pack in a temperate-climate operator's storage.
4. Internal Resistance Proxy
Lithium packs increase their internal resistance as they age, and the symptom is voltage sag under load. The SoH engine correlates concurrent telemetry — voltage drops while the vehicle is being ridden hard (speed up, current up) — to estimate this resistance growth without firmware-level access.
5. EoL Prediction (End-of-Life Date)
Once a pack has at least 30 days of data, the engine does a linear extrapolation of the fade rate to project when SoH will cross 40 (forced retirement). The output is a predicted date with a confidence interval. Use this for ordering replacement packs ahead of time, not as a hard deadline.
Supported IoT Types and Confidence Weights
SoH quality depends on the telemetry fidelity of the underlying IoT type. Each OEM contributes data weighted by a confidence factor — the lower the weight, the more conservative the SoH score (we don't punish a pack for thin data, but we also don't claim high confidence in it).
| OEM / IoT Type | Confidence Weight | Notes |
|---|---|---|
| OKAI | 1.0 | Most fields; cleanest voltage + temperature stream |
| Segway | 0.9 | Full coverage; current draw available |
| Omni 4G | 0.85 | Voltage + temperature; some packets sparse |
| Queclink (ZK600 / ZK105L) | 0.8 | Reliable voltage; temperature gaps possible |
| Acton / Feishen / Physhen | 0.7 | Lower-frequency packets; H0 mapping varies |
| Zimo | 0.5 | MQTT-only payload; fewer fields, longer SoH "warmup" |
| AXA / Manual | n/a | No live telemetry — SoH shows "n/a" |
If a vehicle's IoT type isn't in this list, the pack still has a row but the index is blank and the Battery Health page shows "n/a" with the IoT-type reason.
Where to See SoH in the Dashboard
- Dashboard → Swap → Battery Health — fleet-wide leaderboard, filterable by SoH band, EoL window, or rotation flag
- Per-pack drill-down — click any pack to see its voltage curve, hot/cold minute history, swap history, and projected EoL
- Per-vehicle detail — the assigned pack's SoH appears on each vehicle's detail page
When SoH Triggers Action
- SoH below 60 raises a "rotation recommended" flag, which surfaces the vehicle on the operator-app Swap Queue with a non-SoC reason.
- SoH below 40 flags the pack for retirement; the next swap completes the pack into the
returnedstate instead of going back into station inventory. - EoL within 30 days appears in the Battery Health summary cards so you can place replacement orders ahead of the cliff.
What SoH Does Not Do
- It does not require new hardware. We use existing OEM telemetry only.
- It does not flash battery BMS firmware.
- It is not a capacity test — a lab-grade discharge test is more accurate, but impractical at fleet scale. SoH is a continuous proxy that's been validated to within roughly ±10% MAE on 30-day-ahead capacity prediction across the supported OEM matrix.
Troubleshooting SoH
See Troubleshooting for the most common SoH issues — packs stuck "warming up," sudden drops after a firmware update, and discrepancies between SoH and observed range.