issue-51-telegram refactored TelegramParser.parse to return Telegram object. Telegram object now does not do parsing anymore.
This commit is contained in:
parent
0a259a3c9d
commit
d146565717
@ -72,7 +72,7 @@ class FileReader(object):
|
|||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
@ -121,7 +121,7 @@ class FileInputReader(object):
|
|||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
@ -167,7 +167,7 @@ class FileTailReader(object):
|
|||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
|
@ -55,7 +55,7 @@ class SerialReader(object):
|
|||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
@ -121,7 +121,7 @@ class AsyncSerialReader(SerialReader):
|
|||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
queue.put_nowait(
|
queue.put_nowait(
|
||||||
Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
self.telegram_parser.parse(telegram)
|
||||||
)
|
)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
|
@ -81,7 +81,7 @@ class SocketReader(object):
|
|||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield Telegram(telegram, self.telegram_parser, self.telegram_specification)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
|
@ -17,6 +17,14 @@ EN = {
|
|||||||
obis.ELECTRICITY_DELIVERED_TARIFF_1: 'ELECTRICITY_DELIVERED_TARIFF_1',
|
obis.ELECTRICITY_DELIVERED_TARIFF_1: 'ELECTRICITY_DELIVERED_TARIFF_1',
|
||||||
obis.ELECTRICITY_DELIVERED_TARIFF_2: 'ELECTRICITY_DELIVERED_TARIFF_2',
|
obis.ELECTRICITY_DELIVERED_TARIFF_2: 'ELECTRICITY_DELIVERED_TARIFF_2',
|
||||||
obis.ELECTRICITY_ACTIVE_TARIFF: 'ELECTRICITY_ACTIVE_TARIFF',
|
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.EQUIPMENT_IDENTIFIER: 'EQUIPMENT_IDENTIFIER',
|
||||||
obis.CURRENT_ELECTRICITY_USAGE: 'CURRENT_ELECTRICITY_USAGE',
|
obis.CURRENT_ELECTRICITY_USAGE: 'CURRENT_ELECTRICITY_USAGE',
|
||||||
obis.CURRENT_ELECTRICITY_DELIVERY: 'CURRENT_ELECTRICITY_DELIVERY',
|
obis.CURRENT_ELECTRICITY_DELIVERY: 'CURRENT_ELECTRICITY_DELIVERY',
|
||||||
@ -78,6 +86,7 @@ EN = {
|
|||||||
obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER',
|
obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER',
|
||||||
obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE',
|
obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE',
|
||||||
obis.Q3D_EQUIPMENT_SERIALNUMBER: 'Q3D_EQUIPMENT_SERIALNUMBER',
|
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()])
|
REVERSE_EN = dict([(v, k) for k, v in EN.items()])
|
||||||
|
@ -6,15 +6,7 @@ from decimal import Decimal
|
|||||||
|
|
||||||
class Telegram(object):
|
class Telegram(object):
|
||||||
"""
|
"""
|
||||||
Container for raw and parsed telegram data.
|
Container for 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)
|
|
||||||
|
|
||||||
Attributes can be accessed on a telegram object by addressing by their english name, for example:
|
Attributes can be accessed on a telegram object by addressing by their english name, for example:
|
||||||
telegram.ELECTRICITY_USED_TARIFF_1
|
telegram.ELECTRICITY_USED_TARIFF_1
|
||||||
@ -24,22 +16,26 @@ class Telegram(object):
|
|||||||
yields:
|
yields:
|
||||||
['P1_MESSAGE_HEADER', 'P1_MESSAGE_TIMESTAMP', 'EQUIPMENT_IDENTIFIER', ...]
|
['P1_MESSAGE_HEADER', 'P1_MESSAGE_TIMESTAMP', 'EQUIPMENT_IDENTIFIER', ...]
|
||||||
"""
|
"""
|
||||||
def __init__(self, telegram_data, telegram_parser, telegram_specification):
|
def __init__(self, telegram_data, telegram_specification):
|
||||||
self._telegram_data = telegram_data
|
|
||||||
self._telegram_specification = telegram_specification
|
self._telegram_specification = telegram_specification
|
||||||
self._telegram_parser = telegram_parser
|
|
||||||
self._obis_name_mapping = dsmr_parser.obis_name_mapping.EN
|
self._obis_name_mapping = dsmr_parser.obis_name_mapping.EN
|
||||||
self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_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()
|
self._item_names = self._get_item_names()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
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]
|
obis_reference = self._reverse_obis_name_mapping[name]
|
||||||
value = self._dictionary[obis_reference]
|
value = self._dictionary[obis_reference]
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
return 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):
|
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._dictionary.items()]
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from decimal import Decimal
|
|||||||
from dlms_cosem.connection import XDlmsApduFactory
|
from dlms_cosem.connection import XDlmsApduFactory
|
||||||
from dlms_cosem.protocol.xdlms import GeneralGlobalCipher
|
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.exceptions import ParseError, InvalidChecksumError
|
||||||
from dsmr_parser.value_types import timestamp
|
from dsmr_parser.value_types import timestamp
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class TelegramParser(object):
|
class TelegramParser(object):
|
||||||
crc16_tab = []
|
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 telegram_specification: determines how the telegram is parsed
|
||||||
:param apply_checksum_validation: validate checksum if applicable for
|
: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
|
('!ABCD') including line endings in between the telegram's lines
|
||||||
:param str encryption_key: encryption key
|
:param str encryption_key: encryption key
|
||||||
:param str authentication_key: authentication key
|
:param str authentication_key: authentication key
|
||||||
:rtype: dict
|
:rtype: Telegram
|
||||||
:returns: Shortened example:
|
|
||||||
{
|
|
||||||
..
|
|
||||||
r'\d-\d:96\.1\.1.+?\r\n': <CosemObject>, # EQUIPMENT_IDENTIFIER
|
|
||||||
r'\d-\d:1\.8\.1.+?\r\n': <CosemObject>, # ELECTRICITY_USED_TARIFF_1
|
|
||||||
r'\d-\d:24\.3\.0.+?\r\n.+?\r\n': <MBusObject>, # GAS_METER_READING
|
|
||||||
..
|
|
||||||
}
|
|
||||||
:raises ParseError:
|
:raises ParseError:
|
||||||
:raises InvalidChecksumError:
|
:raises InvalidChecksumError:
|
||||||
"""
|
"""
|
||||||
@ -100,7 +92,7 @@ class TelegramParser(object):
|
|||||||
logger.error("ignore line with signature {}, because parsing failed.".format(signature),
|
logger.error("ignore line with signature {}, because parsing failed.".format(signature),
|
||||||
exc_info=True)
|
exc_info=True)
|
||||||
|
|
||||||
return telegram
|
return Telegram(telegram, self.telegram_specification)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_checksum(telegram):
|
def validate_checksum(telegram):
|
||||||
|
@ -3,6 +3,6 @@ from dsmr_parser.objects import Telegram
|
|||||||
from dsmr_parser.parsers import TelegramParser
|
from dsmr_parser.parsers import TelegramParser
|
||||||
from example_telegrams import TELEGRAM_V4_2
|
from example_telegrams import TELEGRAM_V4_2
|
||||||
parser = TelegramParser(telegram_specifications.V4)
|
parser = TelegramParser(telegram_specifications.V4)
|
||||||
telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4)
|
telegram = parser.parse(TELEGRAM_V4_2)
|
||||||
|
|
||||||
print(telegram)
|
print(telegram)
|
||||||
|
@ -18,7 +18,7 @@ class TestParserCornerCases(unittest.TestCase):
|
|||||||
def test_power_event_log_empty_1(self):
|
def test_power_event_log_empty_1(self):
|
||||||
# POWER_EVENT_FAILURE_LOG (1-0:99.97.0)
|
# POWER_EVENT_FAILURE_LOG (1-0:99.97.0)
|
||||||
parser = TelegramParser(telegram_specifications.V5)
|
parser = TelegramParser(telegram_specifications.V5)
|
||||||
telegram = Telegram(TELEGRAM_V5, parser, telegram_specifications.V5)
|
telegram = parser.parse(TELEGRAM_V5)
|
||||||
|
|
||||||
object_type = ProfileGenericObject
|
object_type = ProfileGenericObject
|
||||||
testitem = telegram.POWER_EVENT_FAILURE_LOG
|
testitem = telegram.POWER_EVENT_FAILURE_LOG
|
||||||
|
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
from dsmr_parser import obis_references as obis
|
from dsmr_parser import obis_references as obis
|
||||||
from dsmr_parser.clients.protocol import create_dsmr_protocol
|
from dsmr_parser.clients.protocol import create_dsmr_protocol
|
||||||
|
from dsmr_parser.objects import Telegram
|
||||||
|
|
||||||
TELEGRAM_V2_2 = (
|
TELEGRAM_V2_2 = (
|
||||||
'/ISk5\2MT382-1004\r\n'
|
'/ISk5\2MT382-1004\r\n'
|
||||||
@ -44,7 +44,7 @@ class ProtocolTest(unittest.TestCase):
|
|||||||
self.protocol.data_received(TELEGRAM_V2_2.encode('ascii'))
|
self.protocol.data_received(TELEGRAM_V2_2.encode('ascii'))
|
||||||
|
|
||||||
telegram = self.protocol.telegram_callback.call_args_list[0][0][0]
|
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 float(telegram[obis.CURRENT_ELECTRICITY_USAGE].value) == 1.01
|
||||||
assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW'
|
assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW'
|
||||||
|
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
from dsmr_parser import obis_references as obis
|
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.clients.rfxtrx_protocol import create_rfxtrx_dsmr_protocol, PACKETTYPE_DSMR, SUBTYPE_P1
|
||||||
|
from dsmr_parser.objects import Telegram
|
||||||
|
|
||||||
TELEGRAM_V2_2 = (
|
TELEGRAM_V2_2 = (
|
||||||
'/ISk5\2MT382-1004\r\n'
|
'/ISk5\2MT382-1004\r\n'
|
||||||
@ -68,7 +68,7 @@ class RFXtrxProtocolTest(unittest.TestCase):
|
|||||||
self.protocol.data_received(data[200:])
|
self.protocol.data_received(data[200:])
|
||||||
|
|
||||||
telegram = self.protocol.telegram_callback.call_args_list[0][0][0]
|
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 float(telegram[obis.CURRENT_ELECTRICITY_USAGE].value) == 1.01
|
||||||
assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW'
|
assert telegram[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW'
|
||||||
|
@ -30,7 +30,7 @@ class TelegramTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_instantiate(self):
|
def test_instantiate(self):
|
||||||
parser = TelegramParser(telegram_specifications.V4)
|
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)
|
# P1_MESSAGE_HEADER (1-3:0.2.8)
|
||||||
self.verify_telegram_item(telegram,
|
self.verify_telegram_item(telegram,
|
||||||
|
Loading…
Reference in New Issue
Block a user