The BMS Dashboard API provides real-time battery management system data along with GPS tracking information for electric vehicles and IoT devices. The API supports multiple battery packs per device, returning an array of device data objects when multiple batteries are connected.
Base URL: https://api.baliniot.in
Authentication: Bearer Token (JWT)
Retrieves comprehensive BMS data including battery metrics, cell voltages, temperatures, and GPS location for a specific device. Returns multiple entries if the device has multiple battery packs.
Endpoint: GET /api/BMS/Dashboard/{deviceId}
Parameters:
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
| deviceId | Integer | Path | Yes | Unique identifier for the device |
| Authorization | String | Header | Yes | Bearer token for authentication |
Request Headers:
Accept: application/json, text/plain, */*
Authorization: Bearer {jwt_token}
Origin: https://iot.baliniot.in
Example Request:
curl 'https://api.baliniot.in/api/BMS/Dashboard/20774' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Status Code: 200 OK
Response Structure:
{
"result": true,
"data": [
"{JSON_STRING_BATTERY_1}",
"{JSON_STRING_BATTERY_2}",
"{JSON_STRING_BATTERY_N}"
]
}
Important Notes:
- The
dataarray contains JSON-encoded strings that need to be parsed individually- Each array element represents one battery pack connected to the device
- For single battery devices:
data.length === 1- For multiple battery devices:
data.length === number of battery packs- Each string contains complete device snapshot with position and BMS data for that specific battery
Each battery in a multi-battery system can be identified by:
data array (0-based)device.attributes.batterySerialNoposition.id for each battery reading| Aspect | Behavior |
|---|---|
| Timestamp | All batteries share same deviceTime |
| GPS Data | Identical across all batteries (same vehicle) |
| Device Info | Same device ID, but different batterySerialNo |
| BMS Data | Independent per battery pack |
| Configuration | Description | Data Array Length |
|---|---|---|
| Single Battery | Standard EV/device | 1 |
| Dual Battery | Extended range vehicles | 2 |
| Triple Battery | Commercial/heavy vehicles | 3 |
| Swappable Batteries | Multiple slots | Variable (1-N) |
| Field | Type | Description |
|---|---|---|
| result | Boolean | Indicates if the request was successful |
| data | Array[String] | Array of JSON-encoded battery data strings (one per battery pack) |
| Field | Type | Description |
|---|---|---|
| position | Object | GPS and BMS data for this specific battery |
| device | Object | Device metadata (contains battery-specific attributes) |
| Field | Type | Unit | Description |
|---|---|---|---|
| id | Long | - | Position record ID (unique per battery reading) |
| deviceId | Integer | - | Device identifier (same for all batteries) |
| protocol | String | - | Communication protocol (e.g., "cbalin", "ctrackmate") |
| serverTime | String (ISO 8601) | - | Server timestamp |
| deviceTime | String (ISO 8601) | - | Device timestamp (synchronized across batteries) |
| fixTime | String (ISO 8601) | - | GPS fix timestamp |
| outdated | Boolean | - | Indicates if data is outdated |
| valid | Boolean | - | GPS data validity |
| Field | Type | Unit | Description |
|---|---|---|---|
| latitude | Double | degrees | Latitude coordinate (same for all batteries) |
| longitude | Double | degrees | Longitude coordinate (same for all batteries) |
| altitude | Double | meters | Altitude above sea level |
| speed | Double | km/h | Current speed (same for all batteries) |
| course | Double | degrees | Direction of movement (0-360°) |
| address | String | - | Reverse geocoded address |
| accuracy | Double | meters | GPS accuracy |
| network | Object/Null | - | Network cell information |
| geofenceIds | Array[Int]/Null | - | Active geofence IDs |
| Field | Type | Description |
|---|---|---|
| BMS | Object | Battery Management System data (unique per battery) |
| charge | Boolean | Charging status (per battery) |
| distance | Double | Trip distance (km) |
| totalDistance | Double | Odometer reading (km) |
| extVolt | Double | External voltage (V) |
| intVolt | Double | Internal voltage (V) |
| ign | Boolean | Ignition status |
| motion | Boolean | Motion detected |
| vDuration | Long | Vehicle duration (milliseconds) |
| vStatus | String | Vehicle status ("running", "stop", "idle") |
| armed | Boolean | (Optional) Security armed status |
| engHours | Long | (Optional) Engine hours (milliseconds) |
| in1 | Integer | (Optional) Digital input 1 |
The Battery Management System (BMS) object contains comprehensive battery health and performance metrics for each individual battery pack.
| Field | Type | Unit | Description |
|---|---|---|---|
| B1 | Double | V | Total battery voltage (per pack) |
| B2 | Double | A | Current (positive = charging, negative = discharging) |
| B3 | Double | % | State of Charge (SoC) per battery |
| B4 | Double | mV | Maximum cell voltage in this pack |
| B5 | Double | - | Cell number with maximum voltage |
| B6 | Double | mV | Minimum cell voltage in this pack |
| B7 | Double | - | Cell number with minimum voltage |
| B8 | Double | °C | Maximum temperature in this pack |
| B9 | Double | °C | Minimum temperature in this pack |
| Field | Type | Unit | Description |
|---|---|---|---|
| B10 | Double | - | Reserved parameter |
| B11 | Double | mAh | Residual capacity (per pack) |
| B12 | Double | - | Charge status flag |
| B13 | Double | - | Load status flag |
| B14 | Integer | cycles | Charge/discharge cycle count (per pack) |
| B15 | Integer | - | Number of battery cells in this pack |
| B16 | Integer | - | Number of temperature sensors in this pack |
| B17 | Double | kWh | Total energy charged (per pack) |
| B18 | Double | kWh | Total energy discharged (per pack) |
| B19 | Integer | - | BMS status/mode (0=Offline, 1=Init, 2=Normal, 3=Charging, 4=Idle) |
| Field | Type | Unit | Description |
|---|---|---|---|
| B20-B28 | Integer | - | Protocol-specific parameters |
| B29 | Double | % | State of Health (SoH) per pack |
| B30 | Double | Ah | Total battery capacity per pack |
| B31 | String | hex | Hex-encoded status data |
| B32 | String | hex | Hex-encoded extended data |
| BR1 | Double | - | Battery reserved parameter 1 |
| BR2 | Double | - | Battery reserved parameter 2 |
| BR3 | Double | - | Battery reserved parameter 3 |
| Field | Type | Unit | Description |
|---|---|---|---|
| CV | Array[String] | mV | Individual cell voltages for this pack (length = B15) |
| TM | Array[String] | °C | Individual temperature sensor readings for this pack (length = B16) |
Device metadata and configuration information. Contains battery-specific identification in attributes.
| Field | Type | Description |
|---|---|---|
| id | Integer | Device ID (same for all batteries) |
| name | String | Device name/identifier |
| uniqueId | String | IMEI or unique hardware ID |
| status | String | Connection status ("online", "offline") |
| lastUpdate | String (ISO 8601) | Last communication timestamp |
| positionId | Long | Latest position record ID (unique per battery) |
| groupId | Integer | Device group ID |
| calendarId | Integer | Calendar ID for scheduling |
| phone | String | Associated phone number |
| model | String | Device model |
| contact | String | Contact information |
| category | String | Device category |
| disabled | Boolean | Device enabled/disabled status |
| expirationTime | String/Null | Service expiration date |
| attributes | Object | Custom device attributes (includes battery identifiers) |
| Field | Type | Description |
|---|---|---|
| speedLimit | Double | Configured speed limit (km/h) |
| batteryCurrent | String | Battery current rating (e.g., "100A") |
| batterySerialNo | String | Battery serial number (unique per pack) |
| batteryVoltage | String | Battery voltage rating (e.g., "62V") |
| batterySlot | Integer | (Optional) Physical slot number |
| batteryPosition | String | (Optional) "front", "rear", "left", "right" |
{
"result": true,
"data": [
"{\"position\":{\"id\":3217805120,\"attributes\":{\"BMS\":{\"B1\":46.84,\"B2\":0,\"B3\":34,\"B4\":3611,\"B5\":2,\"B6\":3592,\"B7\":3,\"B8\":44.2,\"B9\":34.5,\"B14\":9,\"B15\":13,\"B16\":2,\"B29\":40,\"B30\":13.44,\"CV\":[\"3595\",\"3611\",\"3592\",\"3601\",\"3608\",\"3605\",\"3602\",\"3611\",\"3607\",\"3598\",\"3600\",\"3600\",\"3595\"],\"TM\":[\"44.2\",\"34.5\"]},\"charge\":true,\"ign\":true,\"motion\":true},\"deviceId\":20643,\"latitude\":12.90867,\"longitude\":77.60253,\"speed\":6.64},\"device\":{\"id\":20643,\"name\":\"ISN4850CKPEX16170073\",\"status\":\"online\",\"attributes\":{\"batterySerialNo\":\"1000314\"}}}"
]
}
{
"result": true,
"data": [
"{\"position\":{\"id\":3217805120,\"attributes\":{\"BMS\":{\"B1\":48.2,\"B2\":-5.3,\"B3\":75,\"B4\":3650,\"B5\":1,\"B6\":3620,\"B7\":8,\"B8\":38.5,\"B9\":32.1,\"B14\":45,\"B15\":13,\"B16\":2,\"B29\":85,\"B30\":15.0,\"CV\":[\"3650\",\"3640\",\"3645\",\"3635\",\"3642\",\"3638\",\"3641\",\"3620\",\"3639\",\"3643\",\"3637\",\"3644\",\"3641\"],\"TM\":[\"38.5\",\"32.1\"]},\"charge\":false,\"ign\":true,\"motion\":true},\"deviceId\":20643,\"deviceTime\":\"2025-12-15T10:43:22Z\",\"latitude\":12.90867,\"longitude\":77.60253,\"speed\":6.64},\"device\":{\"id\":20643,\"name\":\"EV-TRUCK-01\",\"status\":\"online\",\"attributes\":{\"batterySerialNo\":\"BAT-FRONT-001\",\"batteryPosition\":\"front\"}}}",
"{\"position\":{\"id\":3217805121,\"attributes\":{\"BMS\":{\"B1\":47.8,\"B2\":-5.1,\"B3\":72,\"B4\":3648,\"B5\":3,\"B6\":3615,\"B7\":11,\"B8\":40.2,\"B9\":33.5,\"B14\":47,\"B15\":13,\"B16\":2,\"B29\":82,\"B30\":15.0,\"CV\":[\"3640\",\"3645\",\"3648\",\"3635\",\"3638\",\"3642\",\"3639\",\"3641\",\"3637\",\"3644\",\"3615\",\"3643\",\"3640\"],\"TM\":[\"40.2\",\"33.5\"]},\"charge\":false,\"ign\":true,\"motion\":true},\"deviceId\":20643,\"deviceTime\":\"2025-12-15T10:43:22Z\",\"latitude\":12.90867,\"longitude\":77.60253,\"speed\":6.64},\"device\":{\"id\":20643,\"name\":\"EV-TRUCK-01\",\"status\":\"online\",\"attributes\":{\"batterySerialNo\":\"BAT-REAR-002\",\"batteryPosition\":\"rear\"}}}"
]
}
{
"result": true,
"data": [
"{\"position\":{\"attributes\":{\"BMS\":{\"B1\":52.1,\"B2\":0,\"B3\":95,\"B19\":3}},\"deviceTime\":\"2025-12-15T10:43:22Z\"},\"device\":{\"attributes\":{\"batterySerialNo\":\"SWAP-SLOT1-789\",\"batterySlot\":1}}}",
"{\"position\":{\"attributes\":{\"BMS\":{\"B1\":51.8,\"B2\":0,\"B3\":88,\"B19\":2}},\"deviceTime\":\"2025-12-15T10:43:22Z\"},\"device\":{\"attributes\":{\"batterySerialNo\":\"SWAP-SLOT2-456\",\"batterySlot\":2}}}",
"{\"position\":{\"attributes\":{\"BMS\":{\"B1\":0,\"B2\":0,\"B3\":0,\"B19\":0}},\"deviceTime\":\"2025-12-15T10:43:22Z\"},\"device\":{\"attributes\":{\"batterySerialNo\":\"\",\"batterySlot\":3}}}"
]
}
{
"result": true,
"data": [
"{\"position\":{\"id\":0,\"attributes\":{\"BMS\":{\"B1\":0,\"B2\":0,\"B3\":0,\"B4\":0,\"B5\":0,\"B6\":0,\"B7\":0,\"B8\":0,\"B9\":0,\"B10\":0,\"B11\":0,\"B12\":0,\"B13\":0,\"B14\":0,\"B15\":0,\"B16\":0,\"B17\":0,\"B18\":0,\"B19\":0,\"BR1\":0,\"BR2\":0,\"BR3\":0,\"CV\":[\"0\"],\"TM\":[\"0\"]},\"charge\":false,\"distance\":0,\"extVolt\":0,\"ign\":false,\"intVolt\":0,\"motion\":false,\"totalDistance\":51.45586682025701,\"vDuration\":25900411288,\"vStatus\":\"stop\"},\"deviceId\":300,\"protocol\":\"cbalin\",\"serverTime\":\"2025-04-29T05:38:21.411Z\",\"deviceTime\":\"2025-04-29T05:38:21.411Z\",\"fixTime\":\"2025-04-29T05:38:21.411Z\",\"outdated\":true,\"valid\":true,\"latitude\":28.601419,\"longitude\":77.431877,\"altitude\":0,\"speed\":0,\"course\":143.48,\"address\":\"\",\"accuracy\":0,\"network\":null,\"geofenceIds\":null},\"device\":{\"id\":300,\"attributes\":{\"speedLimit\":64.79},\"groupId\":0,\"calendarId\":0,\"name\":\"BMS-DEMO1\",\"uniqueId\":\"869630057868766\",\"status\":\"online\",\"lastUpdate\":\"2025-04-29T05:38:21.411Z\",\"positionId\":297552643,\"phone\":\"\",\"model\":\"\",\"contact\":\"\",\"category\":\"\",\"disabled\":false,\"expirationTime\":null}}"
]
}
These values can be derived from the BMS data:
| Metric | Formula | Unit | Description |
|---|---|---|---|
| Power | B1 × B2 | W | Instantaneous power |
| Energy | (B1 × B2 × time) / 3600 | Wh | Energy consumed/charged |
| Cell Voltage Delta | B4 - B6 | mV | Cell imbalance indicator |
| Average Cell Voltage | sum(CV) / B15 | mV | Mean cell voltage |
| Average Temperature | sum(TM) / B16 | °C | Mean temperature |
| Residual Capacity (Ah) | B11 / 1000 | Ah | Remaining capacity in Ah |
| Charge/Discharge Rate | B2 / B30 | C | C-rate (if B30 available) |
When working with multiple batteries, you may need to aggregate data:
| Metric | Calculation | Description |
|---|---|---|
| Total Voltage | Sum of all B1 values | Only if batteries are in series |
| Total Current | Sum of all B2 values | If batteries are in parallel |
| Average SoC | Mean of all B3 values | Overall system charge level |
| System Capacity | Sum of all B30 values | Total energy storage |
| Total Power | Sum of (B1 × B2) for each | Total system power |
| Min Cell Voltage | Minimum of all B6 values | Weakest cell in system |
| Max Temperature | Maximum of all B8 values | Hottest point in system |
| Total Cycles | Mean or Max of B14 | Depends on usage pattern |
| System SoH | Weighted avg of B29 | By capacity or simple mean |
function aggregateBatteries(parsedData) {
const batteries = parsedData.map(item => item.position.attributes.BMS);
return {
totalVoltage: batteries.reduce((sum, b) => sum + b.B1, 0),
totalCurrent: batteries.reduce((sum, b) => sum + b.B2, 0),
averageSoC: batteries.reduce((sum, b) => sum + b.B3, 0) / batteries.length,
systemCapacity: batteries.reduce((sum, b) => sum + (b.B30 || 0), 0),
totalPower: batteries.reduce((sum, b) => sum + (b.B1 * b.B2), 0),
minCellVoltage: Math.min(...batteries.map(b => b.B6)),
maxTemperature: Math.max(...batteries.map(b => b.B8)),
batteryCount: batteries.length,
onlineBatteries: batteries.filter(b => b.B19 > 0).length
};
}
| Value | Status | Description |
|---|---|---|
| 0 | Offline | No BMS communication |
| 1 | Initializing | BMS starting up |
| 2 | Normal | Normal operation |
| 3 | Charging | Battery charging |
| 4 | Idle | Standby mode |
| Value | Description |
|---|---|
| "running" | Vehicle in motion or engine on |
| "stop" | Vehicle stopped, ignition off |
| "idle" | Vehicle stopped, ignition on |
| Value | Description |
|---|---|
| "online" | Device connected and transmitting |
| "offline" | Device not connected |
| "unknown" | Connection status unknown |
| Condition | Threshold | Action |
|---|---|---|
| Critical Low | B1 < 40V (for 48V system) | Alert + Stop discharge |
| Warning Low | B1 < 44V | Warning notification |
| Normal | 44V - 54V | Normal operation |
| Warning High | B1 > 58V | Warning notification |
| Critical High | B1 > 60V | Alert + Stop charge |
| Condition | Delta (mV) | Action |
|---|---|---|
| Excellent | < 20 | No action |
| Good | 20 - 50 | Monitor |
| Warning | 50 - 100 | Balance cells |
| Critical | > 100 | Alert + Balance required |
| Condition | Threshold | Action |
|---|---|---|
| Critical Low | < 0°C | Alert + Reduce power |
| Warning Low | < 10°C | Monitor closely |
| Normal | 10°C - 45°C | Normal operation |
| Warning High | > 45°C | Reduce load |
| Critical High | > 60°C | Alert + Emergency stop |
| Level | SoC % | Action |
|---|---|---|
| Critical | < 5% | Emergency notification |
| Low | 5% - 20% | Low battery warning |
| Normal | 20% - 80% | Normal operation |
| High | 80% - 95% | Optimal for longevity |
| Full | > 95% | Stop charging |
| Condition | SoH % | Description |
|---|---|---|
| Excellent | > 80% | Battery in good condition |
| Good | 60% - 80% | Normal degradation |
| Fair | 40% - 60% | Consider replacement planning |
| Poor | < 40% | Replacement recommended |
Apply these to each battery independently:
Cell Count Consistency
CV.length should equal B15TM.length should equal B16Voltage Consistency
B4 (max) should be ≥ all values in CVB6 (min) should be ≤ all values in CVB1 × 1000Temperature Consistency
B8 (max) should be ≥ all values in TMB9 (min) should be ≤ all values in TMRange Validations
B3 (SoC) should be 0-100B29 (SoH) should be 0-100For multi-battery systems:
| Check | Validation | Alert Condition |
|---|---|---|
| Voltage Mismatch | Compare B1 across batteries | Difference > 5V |
| SoC Imbalance | Compare B3 across batteries | Difference > 15% |
| Temperature Variance | Compare B8 across batteries | Difference > 10°C |
| Sync Check | Compare deviceTime | Timestamps differ > 5s |
| Battery Count | Check data.length | Changed from last reading |
| Missing Battery | Check B19 status | Any battery B19 = 0 |
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid device ID or parameters |
| 401 | Unauthorized - Invalid or expired token |
| 403 | Forbidden - No access to this device |
| 404 | Not Found - Device does not exist |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
{
"result": false,
"error": {
"code": "ERROR_CODE",
"message": "Human readable error message"
}
}
| Code | Description | Solution |
|---|---|---|
| INVALID_TOKEN | JWT token expired or invalid | Refresh authentication token |
| DEVICE_NOT_FOUND | Device ID does not exist | Verify device ID |
| NO_PERMISSION | User lacks access to device | Check user permissions |
| DEVICE_OFFLINE | Device not communicating | Check device connectivity |
| INVALID_BMS_DATA | BMS data corrupted or incomplete | Wait for next update |
| Limit Type | Rate | Period |
|---|---|---|
| Per User | 100 requests | 1 minute |
| Per Device | 60 requests | 1 minute |
Rate Limit Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1735132800
| View Type | Recommendation |
|---|---|
| Overview | Show aggregated metrics + battery count |
| Individual | Separate cards/tabs for each battery |
| Comparison | Side-by-side battery metrics |
| Alerts | Flag individual battery issues |
| History | Track per-battery trends over time |
async function getBmsData(deviceId, token) {
const response = await fetch(
`https://api.baliniot.in/api/BMS/Dashboard/${deviceId}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
}
);
const data = await response.json();
// Parse the data strings
return data.data.map(item => JSON.parse(item));
}
async function getBmsDataMultiBattery(deviceId, token) {
const response = await fetch(
`https://api.baliniot.in/api/BMS/Dashboard/${deviceId}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
}
);
const data = await response.json();
// Parse all battery data
const batteries = data.data.map(item => JSON.parse(item));
return {
batteryCount: batteries.length,
batteries: batteries.map((battery, index) => ({
index,
serialNo: battery.device.attributes.batterySerialNo,
bms: battery.position.attributes.BMS,
gps: {
lat: battery.position.latitude,
lon: battery.position.longitude,
speed: battery.position.speed
}
})),
device: batteries[0].device // Device info is same for all
};
}
import requests
import json
def get_bms_data(device_id, token):
url = f"https://api.baliniot.in/api/BMS/Dashboard/{device_id}"
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json"
}
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
return [json.loads(item) for item in data["data"]]
def get_multi_battery_data(device_id, token):
url = f"https://api.baliniot.in/api/BMS/Dashboard/{device_id}"
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json"
}
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
batteries = [json.loads(item) for item in data["data"]]
return {
"battery_count": len(batteries),
"batteries": [
{
"serial_no": b["device"]["attributes"].get("batterySerialNo"),
"bms": b["position"]["attributes"]["BMS"],
"voltage": b["position"]["attributes"]["BMS"]["B1"],
"soc": b["position"]["attributes"]["BMS"]["B3"],
"online": b["position"]["attributes"]["BMS"]["B19"] > 0
}
for b in batteries
],
"system_voltage": sum(b["position"]["attributes"]["BMS"]["B1"] for b in batteries),
"average_soc": sum(b["position"]["attributes"]["BMS"]["B3"] for b in batteries) / len(batteries)
}
// Main Response
data class BmsDashboardResponse(
val result: Boolean,
val data: List<String> // Array of JSON strings
)
// Parsed Device Data
data class BmsDeviceData(
val position: Position,
val device: Device
)
// Position Data
data class Position(
val id: Long,
val attributes: PositionAttributes,
val deviceId: Int,
val protocol: String,
val serverTime: String,
val deviceTime: String,
val fixTime: String,
val outdated: Boolean,
val valid: Boolean,
val latitude: Double,
val longitude: Double,
val altitude: Double,
val speed: Double,
val course: Double,
val address: String,
val accuracy: Double,
val network: String?,
val geofenceIds: List<Int>?
)
data class PositionAttributes(
val BMS: BmsData,
val charge: Boolean,
val distance: Double,
val extVolt: Double,
val ign: Boolean,
val intVolt: Double,
val motion: Boolean,
val totalDistance: Double,
val vDuration: Long,
val vStatus: String,
val armed: Boolean? = null,
val engHours: Long? = null,
val in1: Int? = null
)
// Complete BMS Data Class
data class BmsData(
val B1: Double, // Total Voltage (V)
val B2: Double, // Current (A)
val B3: Double, // State of Charge (SoC) %
val B4: Double, // Max Cell Voltage (mV)
val B5: Double, // Max Voltage Cell No
val B6: Double, // Min Cell Voltage (mV)
val B7: Double, // Min Voltage Cell No
val B8: Double, // Max Temperature (°C)
val B9: Double, // Min Temperature (°C)
val B10: Double, // Additional parameter
val B11: Double, // Residual Capacity (mAh)
val B12: Double, // Charge Status
val B13: Double, // Load Status
val B14: Int, // BMS Cycle Count
val B15: Int, // Number of Cells
val B16: Int, // Temperature Sensor Count
val B17: Double, // kWh Charging
val B18: Double, // kWh Discharging
val B19: Int, // BMS Status/Mode
val B20: Int? = null,
val B21: Int? = null,
val B22: Int? = null,
val B23: Int? = null,
val B25: Int? = null,
val B27: Int? = null,
val B28: Int? = null,
val B29: Double? = null, // State of Health (SoH) %
val B30: Double? = null, // Capacity (Ah)
val B31: String? = null, // Hex data
val B32: String? = null, // Hex data
val BR1: Double, // Battery Reserved param 1
val BR2: Double, // Battery Reserved param 2
val BR3: Double, // Battery Reserved param 3
val CV: List<String>, // Cell Voltages (mV)
val TM: List<String> // Temperature readings (°C)
)
// Device Info
data class Device(
val id: Int,
val attributes: DeviceAttributes,
val groupId: Int,
val calendarId: Int,
val name: String,
val uniqueId: String,
val status: String,
val lastUpdate: String,
val positionId: Long,
val phone: String,
val model: String,
val contact: String,
val category: String,
val disabled: Boolean,
val expirationTime: String?
)
data class DeviceAttributes(
val speedLimit: Double? = null,
val batteryCurrent: String? = null,
val batterySerialNo: String? = null,
val batteryVoltage: String? = null,
val batterySlot: Int? = null,
val batteryPosition: String? = null
)
import com.google.gson.Gson
class BmsDataParser {
private val gson = Gson()
fun parseResponse(jsonResponse: String): List<BmsDeviceData> {
// Parse main response
val response = gson.fromJson(jsonResponse, BmsDashboardResponse::class.java)
// Parse each data string
return response.data.map { dataString ->
gson.fromJson(dataString, BmsDeviceData::class.java)
}
}
}
// Usage
val parser = BmsDataParser()
val devices = parser.parseResponse(responseJson)
devices.forEach { deviceData ->
val bms = deviceData.position.attributes.BMS
val device = deviceData.device
println("Device: ${device.name}")
println("Voltage: ${bms.B1}V")
println("Current: ${bms.B2}A")
println("SoC: ${bms.B3}%")
}
data class MultiBatteryResponse(
val batteryCount: Int,
val batteries: List<BatteryInfo>,
val systemMetrics: SystemMetrics
)
data class BatteryInfo(
val index: Int,
val serialNo: String,
val bmsData: BmsData,
val isOnline: Boolean
)
data class SystemMetrics(
val totalVoltage: Double,
val totalCurrent: Double,
val averageSoC: Double,
val systemCapacity: Double,
val totalPower: Double
)
suspend fun getMultiBatteryData(deviceId: Int, token: String): MultiBatteryResponse {
val response = client.get("https://api.baliniot.in/api/BMS/Dashboard/$deviceId") {
header("Authorization", "Bearer $token")
}
val data = response.body<BmsDashboardResponse>()
val batteries = data.data.map { Json.decodeFromString<BmsDeviceData>(it) }
val batteryInfoList = batteries.mapIndexed { index, battery ->
BatteryInfo(
index = index,
serialNo = battery.device.attributes.batterySerialNo ?: "Unknown",
bmsData = battery.position.attributes.BMS,
isOnline = battery.position.attributes.BMS.B19 > 0
)
}
val systemMetrics = calculateSystemMetrics(batteries)
return MultiBatteryResponse(
batteryCount = batteries.size,
batteries = batteryInfoList,
systemMetrics = systemMetrics
)
}
fun calculateSystemMetrics(batteries: List<BmsDeviceData>): SystemMetrics {
val bmsDataList = batteries.map { it.position.attributes.BMS }
return SystemMetrics(
totalVoltage = bmsDataList.sumOf { it.B1 },
totalCurrent = bmsDataList.sumOf { it.B2 },
averageSoC = bmsDataList.map { it.B3 }.average(),
systemCapacity = bmsDataList.sumOf { it.B30 ?: 0.0 },
totalPower = bmsDataList.sumOf { it.B1 * it.B2 }
)
}
// Extension functions for BmsData
val BmsData.isOnline: Boolean
get() = B1 > 0 && B19 > 0
val BmsData.power: Double
get() = B1 * B2
val BmsData.isCharging: Boolean
get() = B2 > 0
val BmsData.cellVoltageDelta: Double
get() = if (B4 > 0) B4 - B6 else 0.0
val BmsData.cellVoltagesDouble: List<Double>
get() = CV.mapNotNull { it.toDoubleOrNull() }
val BmsData.temperaturesDouble: List<Double>
get() = TM.mapNotNull { it.toDoubleOrNull() }
val BmsData.avgCellVoltage: Double
get() = if (cellVoltagesDouble.isNotEmpty())
cellVoltagesDouble.average()
else 0.0
val BmsData.avgTemperature: Double
get() = if (temperaturesDouble.isNotEmpty())
temperaturesDouble.average()
else 0.0
val BmsData.residualCapacityAh: Double
get() = B11 / 1000.0 // Convert mAh to Ah
val BmsData.healthStatus: String
get() = when {
B29 ?: 0.0 > 80 -> "Excellent"
B29 ?: 0.0 > 60 -> "Good"
B29 ?: 0.0 > 40 -> "Fair"
else -> "Poor"
}
val BmsData.statusDescription: String
get() = when (B19) {
0 -> "Offline"
1 -> "Initializing"
2 -> "Normal"
3 -> "Charging"
4 -> "Idle"
else -> "Unknown"
}
val BmsData.isCellBalanced: Boolean
get() = cellVoltageDelta <= 50 // Delta < 50mV
val BmsData.temperatureStatus: String
get() = when {
B8 > 60 -> "Critical High"
B8 > 45 -> "Warning High"
B9 < 0 -> "Critical Low"
B9 < 10 -> "Warning Low"
else -> "Normal"
}
<?php
function getBmsData($deviceId, $token) {
$url = "https://api.baliniot.in/api/BMS/Dashboard/{$deviceId}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$token}",
"Accept: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
// Parse each battery data string
$batteries = array_map(function($item) {
return json_decode($item, true);
}, $data['data']);
return $batteries;
}
// Multi-battery aggregation
function aggregateMultiBatteryData($batteries) {
$batteryCount = count($batteries);
$totalVoltage = 0;
$totalCurrent = 0;
$totalSoC = 0;
foreach ($batteries as $battery) {
$bms = $battery['position']['attributes']['BMS'];
$totalVoltage += $bms['B1'];
$totalCurrent += $bms['B2'];
$totalSoC += $bms['B3'];
}
return [
'battery_count' => $batteryCount,
'total_voltage' => $totalVoltage,
'total_current' => $totalCurrent,
'average_soc' => $totalSoC / $batteryCount,
'total_power' => $totalVoltage * $totalCurrent
];
}
?>
| Version | Date | Changes |
|---|---|---|
| 1.1 | 2025-12-15 | Added multi-battery support documentation |
| 1.0 | 2025-12-15 | Initial API documentation |
For API support and questions:
Voltage & Current:
State of Charge:
Temperature:
Cell Configuration:
Status & Cycles:
Energy:
// Power (W)
power = B1 * B2
// Energy (Wh) - over time period in seconds
energy = (B1 * B2 * seconds) / 3600
// C-rate
cRate = B2 / B30
// Cell imbalance (mV)
imbalance = B4 - B6
// Remaining capacity (Ah)
remainingAh = B11 / 1000
// Remaining energy (Wh)
remainingWh = (B11 / 1000) * B1
// Time to empty (hours) - if discharging
timeToEmpty = (B11 / 1000) / Math.abs(B2)
// Time to full (hours) - if charging
timeToFull = ((B30 - (B11/1000)) / B2)
© 2025 Baliniot. All rights reserved.