Skip to content
Stand with Ukraine flag

Normalize Cell Voltages and Compute Spread

  • Calculated Field
  • 1 install
  • v1.0.1
  • Aug 26, 2026
  • MIT license
  • v4.3+

Turn a per-cell battery voltage array into min, max, average and the cell imbalance in millivolts, converting millivolt readings to volts automatically.

Type
  • Script
Category
  • Statistical
  • Custom Formula
Use Cases
  • Predictive Maintenance
  • Smart Energy

Who it’s for

Anyone monitoring a multi-cell battery pack - a LiFePO4 or Li-ion storage bank, an EV or e-bike pack, a telecom or solar backup string - whose device (or BMS) reports the individual cell voltages. It turns that raw per-cell array into the four numbers a pack dashboard and its alarms actually use, and it fixes the unit problem (millivolts vs volts) once, on the server, so every widget, chart and rule downstream sees the same correct value.

What it does

Reads one telemetry key holding the per-cell voltages as a JSON array (for example [3.520, 3.600, 3.550, 3.472]), fixes the units, and writes the lowest, highest and average cell voltage plus the spread between them:

Normalize Cell Voltages and Compute Spread diagram

The spread is the point. A pack can read a healthy total voltage and a confident 100 percent while one cell quietly drifts out of line. The pack-level number cannot show it, but the spread can, and a widening spread over time is the earliest sign of a failing pack. Because cellSpreadMv is now a real telemetry key, an alarm rule can fire on it, a chart can trend it, and a card can display it.

It also normalises units: if the cell readings arrive in millivolts (any value above 100), they are converted to volts before anything is computed, so cellSpreadMv is correct whether the device sends 3.472 or 3472.

How to set up

  1. On the device (or asset) that carries the pack, add this calculated field.
  2. Check the cells argument: its Time series key defaults to cellVoltages. Change it if your device publishes the array under a different key.
  3. Post or wait for a telemetry update. The four output keys appear on the entity and update on every new reading.
  4. Use them: bind cellMinV / cellMaxV / cellAvgV to a pack widget, trend cellSpreadMv on a time-series or range chart, and raise an alarm when cellSpreadMv crosses your imbalance threshold.

Suggested imbalance thresholds, derived from the cell’s full voltage (not a single guessed number): advisory at 3 percent of full capped at 120 mV, serious at 5 percent capped at 200 mV. For LiFePO4 that is about 110 / 183 mV, and for Li-ion / NCM, 120 / 200 mV.

How to customize

  • To read the array from a different key - change the Time series key on the cells argument.
  • To change what counts as a millivolt reading - open the script and change the 100. Raise it only if you monitor modules above 100 V reported in volts.
  • To rename the outputs - open the script and rename the result.* keys.

See also

Trend cellSpreadMv on a Range chart or Time series chart with the two thresholds above to watch the imbalance over time.

If your BMS reports only the minimum and maximum cell voltage rather than the whole per-cell array, that is the other template - this one reads the array and also gives you the pack average, that one reads the two extremes:

Compute Cell Spread from Min and Max Andrii Zaiko

Share Your Calculated Field with the Community

Built a useful data transformation? Export it as a JSON from ThingsBoard and publish it to the IoT Hub. Share it with thousands of ThingsBoard developers worldwide.