from decimal import Decimal from pathlib import Path from scripts.p1_probe import IntegrityStatus, TelegramFramer, parse_telegram FIXTURES = Path(__file__).parent / "fixtures" def _fixture(name: str) -> bytes: return (FIXTURES / name).read_bytes() def test_standard_dsmr_fixture_has_a_valid_frame_and_crc(): frame = _fixture("dsmr_p1_valid.txt") framer = TelegramFramer() assert framer.feed(frame[:23]) == [] assert framer.feed(frame[23:]) == [frame] telegram = parse_telegram(frame) assert telegram.integrity is IntegrityStatus.VALID assert telegram.header == b"/ISk5\\2MT382-1000" assert telegram.timestamp == "240822120000S" def test_warmtelink_fixture_is_unverifiable_but_parses_channels_by_obis_code(): telegram = parse_telegram(_fixture("warmtelink_p1_7n1.txt")) assert telegram.integrity is IntegrityStatus.UNVERIFIABLE assert "missing standard" in telegram.integrity_reason assert [channel.number for channel in telegram.channels] == [1, 2] values = { channel.number: [(field.value, field.unit) for field in channel.readings] for channel in telegram.channels } assert values[1] == [(Decimal("5.900"), "m3")] assert values[2] == [(Decimal("0.017"), "GJ")] def test_arbitrary_chunk_boundaries_and_field_order_do_not_change_parsing(): frame = _fixture("warmtelink_p1_7n1.txt") framer = TelegramFramer() frames = [] for byte in frame: frames.extend(framer.feed(bytes([byte]))) assert frames == [frame] assert parse_telegram(frames[0]).channels == parse_telegram(frame).channels def test_unknown_fields_are_preserved_verbatim(): frame = b")HEADER\n9-9:9.9.9(opaque)(still-opaque)\n!nope\n" telegram = parse_telegram(frame) assert len(telegram.fields) == 1 assert telegram.fields[0].code == "9-9:9.9.9" assert telegram.fields[0].raw_values == ("opaque", "still-opaque") assert telegram.fields[0].value is None def test_missing_header_and_non_hex_footer_are_unverifiable(): telegram = parse_telegram(b")HEADER\n0-0:1.0.0(240822120000S)\n!zzzz\n") assert telegram.integrity is IntegrityStatus.UNVERIFIABLE assert telegram.footer == b"zzzz" def test_crc_mismatch_is_invalid_when_standard_framing_is_present(): frame = _fixture("dsmr_p1_valid.txt") invalid = frame[:-5] + b"0000\n" telegram = parse_telegram(invalid) assert telegram.integrity is IntegrityStatus.INVALID