"""Framing tests against packets captured from a real DGM20 (firmware 2.1.2).""" import unittest from dgm20.device import decode, encode, frame, parse, words_to_ascii def h(s): return bytes.fromhex(s) + bytes(64 - len(bytes.fromhex(s))) class Framing(unittest.TestCase): def test_read_request_matches_app(self): # checksum = -(0xC4+0x09+0x04+0x28+0x20) = -0x119 = 0xFEE7 p = frame(4, [0x2028]) self.assertEqual(p[:10].hex(" "), "51 c4 09 00 00 04 28 20 e7 fe") self.assertEqual(len(p), 65) def test_write_request_checksum(self): p = frame(3, [0x2028, 64]) self.assertEqual(p[1:3], bytes([0xC4, 0x0B])) self.assertEqual((sum(p[1:10]) + (p[10] | p[11] << 8)) & 0xFFFF, 0) def test_parse_read_reply(self): self.assertEqual(parse(h("11 c4 0b 00 00 04 28 20 40 00 a5 fe")), (4, [0x2028, 64])) def test_parse_range_reply(self): self.assertEqual(parse(h("11 c4 0f 00 00 06 27 20 02 00 01 00 40 00 9d fe")), (6, [0x2027, 2, 1, 64])) def test_parse_ack(self): self.assertEqual(parse(h("11 c4 09 00 00 02 00 00 31 ff")), (2, [0])) def test_parse_rejects_bad_checksum(self): self.assertIsNone(parse(h("11 c4 0b 00 00 04 28 20 40 00 a5 ff"))) def test_model_name(self): self.assertEqual(words_to_ascii([0x4744, 0x324D, 0x0030, 0]), "DGM20") class Encoding(unittest.TestCase): def test_bool(self): self.assertEqual(encode("nc", "on"), 1) self.assertEqual(encode("mute", False), 0) self.assertIs(decode("nc", 1), True) def test_monitor_uses_2000_3000(self): self.assertEqual(encode("monitor", True), 2000) self.assertEqual(encode("monitor", "off"), 3000) self.assertEqual(decode("monitor", 2000), "on") def test_range(self): self.assertEqual(encode("nc-level", "0"), 0) self.assertEqual(encode("nc-level", 100), 100) for bad in (101, -1, True, "loud"): with self.assertRaises(ValueError): encode("nc-level", bad) def test_unknown(self): with self.assertRaises(ValueError): encode("volume", 3) if __name__ == "__main__": unittest.main()