diff --git a/dsmr_parser/objects.py b/dsmr_parser/objects.py index 9489d97..e6706c4 100644 --- a/dsmr_parser/objects.py +++ b/dsmr_parser/objects.py @@ -1,4 +1,7 @@ class DSMRObject(object): + """ + Represents all data from a single telegram line. + """ def __init__(self, values): self.values = values diff --git a/dsmr_parser/parsers.py b/dsmr_parser/parsers.py index 478b518..6a9f465 100644 --- a/dsmr_parser/parsers.py +++ b/dsmr_parser/parsers.py @@ -27,8 +27,8 @@ class TelegramParser(object): The telegram str type makes python 2.x integration easier. - :param str telegram: full telegram from start ('/') to checksum - ('!ABCD') including line endings inbetween the telegram's lines + :param str telegram_data: full telegram from start ('/') to checksum + ('!ABCD') including line endings in between the telegram's lines :rtype: dict :returns: Shortened example: { @@ -51,8 +51,12 @@ class TelegramParser(object): for signature, parser in self.telegram_specification['objects'].items(): match = re.search(signature, telegram_data, re.DOTALL) - if match: - telegram[signature] = parser.parse(match.group(0)) + # All telegram specification lines/signatures are expected to be + # present. + if not match: + raise ParseError('Telegram specification does not match ' + 'telegram data') + telegram[signature] = parser.parse(match.group(0)) return telegram @@ -90,6 +94,31 @@ class TelegramParser(object): ) +def match_telegram_specification(telegram_data): + """ + Find telegram specification that matches the telegram data by trying all + specifications. + + Could be further optimized to check the actual 0.2.8 OBIS reference which + is available for DSMR version 4 and up. + + :param str telegram_data: full telegram from start ('/') to checksum + ('!ABCD') including line endings in between the telegram's lines + :return: telegram specification + :rtype: dict + """ + # Prevent circular import + from dsmr_parser import telegram_specifications + + for specification in telegram_specifications.ALL: + try: + TelegramParser(specification).parse(telegram_data) + except ParseError: + pass + else: + return specification + + class DSMRObjectParser(object): """ Parses an object (can also be see as a 'line') from a telegram. diff --git a/dsmr_parser/telegram_specifications.py b/dsmr_parser/telegram_specifications.py index 43642f9..5222786 100644 --- a/dsmr_parser/telegram_specifications.py +++ b/dsmr_parser/telegram_specifications.py @@ -42,34 +42,7 @@ V2_2 = { } } -V3 = { - 'checksum_support': False, - 'objects': { - obis.EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), - obis.ELECTRICITY_USED_TARIFF_1: CosemParser(ValueParser(Decimal)), - obis.ELECTRICITY_USED_TARIFF_2: CosemParser(ValueParser(Decimal)), - obis.ELECTRICITY_DELIVERED_TARIFF_1: CosemParser(ValueParser(Decimal)), - obis.ELECTRICITY_DELIVERED_TARIFF_2: CosemParser(ValueParser(Decimal)), - obis.ELECTRICITY_ACTIVE_TARIFF: CosemParser(ValueParser(str)), - obis.CURRENT_ELECTRICITY_USAGE: CosemParser(ValueParser(Decimal)), - obis.CURRENT_ELECTRICITY_DELIVERY: CosemParser(ValueParser(Decimal)), - obis.ACTUAL_TRESHOLD_ELECTRICITY: CosemParser(ValueParser(Decimal)), - obis.ACTUAL_SWITCH_POSITION: CosemParser(ValueParser(str)), - obis.TEXT_MESSAGE_CODE: CosemParser(ValueParser(int)), - obis.TEXT_MESSAGE: CosemParser(ValueParser(str)), - obis.EQUIPMENT_IDENTIFIER_GAS: CosemParser(ValueParser(str)), - obis.DEVICE_TYPE: CosemParser(ValueParser(str)), - obis.VALVE_POSITION_GAS: CosemParser(ValueParser(str)), - obis.GAS_METER_READING: MBusParser( - ValueParser(timestamp), - ValueParser(int), - ValueParser(int), - ValueParser(int), - ValueParser(str), - ValueParser(Decimal), - ), - } -} +V3 = V2_2 V4 = { 'checksum_support': True, @@ -145,3 +118,5 @@ V5 = { ) } } + +ALL = (V2_2, V3, V4, V5) diff --git a/test/test_match_telegram_specification.py b/test/test_match_telegram_specification.py index e69de29..1385b82 100644 --- a/test/test_match_telegram_specification.py +++ b/test/test_match_telegram_specification.py @@ -0,0 +1,25 @@ +import unittest + +from dsmr_parser.parsers import match_telegram_specification +from dsmr_parser import telegram_specifications +from test import example_telegrams + + +class MatchTelegramSpecificationTest(unittest.TestCase): + + + def test_v2_2(self): + assert match_telegram_specification(example_telegrams.TELEGRAM_V2_2) \ + == telegram_specifications.V2_2 + + def test_v3(self): + assert match_telegram_specification(example_telegrams.TELEGRAM_V3) \ + == telegram_specifications.V3 + + def test_v4_2(self): + assert match_telegram_specification(example_telegrams.TELEGRAM_V4_2) \ + == telegram_specifications.V4 + + def test_v5(self): + assert match_telegram_specification(example_telegrams.TELEGRAM_V5) \ + == telegram_specifications.V5