diff --git a/dsmr_parser/clients/filereader.py b/dsmr_parser/clients/filereader.py index 9b9cf6e..47a6338 100644 --- a/dsmr_parser/clients/filereader.py +++ b/dsmr_parser/clients/filereader.py @@ -72,7 +72,7 @@ class FileReader(object): for telegram in self.telegram_buffer.get_all(): try: - yield Telegram(telegram, self.telegram_parser, self.telegram_specification) + yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: @@ -121,7 +121,7 @@ class FileInputReader(object): for telegram in self.telegram_buffer.get_all(): try: - yield Telegram(telegram, self.telegram_parser, self.telegram_specification) + yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: @@ -167,7 +167,7 @@ class FileTailReader(object): for telegram in self.telegram_buffer.get_all(): try: - yield Telegram(telegram, self.telegram_parser, self.telegram_specification) + yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: diff --git a/dsmr_parser/clients/serial_.py b/dsmr_parser/clients/serial_.py index a76780f..91b3a3b 100644 --- a/dsmr_parser/clients/serial_.py +++ b/dsmr_parser/clients/serial_.py @@ -55,7 +55,7 @@ class SerialReader(object): for telegram in self.telegram_buffer.get_all(): try: - yield Telegram(telegram, self.telegram_parser, self.telegram_specification) + yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: @@ -121,7 +121,7 @@ class AsyncSerialReader(SerialReader): for telegram in self.telegram_buffer.get_all(): try: queue.put_nowait( - Telegram(telegram, self.telegram_parser, self.telegram_specification) + self.telegram_parser.parse(telegram) ) except InvalidChecksumError as e: logger.warning(str(e)) diff --git a/dsmr_parser/clients/socket_.py b/dsmr_parser/clients/socket_.py index 6727979..39621c6 100644 --- a/dsmr_parser/clients/socket_.py +++ b/dsmr_parser/clients/socket_.py @@ -81,7 +81,7 @@ class SocketReader(object): for telegram in self.telegram_buffer.get_all(): try: - yield Telegram(telegram, self.telegram_parser, self.telegram_specification) + yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: diff --git a/dsmr_parser/obis_name_mapping.py b/dsmr_parser/obis_name_mapping.py index 316e43a..8f5f78d 100644 --- a/dsmr_parser/obis_name_mapping.py +++ b/dsmr_parser/obis_name_mapping.py @@ -17,6 +17,14 @@ EN = { obis.ELECTRICITY_DELIVERED_TARIFF_1: 'ELECTRICITY_DELIVERED_TARIFF_1', obis.ELECTRICITY_DELIVERED_TARIFF_2: 'ELECTRICITY_DELIVERED_TARIFF_2', obis.ELECTRICITY_ACTIVE_TARIFF: 'ELECTRICITY_ACTIVE_TARIFF', + obis.CURRENT_REACTIVE_EXPORTED: 'CURRENT_REACTIVE_EXPORTED', + obis.ELECTRICITY_REACTIVE_IMPORTED_TOTAL: 'ELECTRICITY_REACTIVE_IMPORTED_TOTAL', + obis.ELECTRICITY_REACTIVE_IMPORTED_TARIFF_1: 'ELECTRICITY_REACTIVE_IMPORTED_TARIFF_1', + obis.ELECTRICITY_REACTIVE_IMPORTED_TARIFF_2: 'ELECTRICITY_REACTIVE_IMPORTED_TARIFF_2', + obis.ELECTRICITY_REACTIVE_EXPORTED_TOTAL: 'ELECTRICITY_REACTIVE_EXPORTED_TOTAL', + obis.ELECTRICITY_REACTIVE_EXPORTED_TARIFF_1: 'ELECTRICITY_REACTIVE_EXPORTED_TARIFF_1', + obis.ELECTRICITY_REACTIVE_EXPORTED_TARIFF_2: 'ELECTRICITY_REACTIVE_EXPORTED_TARIFF_2', + obis.CURRENT_REACTIVE_IMPORTED: 'CURRENT_REACTIVE_IMPORTED', obis.EQUIPMENT_IDENTIFIER: 'EQUIPMENT_IDENTIFIER', obis.CURRENT_ELECTRICITY_USAGE: 'CURRENT_ELECTRICITY_USAGE', obis.CURRENT_ELECTRICITY_DELIVERY: 'CURRENT_ELECTRICITY_DELIVERY', @@ -78,6 +86,7 @@ EN = { obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER', obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE', obis.Q3D_EQUIPMENT_SERIALNUMBER: 'Q3D_EQUIPMENT_SERIALNUMBER', + obis.BELGIUM_MBUS2_DEVICE_TYPE: 'BELGIUM_MBUS2_DEVICE_TYPE' } REVERSE_EN = dict([(v, k) for k, v in EN.items()]) diff --git a/dsmr_parser/objects.py b/dsmr_parser/objects.py index 351b5c6..121fe31 100644 --- a/dsmr_parser/objects.py +++ b/dsmr_parser/objects.py @@ -6,15 +6,7 @@ from decimal import Decimal class Telegram(object): """ - Container for raw and parsed telegram data. - Initializing: - from dsmr_parser import telegram_specifications - from dsmr_parser.exceptions import InvalidChecksumError, ParseError - from dsmr_parser.objects import CosemObject, MBusObject, Telegram - from dsmr_parser.parsers import TelegramParser - from test.example_telegrams import TELEGRAM_V4_2 - parser = TelegramParser(telegram_specifications.V4) - telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) + Container for parsed telegram data. Attributes can be accessed on a telegram object by addressing by their english name, for example: telegram.ELECTRICITY_USED_TARIFF_1 @@ -24,22 +16,26 @@ class Telegram(object): yields: ['P1_MESSAGE_HEADER', 'P1_MESSAGE_TIMESTAMP', 'EQUIPMENT_IDENTIFIER', ...] """ - def __init__(self, telegram_data, telegram_parser, telegram_specification): - self._telegram_data = telegram_data + def __init__(self, telegram_data, telegram_specification): self._telegram_specification = telegram_specification - self._telegram_parser = telegram_parser self._obis_name_mapping = dsmr_parser.obis_name_mapping.EN self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_EN - self._dictionary = self._telegram_parser.parse(telegram_data) + self._dictionary = telegram_data self._item_names = self._get_item_names() def __getattr__(self, name): - ''' will only get called for undefined attributes ''' + """ will only get called for undefined attributes """ obis_reference = self._reverse_obis_name_mapping[name] value = self._dictionary[obis_reference] setattr(self, name, value) return value + def __getitem__(self, obis_reference): + return self._dictionary[obis_reference] + + def __len__(self): + return len(self._dictionary) + def _get_item_names(self): return [self._obis_name_mapping[k] for k, v in self._dictionary.items()] diff --git a/dsmr_parser/parsers.py b/dsmr_parser/parsers.py index 9b10b4d..fb12a02 100644 --- a/dsmr_parser/parsers.py +++ b/dsmr_parser/parsers.py @@ -8,7 +8,7 @@ from decimal import Decimal from dlms_cosem.connection import XDlmsApduFactory from dlms_cosem.protocol.xdlms import GeneralGlobalCipher -from dsmr_parser.objects import MBusObject, MBusObjectPeak, CosemObject, ProfileGenericObject +from dsmr_parser.objects import MBusObject, MBusObjectPeak, CosemObject, ProfileGenericObject, Telegram from dsmr_parser.exceptions import ParseError, InvalidChecksumError from dsmr_parser.value_types import timestamp @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) class TelegramParser(object): crc16_tab = [] - def __init__(self, telegram_specification, apply_checksum_validation=True): + def __init__(self, telegram_specification, apply_checksum_validation=True, gas_meter_channel=None): """ :param telegram_specification: determines how the telegram is parsed :param apply_checksum_validation: validate checksum if applicable for @@ -37,15 +37,7 @@ class TelegramParser(object): ('!ABCD') including line endings in between the telegram's lines :param str encryption_key: encryption key :param str authentication_key: authentication key - :rtype: dict - :returns: Shortened example: - { - .. - r'\d-\d:96\.1\.1.+?\r\n': , # EQUIPMENT_IDENTIFIER - r'\d-\d:1\.8\.1.+?\r\n': , # ELECTRICITY_USED_TARIFF_1 - r'\d-\d:24\.3\.0.+?\r\n.+?\r\n': , # GAS_METER_READING - .. - } + :rtype: Telegram :raises ParseError: :raises InvalidChecksumError: """ @@ -100,7 +92,7 @@ class TelegramParser(object): logger.error("ignore line with signature {}, because parsing failed.".format(signature), exc_info=True) - return telegram + return Telegram(telegram, self.telegram_specification) @staticmethod def validate_checksum(telegram): diff --git a/test/experiment_telegram.py b/test/experiment_telegram.py index 2892346..85622c7 100644 --- a/test/experiment_telegram.py +++ b/test/experiment_telegram.py @@ -3,6 +3,6 @@ from dsmr_parser.objects import Telegram from dsmr_parser.parsers import TelegramParser from example_telegrams import TELEGRAM_V4_2 parser = TelegramParser(telegram_specifications.V4) -telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) +telegram = parser.parse(TELEGRAM_V4_2) print(telegram) diff --git a/test/test_parser_corner_cases.py b/test/test_parser_corner_cases.py index 3f203e7..7292b2c 100644 --- a/test/test_parser_corner_cases.py +++ b/test/test_parser_corner_cases.py @@ -18,7 +18,7 @@ class TestParserCornerCases(unittest.TestCase): def test_power_event_log_empty_1(self): # POWER_EVENT_FAILURE_LOG (1-0:99.97.0) parser = TelegramParser(telegram_specifications.V5) - telegram = Telegram(TELEGRAM_V5, parser, telegram_specifications.V5) + telegram = parser.parse(TELEGRAM_V5) object_type = ProfileGenericObject testitem = telegram.POWER_EVENT_FAILURE_LOG diff --git a/test/test_protocol.py b/test/test_protocol.py index d1393f3..1e7440b 100644 --- a/test/test_protocol.py +++ b/test/test_protocol.py @@ -4,7 +4,7 @@ import unittest from dsmr_parser import obis_references as obis from dsmr_parser.clients.protocol import create_dsmr_protocol - +from dsmr_parser.objects import Telegram TELEGRAM_V2_2 = ( '/ISk5\2MT382-1004\r\n' @@ -44,7 +44,7 @@ class ProtocolTest(unittest.TestCase): self.protocol.data_received(TELEGRAM_V2_2.encode('ascii')) telegram = self.protocol.telegram_callback.call_args_list[0][0][0] - assert isinstance(telegram, dict) + assert isinstance(telegram, Telegram) assert float(telegram[obis.CURRENT_ELECTRICITY_USAGE].value) == 1.01 assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' diff --git a/test/test_rfxtrx_protocol.py b/test/test_rfxtrx_protocol.py index 7c79d22..6770bd5 100644 --- a/test/test_rfxtrx_protocol.py +++ b/test/test_rfxtrx_protocol.py @@ -4,7 +4,7 @@ import unittest from dsmr_parser import obis_references as obis from dsmr_parser.clients.rfxtrx_protocol import create_rfxtrx_dsmr_protocol, PACKETTYPE_DSMR, SUBTYPE_P1 - +from dsmr_parser.objects import Telegram TELEGRAM_V2_2 = ( '/ISk5\2MT382-1004\r\n' @@ -68,7 +68,7 @@ class RFXtrxProtocolTest(unittest.TestCase): self.protocol.data_received(data[200:]) telegram = self.protocol.telegram_callback.call_args_list[0][0][0] - assert isinstance(telegram, dict) + assert isinstance(telegram, Telegram) assert float(telegram[obis.CURRENT_ELECTRICITY_USAGE].value) == 1.01 assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' diff --git a/test/test_telegram.py b/test/test_telegram.py index 90b8eff..39ca426 100644 --- a/test/test_telegram.py +++ b/test/test_telegram.py @@ -30,7 +30,7 @@ class TelegramTest(unittest.TestCase): def test_instantiate(self): parser = TelegramParser(telegram_specifications.V4) - telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) + telegram = parser.parse(TELEGRAM_V4_2) # P1_MESSAGE_HEADER (1-3:0.2.8) self.verify_telegram_item(telegram,