From 447f2a24fb2ce996ae13d1048ac8c630e6abe3d2 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Mon, 7 Nov 2016 20:00:10 +0100 Subject: [PATCH] Add test and exceptions for V2_2 implementation. --- dsmr_parser/objects.py | 15 +++++++++++++++ dsmr_parser/parsers.py | 32 ++++++++++++++++++++++++++++---- dsmr_parser/serial.py | 9 +++++++-- dsmr_parser/value_types.py | 5 ++++- test/test_parse.py | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 test/test_parse.py diff --git a/dsmr_parser/objects.py b/dsmr_parser/objects.py index 5024dba..e96df9f 100644 --- a/dsmr_parser/objects.py +++ b/dsmr_parser/objects.py @@ -19,6 +19,21 @@ class MBusObject(DSMRObject): return self.values[1]['unit'] +class MBusObjectV2_2(DSMRObject): + + @property + def datetime(self): + return self.values[0]['value'] + + @property + def value(self): + return self.values[5]['value'] + + @property + def unit(self): + return self.values[4]['unit'] + + class CosemObject(DSMRObject): @property diff --git a/dsmr_parser/parsers.py b/dsmr_parser/parsers.py index ae08e27..4b49a68 100644 --- a/dsmr_parser/parsers.py +++ b/dsmr_parser/parsers.py @@ -1,9 +1,9 @@ import logging import re -from .objects import MBusObject, CosemObject +from .objects import MBusObject, MBusObjectV2_2, CosemObject from .exceptions import ParseError - +from .obis_references import GAS_METER_READING logger = logging.getLogger(__name__) @@ -29,7 +29,7 @@ class TelegramParser(object): telegram = {} for line_value in line_values: - obis_reference, dsmr_object = self.parse_line(line_value) + obis_reference, dsmr_object = self.parse_line(line_value.strip()) telegram[obis_reference] = dsmr_object @@ -47,6 +47,26 @@ class TelegramParser(object): return obis_reference, parser.parse(line_value) +class TelegramParserV2_2(TelegramParser): + def parse(self, line_values): + """Join lines for gas meter.""" + + def join_lines(line_values): + join_next = re.compile(GAS_METER_READING) + + join = None + for line_value in line_values: + if join: + yield join.strip() + line_value + join = None + elif join_next.match(line_value): + join = line_value + else: + yield line_value + + return super().parse(join_lines(line_values)) + + class DSMRObjectParser(object): def __init__(self, *value_formats): @@ -85,7 +105,11 @@ class MBusParser(DSMRObjectParser): """ def parse(self, line): - return MBusObject(self._parse(line)) + values = self._parse(line) + if len(values) == 2: + return MBusObject(values) + else: + return MBusObjectV2_2(values) class CosemParser(DSMRObjectParser): diff --git a/dsmr_parser/serial.py b/dsmr_parser/serial.py index faa6d94..114244c 100644 --- a/dsmr_parser/serial.py +++ b/dsmr_parser/serial.py @@ -1,6 +1,6 @@ import serial -from dsmr_parser.parsers import TelegramParser +from dsmr_parser.parsers import TelegramParser, V3TelegramParser SERIAL_SETTINGS_V2_2 = { 'baudrate': 9600, @@ -36,7 +36,12 @@ class SerialReader(object): def __init__(self, device, serial_settings, telegram_specification): self.serial_settings = serial_settings self.serial_settings['port'] = device - self.telegram_parser = TelegramParser(telegram_specification) + + if serial_settings is SERIAL_SETTINGS_V2_2: + telegram_parser = V3TelegramParser + else: + telegram_parser = TelegramParser + self.telegram_parser = telegram_parser(telegram_specification) def read(self): """ diff --git a/dsmr_parser/value_types.py b/dsmr_parser/value_types.py index 4154d50..48a9146 100644 --- a/dsmr_parser/value_types.py +++ b/dsmr_parser/value_types.py @@ -6,7 +6,10 @@ import pytz def timestamp(value): naive_datetime = datetime.datetime.strptime(value[:-1], '%y%m%d%H%M%S') - is_dst = value[12] == 'S' # assume format 160322150000W + if len(value) == 13: + is_dst = value[12] == 'S' # assume format 160322150000W + else: + is_dst = False local_tz = pytz.timezone('Europe/Amsterdam') localized_datetime = local_tz.localize(naive_datetime, is_dst=is_dst) diff --git a/test/test_parse.py b/test/test_parse.py new file mode 100644 index 0000000..460b509 --- /dev/null +++ b/test/test_parse.py @@ -0,0 +1,38 @@ +"""Test telegram parsing.""" + +from dsmr_parser.parsers import TelegramParserV2_2 +from dsmr_parser import telegram_specifications +from dsmr_parser.obis_references import CURRENT_ELECTRICITY_USAGE, GAS_METER_READING + +TELEGRAM_V2_2 = [ + "/ISk5\2MT382-1004", + "", + "0-0:96.1.1(00000000000000)", + "1-0:1.8.1(00001.001*kWh)", + "1-0:1.8.2(00001.001*kWh)", + "1-0:2.8.1(00001.001*kWh)", + "1-0:2.8.2(00001.001*kWh)", + "0-0:96.14.0(0001)", + "1-0:1.7.0(0001.01*kW)", + "1-0:2.7.0(0000.00*kW)", + "0-0:17.0.0(0999.00*kW)", + "0-0:96.3.10(1)", + "0-0:96.13.1()", + "0-0:96.13.0()", + "0-1:24.1.0(3)", + "0-1:96.1.0(000000000000)", + "0-1:24.3.0(161107190000)(00)(60)(1)(0-1:24.2.1)(m3)", + "(00001.001)", + "0-1:24.4.0(1)", + "!", +] + + +def test_parse_v2_2(): + """Test if telegram parsing results in correct results.""" + + parser = TelegramParserV2_2(telegram_specifications.V2_2) + result = parser.parse(TELEGRAM_V2_2) + + assert float(result[CURRENT_ELECTRICITY_USAGE].value) == 1.01 + assert float(result[GAS_METER_READING].value) == 1.001