Battery cell voltage monitor
Shows each cell’s voltage in a multi-cell battery pack, flags the weakest cell and the imbalance in millivolts, and warns while the pack total reads full.
Who it’s for
Anyone watching a multi-cell battery pack — a LiFePO4 or Li-ion storage bank, an EV or e-bike pack, a solar or telecom backup string — asks which cell is dragging the pack down, and why a pack that reads full keeps delivering shorter runtimes. A pack total answers neither: it stays healthy right up until the weakest cell collapses. This card is where you look at the cells instead of the total.
What it does
A 16-cell LiFePO4 string reports a pack total of 56.36 V at an average of 3.523 V — both healthy, and a pack-level card would stop there. Drawn cell by cell, cell 4 sits at 3.472 V against cell 11 at 3.600 V: a spread of 128 mV, enough to turn the verdict chip amber while the pack total still reads full.
- Every cell on a zoomed axis. The frame runs from the lowest cell to the highest plus a small margin, so a few millivolts of spread is visible instead of a row of identical bars. Small packs draw numbered tiles, and larger packs draw a bar row.
- The weak cell by number. The lowest and highest cells are marked with their cell number, so a technician knows which link to put a meter on rather than only that something is off.
- The spread in millivolts, beside the pack voltage and the average cell voltage.
- The cell count the widget actually parsed.
16Sfor a sixteen-cell string. An array that arrives short draws as15Sinstead of being charted as though it were the whole pack. - An imbalance verdict derived from the chemistry. Amber past the advisory threshold, red past the serious one — computed from the cell’s full voltage rather than one guessed millivolt figure, and both relax near the top of a charge where the curve naturally pushes cells apart.
- Pack context when your BMS sends it. State of charge, current, power, temperature, capacity, cycle count and state of health, each appearing only when its key arrives.
- Shows the pack as it stands right now: it does not chart the spread over time, and it does not balance cells or command the BMS.
Requirements
A device that reports the individual cell voltages — a BMS, a battery gateway, or anything that publishes them as one JSON array or as a key per cell. A pack total alone is not enough: the card draws cells, and the spread it measures does not exist at pack level. Server-side attributes work as well as telemetry, which matters on a hosted tenant where an attribute is the value an operator can write without a device token.
How to set up
Data keys
| Key | Role | Type | Description |
|---|---|---|---|
cellVoltages (user-configured) | Per-cell values | Timeseries or Attribute | A JSON array of numbers, for example [3.305, 3.306, 3.305, 3.298]. Volts and millivolts are both accepted and auto-detected. One key carries a pack of any length |
| one key per cell (user-configured) | Per-cell values | Timeseries or Attribute | The alternative shape. Each cell is bound as its own data key on the Data tab and read in bind order, with its own history and time period |
packVoltage (user-configured) | Pack summary row | Timeseries or Attribute | The pack total, in volts |
soc current power temperature capacity cycles soh (user-configured) | Stats strip | Timeseries or Attribute | One key per entry in the context strip |
Cell data source picks between the two shapes, and it is the first setting in the Data tab. The array is the default because one key means one timestamp: every cell in the pack is read at the same instant, and a spread computed across that snapshot is a real spread. Independent per-cell keys cannot promise that — each arrives on its own — but they are ordinary data keys, so each cell carries its own history, time period and unit. Choose the array for a BMS that publishes the pack in one message, and one key per cell for a device that reports its cells separately.
The per-cell key is the only one the card cannot do without — without it nothing renders. Every other key is optional: an unbound one hides its own row, or its own entry in the stats strip, and leaves no empty slot behind. A server-side attribute works as well as a telemetry key, which matters on a hosted tenant where an attribute is the one an operator can write without a device access token.
Data
| Setting | Default | Effect |
|---|---|---|
| Cell data source | One JSON array key for the whole pack | The array is one key with one timestamp, an atomic snapshot of the pack; one key per cell binds each cell as an ordinary data key, with its own history |
| Per-cell voltages key (JSON array) | cellVoltages | The single key that carries the whole pack. Hidden when the source is one key per cell |
| Cell voltage unit | Auto-detect | Pins volts or millivolts rather than relying on the guess. One cell can override it in its own data-key settings |
| Bind optional telemetry keys | Off | Reveals the pack-level key fields below. An installer who has only cell voltages never opens them |
| Show pack summary row | On | Draws the pack total and average, and reads Pack voltage key |
| Pack voltage key | packVoltage | The pack total feeding that row |
| Show the stats strip (SoC, current, cycles, etc.) | On | Draws the context strip and reads the seven keys below it |
| State of charge key (%), Current key, Power key (W), Temperature key, Capacity key (Ah), Cycle count key, State of health key (%) | soc, current, power, temperature, capacity, cycles, soh | One key per entry. Bind only what your device sends |
Battery
| Setting | Default | Effect |
|---|---|---|
| Chemistry preset | Li-ion / NCM | Derives the imbalance thresholds and the balance-start voltage from the cell’s full voltage. Li-SOCl2, CR2032, Li-ion / NCM, LiFePO4, Alkaline, NiMH, Lead-acid 12 V or Custom |
| Imbalance advisory (mV) | from the preset | The amber threshold. Shown under Custom only; every named chemistry derives it |
| Imbalance serious (mV) | from the preset | The red threshold, the same way |
| Balance-start voltage (per cell) | from the preset | The point above which both thresholds relax. Custom only, like the two above |
Each preset carries the cell’s full voltage, and the thresholds are derived from it — three per cent of full for the advisory, five per cent for the serious one, each capped at 120 mV and 200 mV:
| Preset | Full voltage | Advisory / serious | Balance-start |
|---|---|---|---|
| Li-ion / NCM | 4.20 V | 120 / 200 mV | 4.00 V |
| LiFePO4 | 3.65 V | 110 / 182 mV | 3.45 V |
| Li-SOCl2 | 3.67 V | 110 / 184 mV | not applicable |
| CR2032 | 3.40 V | 102 / 170 mV | not applicable |
| Alkaline | 1.60 V | 48 / 80 mV | not applicable |
| NiMH | 1.45 V | 44 / 73 mV | not applicable |
| Lead-acid 12 V | 12.64 V | 120 / 200 mV | not applicable |
| Custom | yours | yours | yours, if the chemistry needs one |
The cap is why a Li-ion cell and a 12 V lead-acid block end up on the same 120 / 200 mV, though their voltages differ by a factor of three.
How to customize
- To widen or tighten the zoom around the cells — set Axis margin around cells (mV).
- To keep numbered tiles on a larger pack — raise Show tiles up to this many cells. Six by default — above it the card draws a bar row.
- To read the cells without a verdict — turn off Show verdict chip.
- To be told when the reading has aged — set Stale after (minutes, 0 = off). The card dims
and the chip reads Stale. It ships off, and the footer prints the age of the reading either way,
as
Last updated 13s agoorLast updated 2h 10m ago. On a card too narrow for three labels the words drop and the age stays. - To match the type to your dashboard — set Pack name font, Value font and Cell count and caption font. Each follows the dashboard until you set it.
Tips
-
Read the spread, not the total. The pack voltage and the state of charge are the two numbers a pack-level card already gives you, and they are the two that stay healthy longest. The spread moves first. Everything else on the card is there to tell you whether that spread means anything yet.
-
A tall bar is not a full cell. The axis frames the real minimum-to-maximum window plus a margin, which is why 128 mV across cells sitting near 3.5 V fills the height of the card. Read the bars against each other, not against the top of the frame. A zero-based axis would draw sixteen identical bars and show nothing, which is exactly why this card does not use one.
-
The extremes are numbered so you can act on them. Knowing a pack is 128 mV out tells you to raise a ticket. Knowing it is cell 4 tells the technician which link to put a meter on.
-
Check the cell count in the header.
16Sis how many cells the widget parsed, not how many you own. A sixteen-cell pack drawing as15Smeans the array arrived short or a key is mistyped. -
A wide spread near full charge is less alarming than the same spread at rest. Cells push apart while the balancer works at the top of a charge, so the thresholds relax above the balance-start voltage. The same spread on a pack sitting at rest is the one to chase.
-
Half the chemistries carry no balance-start voltage, and that is deliberate. Relaxing the verdict near a full charge only makes sense where there is something to charge and where the curve turns steep at the top — the lithium chemistries a BMS actually balances. Li-SOCl2, CR2032 and alkaline cells are primary: they are never charged, so there is no top of charge to relax around. NiMH is charged, but termination is read from a voltage drop and from temperature rather than from a per-cell threshold. The lead-acid preset describes a whole 12 V block, which is equalised at block level rather than balanced cell by cell. For all of them the spread is taken at face value, at any point in the charge.
-
A backup string sits float-charged for months and reads full the whole time, while a cell losing capacity surfaces only under load — usually during the outage the bank exists for. Watch the spread while the pack is idle: it moves weeks before the total does.
-
Cell voltages tell you the pack’s internal health. They do not tell you whether the device carrying that pack is still reporting, how strong its link is, or when it was last heard from — and a silent gateway looks exactly like a healthy pack until somebody checks. Put the two side by side:
${item-link:d7931040-8f49-11f1-a1b4-f1800178e9a1}
For the spread over time, which is the earliest failure signal a pack gives, derive it as a calculated field and chart that — an alarm rule can then fire on it. When your BMS sends the raw per-cell array, one field on the hub normalizes it and computes the spread:
${item-link:da992630-932c-11f1-9a63-ef2cf49c242b}
When it already reports a minimum and a maximum, another takes those instead:
${item-link:3a4f4030-93fc-11f1-9a63-ef2cf49c242b}
Share Your Widget with the Community
Built a custom widget? Export it as a JSON from ThingsBoard and publish it to the IoT Hub through a simple 4-step wizard (Upload, Listing, Readme, Review & Submit). Share it with thousands of ThingsBoard developers worldwide and get featured in the catalog.