Improve Berger BLE telemetry and controls
This commit is contained in:
@@ -1,6 +1,22 @@
|
||||
import unittest
|
||||
|
||||
from berger_gui import DeviceState, berger_match_reason, decode_response, read_frame, split_frames, write_frame
|
||||
from berger_gui import (
|
||||
DeviceState,
|
||||
berger_match_reason,
|
||||
cell_statistics,
|
||||
decode_response,
|
||||
mos_mode,
|
||||
read_frame,
|
||||
split_frames,
|
||||
validate_frame,
|
||||
write_frame,
|
||||
)
|
||||
|
||||
|
||||
def response_frame(command, payload):
|
||||
body = bytes([0xDD, command, 0x00, len(payload), *payload])
|
||||
check = (-sum(body[2:])) & 0xFFFF
|
||||
return body + check.to_bytes(2, "big") + b"\x77"
|
||||
|
||||
|
||||
class BergerParserTest(unittest.TestCase):
|
||||
@@ -11,6 +27,12 @@ class BergerParserTest(unittest.TestCase):
|
||||
def test_write_switch_checksum(self):
|
||||
self.assertEqual(write_frame(0xE1, b"\x00\x00").hex().upper(), "DD5AE1020000FF1D77")
|
||||
|
||||
def test_mos_modes(self):
|
||||
self.assertEqual(mos_mode(True, True), 0)
|
||||
self.assertEqual(mos_mode(False, True), 1)
|
||||
self.assertEqual(mos_mode(True, False), 2)
|
||||
self.assertEqual(mos_mode(False, False), 3)
|
||||
|
||||
def test_decode_base_data(self):
|
||||
payload = bytearray(27 + 4)
|
||||
payload[0:2] = (1328).to_bytes(2, "big")
|
||||
@@ -26,10 +48,7 @@ class BergerParserTest(unittest.TestCase):
|
||||
payload[22] = 2
|
||||
payload[23:25] = (2981).to_bytes(2, "big")
|
||||
payload[25:27] = (2991).to_bytes(2, "big")
|
||||
body = bytes([0xDD, 0x03, 0x00, len(payload), *payload])
|
||||
total = sum(body[1:]) & 0xFFFF
|
||||
check = ((total ^ 0xFFFF) + 1) & 0xFFFF
|
||||
frame = body + check.to_bytes(2, "big") + b"\x77"
|
||||
frame = response_frame(0x03, payload)
|
||||
|
||||
buffer = bytearray(b"\x00" + frame + frame)
|
||||
frames = split_frames(buffer)
|
||||
@@ -52,14 +71,47 @@ class BergerParserTest(unittest.TestCase):
|
||||
|
||||
def test_decode_cell_voltages(self):
|
||||
payload = b"".join(v.to_bytes(2, "big") for v in [3306, 3312, 3308, 3311])
|
||||
body = bytes([0xDD, 0x04, 0x00, len(payload), *payload])
|
||||
total = sum(body[1:]) & 0xFFFF
|
||||
check = ((total ^ 0xFFFF) + 1) & 0xFFFF
|
||||
frame = body + check.to_bytes(2, "big") + b"\x77"
|
||||
frame = response_frame(0x04, payload)
|
||||
state = DeviceState()
|
||||
decode_response(frame, state)
|
||||
self.assertEqual(state.telemetry.cells, [3.306, 3.312, 3.308, 3.311])
|
||||
|
||||
def test_captured_fragmented_base_data(self):
|
||||
chunks = [
|
||||
bytes.fromhex("DD030026053400005F8C75300000348900000000"),
|
||||
bytes.fromhex("000063520304030BB70BA60BAA00000075305F8C"),
|
||||
bytes.fromhex("0000F8DD77"),
|
||||
]
|
||||
buffer = bytearray()
|
||||
frames = []
|
||||
for chunk in chunks:
|
||||
buffer.extend(chunk)
|
||||
frames.extend(split_frames(buffer))
|
||||
|
||||
self.assertEqual(len(frames), 1)
|
||||
self.assertTrue(validate_frame(frames[0]))
|
||||
state = DeviceState()
|
||||
decode_response(frames[0], state)
|
||||
self.assertEqual(state.telemetry.voltage, 13.32)
|
||||
self.assertEqual(state.telemetry.remaining_capacity, 244.6)
|
||||
self.assertEqual(state.telemetry.nominal_capacity, 300.0)
|
||||
self.assertEqual(state.telemetry.soc, 82)
|
||||
self.assertEqual(state.telemetry.production_date, "2026-4-9")
|
||||
self.assertEqual(state.telemetry.temperatures, [26.8, 25.1, 25.5])
|
||||
self.assertTrue(state.telemetry.charge_mos)
|
||||
self.assertTrue(state.telemetry.discharge_mos)
|
||||
|
||||
def test_captured_cell_voltages(self):
|
||||
frame = bytes.fromhex("DD0400080D030D040D040D04FFB577")
|
||||
self.assertTrue(validate_frame(frame))
|
||||
state = DeviceState()
|
||||
decode_response(frame, state)
|
||||
self.assertEqual(state.telemetry.cells, [3.331, 3.332, 3.332, 3.332])
|
||||
self.assertEqual(cell_statistics(state.telemetry.cells), (3.331, 3.332, 0.001))
|
||||
|
||||
def test_empty_cell_statistics(self):
|
||||
self.assertIsNone(cell_statistics([]))
|
||||
|
||||
def test_scan_filter(self):
|
||||
self.assertEqual(berger_match_reason(None, ["0000ff00-0000-1000-8000-00805f9b34fb"]), "service:ff00")
|
||||
self.assertEqual(berger_match_reason("JBD-SP04S", []), "name")
|
||||
|
||||
Reference in New Issue
Block a user