Skip to content

Commit

Permalink
present individual packs
Browse files Browse the repository at this point in the history
  • Loading branch information
patman15 committed Dec 17, 2024
1 parent 067c94f commit 415ac06
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 62 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This integration allows to monitor Bluetooth Low Energy (BLE) battery management
- JK BMS, Jikong, (HW version >=11 required)
- Offgridtec LiFePo4 Smart Pro: type A & B (show up as `SmartBat-A`… or `SmartBat-B`…)
- LiTime, Redodo batteries
- Seplos v2 (show up as `BP00`…)
- Seplos v2 (show up as `BP0`?)
- Seplos v3 (show up as `SP0`… or `SP1`…)

New device types can be easily added via the plugin architecture of this integration. See the [contribution guidelines](CONTRIBUTING.md) for details.
Expand Down
2 changes: 1 addition & 1 deletion custom_components/bms_ble/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"manufacturer_id": 65535
},
{
"local_name": "BP00",
"local_name": "BP0?",
"service_uuid": "0000ff00-0000-1000-8000-00805f9b34fb"
}
],
Expand Down
2 changes: 2 additions & 0 deletions custom_components/bms_ble/plugins/basebms.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ def crc_modbus(data: bytearray) -> int:
crc = (crc >> 1) ^ 0xA001 if crc % 2 else (crc >> 1)
return crc & 0xFFFF


def crc_xmodem(data: bytearray) -> int:
"""Calculate CRC-16-CCITT XMODEM."""
crc: int = 0x0000
Expand All @@ -247,6 +248,7 @@ def crc_xmodem(data: bytearray) -> int:
crc = (crc << 1) ^ 0x1021 if (crc & 0x8000) else (crc << 1)
return crc & 0xFFFF


def crc_sum(frame: bytes) -> int:
"""Calculate frame CRC."""
return sum(frame) & 0xFF
41 changes: 13 additions & 28 deletions custom_components/bms_ble/plugins/seplos_v2_bms.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ class BMS(BaseBMS):
(KEY_PACK_COUNT, 0x51, 42, 1, False, lambda x: min(x, BMS._MAX_SUBS)),
(KEY_TEMP_SENS, 0x62, 14, 1, False, lambda x: x),
] # Protocol Seplos V2 (parallel data 0x62, device manufacturer info 0x51)
_CMDS: Final[list[int]] = list({field[1] for field in _FIELDS})
_CMDS: Final[list[tuple[int, bytes]]] = [
*list({(field[1], b"") for field in _FIELDS}),
(0x61, b"\x00"),
]

def __init__(self, ble_device: BLEDevice, reconnect: bool = False) -> None:
"""Initialize BMS."""
Expand All @@ -68,7 +71,7 @@ def matcher_dict_list() -> list[dict[str, Any]]:
"""Provide BluetoothMatcher definition."""
return [
{
"local_name": "BP00",
"local_name": "BP0?",
"service_uuid": BMS.uuid_services()[0],
"connectable": True,
}
Expand Down Expand Up @@ -97,9 +100,10 @@ def uuid_tx() -> str:
@staticmethod
def _calc_values() -> set[str]:
return {
ATTR_POWER,
ATTR_BATTERY_CHARGING,
ATTR_CYCLE_CAP,
ATTR_DELTA_VOLTAGE,
ATTR_POWER,
ATTR_RUNTIME,
} # calculate further values from BMS provided set ones

Expand Down Expand Up @@ -184,13 +188,11 @@ def _decode_data(data: dict[int, bytearray]) -> dict[str, int | float]:
}

@staticmethod
def _cell_voltages(data: bytearray, offset: int = 0) -> dict[str, float]:
def _cell_voltages(data: bytearray) -> dict[str, float]:
return {
f"{KEY_CELL_VOLTAGE}{idx+offset}": float(
f"{KEY_CELL_VOLTAGE}{idx}": float(
int.from_bytes(
data[10 + idx * 2 : 10 + idx * 2 + 2],
byteorder="big",
signed=False,
data[10 + idx * 2 : 10 + idx * 2 + 2], byteorder="big", signed=False
)
)
/ 1000
Expand All @@ -200,29 +202,12 @@ def _cell_voltages(data: bytearray, offset: int = 0) -> dict[str, float]:
async def _async_update(self) -> BMSsample:
"""Update battery status information."""

for cmd in BMS._CMDS:
await self._client.write_gatt_char(BMS.uuid_tx(), data=BMS._cmd(cmd))
for cmd, data in BMS._CMDS:
await self._client.write_gatt_char(BMS.uuid_tx(), data=BMS._cmd(cmd, data=bytearray(data)))
await asyncio.wait_for(self._wait_event(), timeout=BAT_TIMEOUT)

result: BMSsample = BMS._decode_data(self._data_final)

total_cells: int = 0
for pack in range(int(result.get(KEY_PACK_COUNT, 0) + 1)):
await self._client.write_gatt_char(
BMS.uuid_tx(), data=BMS._cmd(0x61, address=pack, data=bytearray(1))
)
await asyncio.wait_for(self._wait_event(), timeout=BAT_TIMEOUT)
pack_cells: dict[str, float] = BMS._cell_voltages(
self._data_final[0x61], total_cells
)
result |= pack_cells
result |= {
ATTR_DELTA_VOLTAGE: max(
float(result.get(ATTR_DELTA_VOLTAGE, 0)),
round(max(pack_cells.values()) - min(pack_cells.values()), 3),
)
}
total_cells += self._data_final[0x61][9]
result |= BMS._cell_voltages(self._data_final[0x61])

self._data_final.clear()

Expand Down
32 changes: 0 additions & 32 deletions tests/test_seplos_v2_bms.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,38 +125,6 @@ async def test_update(monkeypatch, reconnect_fixture) -> None:
"cell#13": 3.312,
"cell#14": 3.313,
"cell#15": 3.313,
"cell#16": 3.312,
"cell#17": 3.313,
"cell#18": 3.313,
"cell#19": 3.313,
"cell#20": 3.313,
"cell#21": 3.312,
"cell#22": 3.313,
"cell#23": 3.315,
"cell#24": 3.311,
"cell#25": 3.312,
"cell#26": 3.313,
"cell#27": 3.313,
"cell#28": 3.313,
"cell#29": 3.312,
"cell#30": 3.313,
"cell#31": 3.313,
"cell#32": 3.312,
"cell#33": 3.313,
"cell#34": 3.313,
"cell#35": 3.313,
"cell#36": 3.313,
"cell#37": 3.312,
"cell#38": 3.313,
"cell#39": 3.315,
"cell#40": 3.311,
"cell#41": 3.312,
"cell#42": 3.313,
"cell#43": 3.313,
"cell#44": 3.313,
"cell#45": 3.312,
"cell#46": 3.313,
"cell#47": 3.313,
"delta_voltage": 0.004,
"pack_count": 2,
}
Expand Down

0 comments on commit 415ac06

Please sign in to comment.