71 lines
3.0 KiB
Python
71 lines
3.0 KiB
Python
import unittest
|
|
|
|
from berger_gui import DeviceState, berger_match_reason, decode_response, read_frame, split_frames, write_frame
|
|
|
|
|
|
class BergerParserTest(unittest.TestCase):
|
|
def test_read_frame_checksum(self):
|
|
self.assertEqual(read_frame(0x03).hex().upper(), "DDA50300FFFD77")
|
|
self.assertEqual(read_frame(0x04).hex().upper(), "DDA50400FFFC77")
|
|
|
|
def test_write_switch_checksum(self):
|
|
self.assertEqual(write_frame(0xE1, b"\x00\x00").hex().upper(), "DD5AE1020000FF1D77")
|
|
|
|
def test_decode_base_data(self):
|
|
payload = bytearray(27 + 4)
|
|
payload[0:2] = (1328).to_bytes(2, "big")
|
|
payload[2:4] = (65536 - 752).to_bytes(2, "big")
|
|
payload[4:6] = (10750).to_bytes(2, "big")
|
|
payload[6:8] = (16000).to_bytes(2, "big")
|
|
payload[8:10] = (3).to_bytes(2, "big")
|
|
payload[10:12] = ((25 << 9) | (7 << 5) | 27).to_bytes(2, "big")
|
|
payload[16:18] = (0x0010).to_bytes(2, "big")
|
|
payload[18] = 21
|
|
payload[19] = 67
|
|
payload[20] = 3
|
|
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"
|
|
|
|
buffer = bytearray(b"\x00" + frame + frame)
|
|
frames = split_frames(buffer)
|
|
self.assertEqual(len(frames), 2)
|
|
|
|
state = DeviceState()
|
|
decode_response(frames[0], state)
|
|
self.assertAlmostEqual(state.telemetry.voltage, 13.28)
|
|
self.assertAlmostEqual(state.telemetry.current, -7.52)
|
|
self.assertEqual(state.telemetry.soc, 67)
|
|
self.assertAlmostEqual(state.telemetry.remaining_capacity, 107.5)
|
|
self.assertAlmostEqual(state.telemetry.nominal_capacity, 160.0)
|
|
self.assertEqual(state.telemetry.cycle_count, 3)
|
|
self.assertEqual(state.telemetry.production_date, "2025-7-27")
|
|
self.assertTrue(state.telemetry.charge_mos)
|
|
self.assertTrue(state.telemetry.discharge_mos)
|
|
self.assertTrue(state.telemetry.protection)
|
|
self.assertEqual(state.telemetry.temperatures, [25.0, 26.0])
|
|
self.assertEqual(state.telemetry.time_label, "Time till empty")
|
|
|
|
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"
|
|
state = DeviceState()
|
|
decode_response(frame, state)
|
|
self.assertEqual(state.telemetry.cells, [3.306, 3.312, 3.308, 3.311])
|
|
|
|
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")
|
|
self.assertIsNone(berger_match_reason("Keyboard", []))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|