From 3e0332963c3d38ab929245da76098eecfb0e0091 Mon Sep 17 00:00:00 2001 From: Nigel Dokter Date: Sat, 14 Jan 2023 19:47:24 +0100 Subject: [PATCH] issue-51-telegram work in progress --- dsmr_parser/objects.py | 27 +++++++++++++++++++-------- dsmr_parser/parsers.py | 16 +++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/dsmr_parser/objects.py b/dsmr_parser/objects.py index 121fe31..15ed27e 100644 --- a/dsmr_parser/objects.py +++ b/dsmr_parser/objects.py @@ -1,7 +1,9 @@ +from collections import defaultdict +from decimal import Decimal + import dsmr_parser.obis_name_mapping import datetime import json -from decimal import Decimal class Telegram(object): @@ -16,28 +18,33 @@ class Telegram(object): yields: ['P1_MESSAGE_HEADER', 'P1_MESSAGE_TIMESTAMP', 'EQUIPMENT_IDENTIFIER', ...] """ - def __init__(self, telegram_data, telegram_specification): - self._telegram_specification = telegram_specification + def __init__(self): + self._telegram_data = defaultdict(list) self._obis_name_mapping = dsmr_parser.obis_name_mapping.EN self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_EN - self._dictionary = telegram_data self._item_names = self._get_item_names() + def add(self, obis_reference, value): + self._telegram_data[obis_reference].append(value) + + def get(self, obis_reference, channel): + return next(filter(lambda x: x.channel == channel, self._telegram_data[obis_reference])) + def __getattr__(self, name): """ will only get called for undefined attributes """ obis_reference = self._reverse_obis_name_mapping[name] - value = self._dictionary[obis_reference] + value = self._telegram_data[obis_reference][0] setattr(self, name, value) return value def __getitem__(self, obis_reference): - return self._dictionary[obis_reference] + return self._telegram_data[obis_reference][0] def __len__(self): - return len(self._dictionary) + return len(self._telegram_data) #TODO: its nested now def _get_item_names(self): - return [self._obis_name_mapping[k] for k, v in self._dictionary.items()] + return [self._obis_name_mapping[k] for k, v in self._telegram_data.items()] def __iter__(self): for attr in self._item_names: @@ -62,6 +69,10 @@ class DSMRObject(object): def __init__(self, values): self.values = values + @property + def channel(self): + return 0 # TODO + class MBusObject(DSMRObject): diff --git a/dsmr_parser/parsers.py b/dsmr_parser/parsers.py index fb12a02..80d9a91 100644 --- a/dsmr_parser/parsers.py +++ b/dsmr_parser/parsers.py @@ -74,25 +74,27 @@ class TelegramParser(object): except Exception: pass - if self.apply_checksum_validation \ - and self.telegram_specification['checksum_support']: + if self.apply_checksum_validation and self.telegram_specification['checksum_support']: self.validate_checksum(telegram_data) - telegram = {} + telegram = Telegram() for signature, parser in self.telegram_specification['objects'].items(): - match = re.search(signature, telegram_data, re.DOTALL) + pattern = re.compile(signature, re.DOTALL) + matches = pattern.findall(telegram_data) # Some signatures are optional and may not be present, # so only parse lines that match - if match: + for match in matches: try: - telegram[signature] = parser.parse(match.group(0)) + value = parser.parse(match) except Exception: logger.error("ignore line with signature {}, because parsing failed.".format(signature), exc_info=True) + else: + telegram.add(obis_reference=signature, value=value) - return Telegram(telegram, self.telegram_specification) + return telegram @staticmethod def validate_checksum(telegram):