Protocol Type: Binary, Master-Slave
Transport: Bluetooth Low Energy (BLE)
This protocol enables communication between a client device and a Battery Management System (BMS) over Bluetooth Low Energy. It supports real-time monitoring of battery pack parameters including voltage, current, temperature, and protection states.
| Component | UUID | Properties |
|---|---|---|
| Service | 0000ff00-0000-1000-8000-00805f9b34fb |
Primary Service |
| R/W Characteristic | 0000ff02-0000-1000-8000-00805f9b34fb |
Read, Write, Notify |
βββββββββββ¬ββββββββββ¬βββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββ¬ββββββββββββββ¬ββββββββββ β Header β Command β Mode β Length β Data β Checksum_H β Checksum_L β Tail β βββββββββββΌββββββββββΌβββββββΌβββββββββΌβββββββββββΌββββββββββββββΌββββββββββββββΌββββββββββ€ β 0xDD β 1 byte β0xA5 β1 byte β N bytes β 1 byte β 1 byte β 0x77 β βββββββββββ΄ββββββββββ΄βββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββ΄ββββββββββββββ΄ββββββββββ Byte 0 Byte 1 Byte 2 Byte 3 Bytes 4-N Byte N+4 Byte N+5 Byte N+6 Total Length = Data Length + 7 bytes
βββββββββββ¬ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββ¬ββββββββββββββ¬ββββββββββ β Header βResponse β Status β Length β Data β Checksum_H β Checksum_L β Tail β βββββββββββΌββββββββββΌβββββββββΌβββββββββΌβββββββββββΌββββββββββββββΌββββββββββββββΌββββββββββ€ β 0xDD β 1 byte β 1 byte β1 byte β N bytes β 1 byte β 1 byte β 0x77 β βββββββββββ΄ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββ΄ββββββββββββββ΄ββββββββββ Byte 0 Byte 1 Byte 2 Byte 3 Bytes 4-N Byte N+4 Byte N+5 Byte N+6
| Field | Size | Description |
|---|---|---|
| Header | 1 byte | Fixed value 0xDD - packet start marker |
| Command | 1 byte | Command identifier |
| Mode | 1 byte | 0xA5 for read operations |
| Status | 1 byte | Response status code (0x00 = success) |
| Length | 1 byte | Number of data bytes (0-255) |
| Data | N bytes | Command-specific payload |
| Checksum_H | 1 byte | High byte of 16-bit CRC |
| Checksum_L | 1 byte | Low byte of 16-bit CRC |
| Tail | 1 byte | Fixed value 0x77 - packet end marker |
Client BMS Device
| |
|-- Write Request Packet ------------------>|
| |
| |-- Process Command
| |
|<-- Notify Response Packet ----------------|
| |
| Parameter | Value | Description |
|---|---|---|
| Command Timeout | 2000ms | Maximum wait time for response |
| Retry Interval | 50ms | Polling interval for command queue |
| Read Timeout | 5000ms | Maximum read operation duration |
| Recording Interval | 1000ms | Data collection frequency |
Request: DD 03 A5 00 ...
| Offset | Size | Field | Type | Unit |
|---|---|---|---|---|
| 0-1 | 2 | Total Voltage | uint16 | 0.1V |
| 2-3 | 2 | Current | int16 | 0.1A (signed) |
| 4-5 | 2 | Remaining Capacity | uint16 | 0.01Ah |
| 6 | 1 | Temperature Count (N) | uint8 | |
| 7-N | N | Temperature Array | int8[] | 1Β°C (signed, offset -40) |
| N+1 | 1 | RSOC | uint8 | 1% |
| N+2 | 1 | MOS Status | uint8 | Bit 0: Charge, Bit 1: Discharge |
| N+3-4 | 2 | Protection State | uint16 | Bit flags |
Request: DD 04 A5 00 ...
| Offset | Size | Field | Type | Unit |
|---|---|---|---|---|
| 0 | 1 | Cell Count (N) | uint8 | |
| 1-2N | 2N | Cell Voltage Array | uint16[] | 1mV per cell |
All multi-byte integers use Big-Endian (most significant byte first) encoding.
def calculate_checksum(command: int, data: bytes) -> tuple[int, int]:
"""
Calculate 16-bit checksum
Returns: (high_byte, low_byte)
"""
checksum = command
for byte in data:
checksum += byte
# Apply modulo and split into bytes
checksum = checksum % 65536
high_byte = (checksum >> 8) & 0xFF
low_byte = checksum & 0xFF
return (high_byte, low_byte)
| Code | Name | Description |
|---|---|---|
| 0x00 | SUCCESS | Command executed successfully |
| 0xFF | CHECKSUM_ERROR | Checksum validation failed |
| 0xFE | TIMEOUT | No response within timeout |
| 0xFD | INVALID_COMMAND | Unknown command byte |
When RSOC is between 45-90% during discharge transition:
For each cell i:
R[i] = (V_pre[i] - V_post[i]) / |I_discharge|
Where:
V_pre[i] = Cell voltage before discharge (PRE_DISCHARGE state)
V_post[i] = Cell voltage after discharge starts (DISCHARGE state)
I_discharge = Discharge current
class BMSProtocol:
HEADER = 0xDD
TAIL = 0x77
MODE_READ = 0xA5
def parse_base_info(self, data: bytes) -> dict:
"""Parse base information response"""
voltage = int.from_bytes(data[0:2], 'big') / 10.0 # 0.1V units
current = int.from_bytes(data[2:4], 'big', signed=True) / 10.0 # 0.1A
capacity = int.from_bytes(data[4:6], 'big') / 100.0 # 0.01Ah
temp_count = data[6]
temperatures = []
for i in range(temp_count):
temp_raw = data[7 + i]
temperatures.append(temp_raw - 40) # Offset by 40Β°C
return {
'voltage': voltage,
'current': current,
'capacity': capacity,
'temperatures': temperatures
}