BattPulse

Securing the Energy Transformation

BMS Display 7"
Developer API Reference

CAN Bus Protocol WiFi HTTP/JSON API

Integration guide for BMS manufacturers and developers.
Implement these protocols to make your BMS compatible with the BattPulse Display.

Document: BP-DSP-7001-API  |  Revision 1.1  |  March 2026
Β© 2026 BattPulse by SONAL  |  info@battpulse.com  |  battpulse.com

πŸ“„ Get the latest version of all documents
πŸ“š BattPulse BMS Display 7" Documentation
Quick Start Guide  |  Developer API Reference  |  Product Datasheet  |  All Documents  |  πŸ›’ Get the Display

Contents

  1. Introduction
  2. Data Model
  3. CAN Bus Protocol β€” Overview
  4. CAN Bus Protocol β€” Frame Reference
  5. CAN Bus Protocol β€” Command Frame
  6. CAN Bus Protocol β€” Code Examples
  7. WiFi HTTP/JSON Protocol β€” Overview
  8. WiFi HTTP/JSON Protocol β€” Endpoints
  9. WiFi HTTP/JSON Protocol β€” Code Examples
  10. Dynamic Hardware Support
  11. Troubleshooting

1. Introduction

The BattPulse BMS Display 7" is an open-protocol touch display that shows real-time BMS data from any compatible battery management system. It supports two communication methods:

Method Transport Speed Best For
CAN Bus CAN 2.0A (11-bit) 100 ms cycle Direct wired connection, vehicles, industrial, no WiFi needed
WiFi HTTP POST / JSON ~250 ms cycle Remote monitoring, wall-mounted displays, existing WiFi infrastructure
πŸ”Œ Who Is This Document For?

This API reference is for BMS manufacturers and embedded developers who want to make their BMS compatible with the BattPulse Display. Implement either the CAN Bus protocol or the WiFi JSON API (or both) and the display will visualise your BMS data automatically.

2. Data Model

Regardless of the transport (CAN or WiFi), the display maintains the same internal data model:

FieldTypeRangeDescription
Pack Voltagefloat0 – 100 VTotal pack voltage
Pack Currentfloat-500 – +500 APositive = discharge, Negative = charge
SOCfloat0 – 100 %State of Charge
Max Cellfloat0 – 5 VHighest individual cell voltage
Min Cellfloat0 – 5 VLowest individual cell voltage
Cell Countuint86 – 16Number of series cells (auto-detected)
Cell Voltagesfloat[]up to 32Individual cell voltages in volts
Temperature Probesstruct[]up to 8Name + value (Β°C) for each active probe
I/O Statesstruct[]up to 8Name + ON/OFF for each I/O (FETs, balancing, etc.)
Event Stringstring32 charsStatus message: "OK", "WARN 0x01", "FAULT 0x03"
Statusenum0–30=Idle, 1=Charging, 2=Discharging, 3=Fault

3. CAN Bus Protocol β€” Overview

Physical Layer

ParameterValue
StandardCAN 2.0A (11-bit identifiers)
Baud Rate500 kbps (default), 125 / 250 / 1000 kbps supported
Byte OrderLittle-endian (LSB first)
TransceiverTJA1051T/3 (3.3 V compatible)
Termination120 Ξ© onboard (jumper selectable)
Cycle Time100 ms (all frames)
Frame FormatStandard (11-bit), no extended, no RTR

CAN ID Map

CAN ID(s) Direction Frame Name DLC Cycle
0x300 BMS β†’ Display Pack Status (V, I, SOC) 8 100 ms
0x301 BMS β†’ Display Pack Status Extended (MaxC, MinC, Temp) 8 100 ms
0x330 – 0x337 BMS β†’ Display Cell Voltages (2 cells per frame) 4 100 ms
0x350 – 0x351 BMS β†’ Display Temperature Probes (4 per frame) 8 100 ms
0x360 BMS β†’ Display I/O State (FETs, Balancing, Inputs) 2 100 ms
0x370 BMS β†’ Display Fault / Warning Bitmasks 4 100 ms
0x3A0 Display β†’ BMS Command Frame (Restart) 5 On demand
πŸ’‘ All CAN IDs are configurable
The base IDs above are defaults. Users can change them in the display's Settings page to match any CAN bus layout.

4. CAN Bus Protocol β€” Frame Reference

Frame 0x300 β€” Pack Status

BMS β†’ Display  |  DLC: 8  |  100 ms cycle
ByteTypeScaleUnitDescription
0–1uint16Γ· 100VPack Voltage (e.g. 5120 = 51.20 V)
2–3int16Γ· 10APack Current (+ = discharge, βˆ’ = charge)
4–5uint16Γ· 10%SOC (e.g. 850 = 85.0%)
6uint8β€”β€”Status: 0=Idle, 1=Charge, 2=Discharge, 3=Fault
7uint8β€”β€”Reserved

Frame 0x301 β€” Pack Status Extended

BMS β†’ Display  |  DLC: 8  |  100 ms cycle
ByteTypeScaleUnitDescription
0–1uint16Γ· 1000VMax Cell Voltage
2–3uint16Γ· 1000VMin Cell Voltage
4–5int16Γ· 10Β°CMax Temperature
6–7int16Γ· 10Β°CMin Temperature

Frames 0x330–0x337 β€” Cell Voltages

BMS β†’ Display  |  DLC: 4  |  100 ms cycle  |  Only active cells sent
ByteTypeScaleUnitDescription
0–1uint16Γ· 1000VCell N voltage (e.g. 3650 = 3.650 V)
2–3uint16Γ· 1000VCell N+1 voltage

Cell-to-Frame mapping:

CAN IDCellsCAN IDCells
0x330Cell 1, 20x334Cell 9, 10
0x331Cell 3, 40x335Cell 11, 12
0x332Cell 5, 60x336Cell 13, 14
0x333Cell 7, 80x337Cell 15, 16
ℹ️ Dynamic Cell Count

Frames 0x350–0x351 β€” Temperature Probes

BMS β†’ Display  |  DLC: 8  |  100 ms cycle  |  Only active probes sent

Each frame carries 4 temperature probes:

ByteTypeScaleUnitDescription
0–1int16Γ· 10Β°CProbe slot 0 (or 4)
2–3int16Γ· 10Β°CProbe slot 1 (or 5)
4–5int16Γ· 10Β°CProbe slot 2 (or 6)
6–7int16Γ· 10Β°CProbe slot 3 (or 7)
CAN IDProbes
0x350T1, T2, T3, T4
0x351T5, T6, T7, T8
ℹ️ Dynamic Probe Count

Frame 0x360 β€” I/O State

BMS β†’ Display  |  DLC: 2  |  100 ms cycle
ByteTypeDescription
0–1uint16 (LE)I/O bitmask
BitName on DisplayMeaning
0CHGCharge FET (1 = ON, 0 = OFF)
1DSCDischarge FET (1 = ON)
2BALBalancing active (1 = ON)
3IN1Digital input 1 (1 = ON)
4IN2Digital input 2 (1 = ON)
5IN3Digital input 3 (1 = ON)
6–15IN4–IN13Reserved for future inputs
ℹ️ Dynamic Inputs

Frame 0x370 β€” Faults & Warnings

BMS β†’ Display  |  DLC: 4  |  100 ms cycle
ByteTypeDescription
0–1uint16 (LE)Warning bitmask (yellow indicator)
2–3uint16 (LE)Fault bitmask (red indicator)

Warning bits:

BitMeaning
0General BMS alarm

Fault bits:

BitMeaning
0Cell overvoltage
1Cell undervoltage
2Over-temperature
3Emergency power-down

When any fault bit is set, the display shows a red fault banner with the fault code. Warning bits trigger a yellow event indicator.

5. CAN Bus Protocol β€” Command Frame

Frame 0x3A0 β€” Command (Display β†’ BMS)

Display β†’ BMS  |  DLC: 5  |  On demand only

This is the only frame sent from the display to the BMS. It uses a two-step ARM + EXECUTE safety protocol to prevent accidental commands.

ByteTypeDescription
0uint8Command: 0x01 = ARM, 0x02 = EXECUTE
1–4bytesSafety key: { 0x52, 0x53, 0x54, 0x52 } ("RSTR")

Two-Step Protocol

StepByte 0Action
1. ARM0x01BMS enters armed state, starts 2-second timer
2. EXECUTE0x02If armed and within 2 seconds β†’ BMS restarts
⚠️ Safety Key Required
Every command frame MUST include the 4-byte safety key { 0x52, 0x53, 0x54, 0x52 } at bytes 1–4. Frames with incorrect keys are silently rejected by the BMS.

Protocol Sequence Diagram

 Display                          BMS
  β”‚                                β”‚
  │── 0x3A0 [01 52 53 54 52] ───►│  ARM β†’ armed state, 2s timer
  β”‚                                β”‚
  β”‚     (within 2 seconds)         β”‚
  β”‚                                β”‚
  │── 0x3A0 [02 52 53 54 52] ───►│  EXECUTE β†’ restart!
  β”‚                                β”‚
  β”‚        ~~~ BMS reboots ~~~     β”‚
  β”‚        (2–4 second gap)        β”‚
  β”‚                                β”‚
  │◄── 0x300, 0x330, etc. ────────│  BMS back online

Timeout Behaviour

ScenarioResult
ARM β†’ EXECUTE (within 2s)BMS restarts
ARM β†’ (wait > 2s) β†’ EXECUTEIgnored (timer expired)
EXECUTE without ARMIgnored
ARM β†’ ARM β†’ EXECUTEBMS restarts (second ARM resets timer)
ARM only (no EXECUTE)Armed state expires silently after 2s

6. CAN Bus Protocol β€” Code Examples

Sending BMS Data to the Display (C)

/* Build and transmit CAN frame 0x300 β€” Pack Status
 * Adapt can_send() to your platform's CAN driver. */
void sendPackStatus(float packVoltage, float packCurrent,
                    float soc, uint8_t status) {
    uint8_t data[8] = {0};

    uint16_t v = (uint16_t)(packVoltage * 100);   // 51.20 V β†’ 5120
    int16_t  i = (int16_t)(packCurrent * 10);     // -12.5 A β†’ -125
    uint16_t s = (uint16_t)(soc * 10);             // 85.0 % β†’ 850

    data[0] = v & 0xFF;  data[1] = v >> 8;     // little-endian
    data[2] = i & 0xFF;  data[3] = i >> 8;
    data[4] = s & 0xFF;  data[5] = s >> 8;
    data[6] = status;    // 0=Idle, 1=Charge, 2=Discharge, 3=Fault
    data[7] = 0;          // reserved

    can_send(0x300, data, 8);  // ← your CAN driver's transmit function
}

/* Build and transmit cell voltage frames 0x330–0x337
 * Example: 7S pack β€” sends 4 frames, last cell padded with 0x0000. */
void sendCellVoltages(float *cellV, int cellCount) {
    for (int pair = 0; pair < (cellCount + 1) / 2; pair++) {
        uint8_t data[4] = {0};
        int c0 = pair * 2;
        int c1 = c0 + 1;

        uint16_t v0 = (uint16_t)(cellV[c0] * 1000);  // 3.650 V β†’ 3650
        uint16_t v1 = (c1 < cellCount)
                    ? (uint16_t)(cellV[c1] * 1000) : 0;
        // ↑ Odd cell count: second slot = 0x0000 (display treats as padding)

        data[0] = v0 & 0xFF;  data[1] = v0 >> 8;
        data[2] = v1 & 0xFF;  data[3] = v1 >> 8;

        can_send(0x330 + pair, data, 4);
    }
}

Handling the Restart Command on the BMS (C)

/* Called when CAN frame 0x3A0 is received.
 * Implements the two-step ARM + EXECUTE safety protocol.
 * Adapt get_tick_ms() and system_restart() to your platform. */
static bool     restart_armed = false;
static uint32_t arm_time_ms   = 0;

void handleCommandFrame(const uint8_t *data, uint8_t dlc) {
    if (dlc < 5) return;
    // Verify safety key: "RSTR" = { 0x52, 0x53, 0x54, 0x52 }
    if (data[1] != 0x52 || data[2] != 0x53 ||
        data[3] != 0x54 || data[4] != 0x52) return;

    switch (data[0]) {
        case 0x01:  // ARM
            restart_armed = true;
            arm_time_ms   = get_tick_ms();
            break;
        case 0x02:  // EXECUTE
            if (restart_armed &&
                (get_tick_ms() - arm_time_ms) < 2000) {
                system_restart();  // ← your platform's reboot function
            }
            break;
    }
}

7. WiFi HTTP/JSON Protocol β€” Overview

The display connects to the BMS over WiFi using HTTP POST requests to a single endpoint. The BMS acts as an HTTP server.

ParameterValue
TransportHTTP 1.1 POST
Content-Typetext/plain
Endpointhttp://<BMS_IP>/JsonHandle
Request BodyJSON object with "type" field
ResponseJSON object or array
Poll Interval~250 ms (alternating dashboard / cellStates)

The display sends two types of requests in alternation:

  1. Dashboard request β€” returns pack status, temperatures, I/O states
  2. Cell States request β€” returns individual cell voltages and colours

8. WiFi HTTP/JSON Protocol β€” Endpoints

Dashboard Request

POST /JsonHandle  |  Body: {"type":"dash"}

Request:

POST /JsonHandle HTTP/1.1
Content-Type: text/plain

{"type":"dash"}

Response (BattPulse format):

{
  "status": {
    "current": -12.5,
    "SoC": 85.0,
    "totSystV": 51.20,
    "MaxC": 3.65,
    "MinC": 3.60,
    "Balance": 1,
    "event": "OK"
  },
  "temps": {
    "ChipTemp": 32.0,
    "ShuntTemp": 19.0,
    "Aux_1": 18.0,
    "Aux_2": 19.0
  },
  "ntcs": {
    "NTC_1": 22.5,
    "NTC_2": 23.0
  },
  "IO_States": {
    "CHG": 1,
    "DSC": 1,
    "BAL": 0
  }
}
ℹ️ Temperature Names Are Displayed
When data comes via WiFi, the JSON key names (e.g. "ChipTemp", "ShuntTemp", "Aux_1") are displayed directly on the dashboard as probe labels. Choose meaningful names for your sensors.

Field Reference:

FieldTypeDescription
status.currentfloatPack current in amps (+ = discharge, βˆ’ = charge)
status.SoCfloatState of charge (0–100)
status.totSystVfloatTotal pack voltage
status.MaxCfloatHighest cell voltage
status.MinCfloatLowest cell voltage
status.Balance0/1Balancing active flag
status.eventstringEvent / status message
temps.*objectNamed temperature probes (key = name, value = Β°C)
ntcs.*objectNamed NTC probes (merged with temps on display)
IO_States.*objectNamed I/O states (key = name, value = 0 or 1)

Cell States Request

POST /JsonHandle  |  Body: {"type":"cellStates"}

Request:

POST /JsonHandle HTTP/1.1
Content-Type: text/plain

{"type":"cellStates"}

Response:

{
  "cells": {
    "Cell1": 3.650,
    "Cell2": 3.645,
    "Cell3": 3.660,
    "Cell4": 3.640,
    "Cell5": 3.655,
    "Cell6": 3.648,
    "Cell7": 3.652
  },
  "colors": {
    "1": "#30B32D",
    "2": "#30B32D",
    "3": "#F5A623",
    "4": "#30B32D"
  },
  "status": {
    "current": -12.5
  },
  "IO_States": {
    "CHG": 1,
    "DSC": 1
  }
}

Field Reference:

FieldTypeDescription
cellsobjectKey-value pairs of cell names and voltages. Cell count = number of keys.
colorsobjectOptional. Key = cell number (1-based), value = hex colour for that cell's border.
status.currentfloatPack current (same as dashboard)
IO_StatesobjectI/O states (same format as dashboard)
πŸ’‘ Cell Colours
The colors object is optional. If provided, the display uses your BMS-defined colours for each cell border. If not provided, the display uses its own colour coding based on voltage ranges (green = good, yellow = warning, red = critical).

9. WiFi HTTP/JSON Protocol β€” Code Examples

Minimal BMS HTTP Server (C β€” Pseudocode)

/* Minimal example showing the JSON response structure.
 * Adapt to your platform's HTTP server library. */

void handleJsonRequest(const char *body, http_response_t *resp) {
    // Parse the "type" field from the POST body
    const char *type = json_get_string(body, "type");

    if (strcmp(type, "dash") == 0) {
        // Return pack status, temperatures, and I/O states
        http_send_json(resp,
            "{"
            "  \"status\": {"
            "    \"current\": -12.5,"
            "    \"SoC\": 85.0,"
            "    \"totSystV\": 51.20,"
            "    \"MaxC\": 3.65,"
            "    \"MinC\": 3.60,"
            "    \"Balance\": 1,"
            "    \"event\": \"OK\""
            "  },"
            "  \"temps\": { \"BoardTemp\": 32.0, \"Shunt\": 19.0 },"
            "  \"IO_States\": { \"CHG\": 1, \"DSC\": 1, \"BAL\": 0 }"
            "}"
        );
    }
    else if (strcmp(type, "cellStates") == 0) {
        // Return individual cell voltages
        http_send_json(resp,
            "{"
            "  \"cells\": {"
            "    \"Cell1\": 3.650, \"Cell2\": 3.645,"
            "    \"Cell3\": 3.660, \"Cell4\": 3.640,"
            "    \"Cell5\": 3.655, \"Cell6\": 3.648,"
            "    \"Cell7\": 3.652"
            "  }"
            "}"
        );
    }
}

/* Register the handler on your HTTP server:
 *   http_register_post("/JsonHandle", handleJsonRequest);
 * The display will POST to this endpoint every ~250 ms. */

10. Dynamic Hardware Support

The display is designed to work with many different BMS configurations without needing firmware changes. Here's what adapts automatically:

Feature CAN Bus Behaviour WiFi Behaviour
Cell Count Auto-detected from cell voltage frames received. 6–16S. Odd counts supported (padding = 0x0000). Auto-detected from number of keys in cells object.
Temp Probe Count Auto-detected from non-zero slots in temp frames. 1–8 probes. Labels: T1, T2, ... T8. Auto-detected from temps + ntcs keys. Labels from JSON key names.
Temp Probe Names Generic labels: T1, T2, T3, etc. (CAN protocol doesn't carry names.) Uses sensor names from JSON (e.g. "ChipTemp", "ShuntTemp", "Aux_1").
I/O States CHG, DSC, BAL always shown; IN1–INx auto-detected from bits 3+. Dynamic: any number of named I/O states from JSON.
Cell Colours Auto-generated from voltage ranges. BMS can supply custom colours via colors object, or auto-generated.

11. Troubleshooting

ProblemCAN BusWiFi
No data on display Check CAN-H/CAN-L wiring. Verify baud rate matches. Check termination. Verify BMS IP. Check WiFi connection. Try "Scan Network".
Wrong cell count Ensure only active cell frames are sent. Use 0x0000 padding for odd counts. Check cells object has correct number of entries.
Extra 0 Β°C temp probes Set unused probe slots to 0x0000 (raw int16 = 0). Display auto-hides them. Only include active probes in temps/ntcs objects.
Restart command ignored Verify safety key bytes match exactly. ARM must precede EXECUTE within 2s. N/A (no restart via WiFi)
Slow update rate Ensure 100ms cycle. Check CAN bus load. BMS HTTP server must respond within 900ms. Keep JSON compact.