diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5800449..46a4645 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,10 @@ Change Log ---------- +**0.20** (2020-05-12) + +- All objects can now print their values +- Add parser + object for generic profile + **0.19** (2020-05-03) - Add following missing elements to telegram specification v4: @@ -45,7 +50,7 @@ Change Log **0.10** (2017-06-05) -- bugix: don't force full telegram signatures (`pull request #25 `_) +- bugfix: don't force full telegram signatures (`pull request #25 `_) - removed unused code for automatic telegram detection as this needs reworking after the fix mentioned above - InvalidChecksumError's are logged as warning instead of error diff --git a/dsmr_parser/objects.py b/dsmr_parser/objects.py index e313cd5..d07cd35 100644 --- a/dsmr_parser/objects.py +++ b/dsmr_parser/objects.py @@ -1,4 +1,5 @@ import dsmr_parser.obis_name_mapping +import datetime class Telegram(object): @@ -48,7 +49,7 @@ class Telegram(object): def __str__(self): output = "" for attr, value in self: - output += "{}: \t {} \t[{}]\n".format(attr, str(value.value), str(value.unit)) + output += "{}: \t {}\n".format(attr, str(value)) return output @@ -87,6 +88,10 @@ class MBusObject(DSMRObject): else: return self.values[1]['unit'] + def __str__(self): + output = "{}\t[{}] at {}".format(str(self.value), str(self.unit), str(self.datetime.astimezone().isoformat())) + return output + class CosemObject(DSMRObject): @@ -98,6 +103,13 @@ class CosemObject(DSMRObject): def unit(self): return self.values[0]['unit'] + def __str__(self): + print_value = self.value + if isinstance(self.value, datetime.datetime): + print_value = self.value.astimezone().isoformat() + output = "{}\t[{}]".format(str(print_value), str(self.unit)) + return output + class ProfileGeneric(DSMRObject): pass # TODO implement diff --git a/dsmr_parser/parsers.py b/dsmr_parser/parsers.py index d9aeb5a..fd88798 100644 --- a/dsmr_parser/parsers.py +++ b/dsmr_parser/parsers.py @@ -183,7 +183,7 @@ class CosemParser(DSMRObjectParser): return CosemObject(self._parse(line)) -class ProfileGenericParser(DSMRObjectParser): +class ProfileGenericParser(object): """ Power failure log parser. @@ -205,6 +205,22 @@ class ProfileGenericParser(DSMRObjectParser): 9) Unit of buffer values (Unit of capture objects attribute) """ + def _parse(self, line): + # Match value groups, but exclude the parentheses. Adapted to also match OBIS code in 3rd position. + pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') + values = re.findall(pattern, line) + + # Convert empty value groups to None for clarity. + values = [None if value == '' else value for value in values] + + buffer_length = int(values[0]) + + if (not values) or (len(values) != (buffer_length * 2 + 2)): + raise ParseError("Invalid '%s' line for '%s'", line, self) + + return [self.value_formats[i].parse(value) + for i, value in enumerate(values)] + def parse(self, line): raise NotImplementedError() diff --git a/dsmr_parser/profile_generic_specifications.py b/dsmr_parser/profile_generic_specifications.py new file mode 100644 index 0000000..470d03f --- /dev/null +++ b/dsmr_parser/profile_generic_specifications.py @@ -0,0 +1,14 @@ +from dsmr_parser.parsers import ValueParser, MBusParser +from dsmr_parser.value_types import timestamp + +FAILURE_EVENT = r'0-0\:96\.7\.19' + +V4 = { + 'objects': { + FAILURE_EVENT: MBusParser( + ValueParser(timestamp), + ValueParser(int) + ) + } + +} diff --git a/setup.py b/setup.py index beb8e57..c925b4d 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( author='Nigel Dokter', author_email='nigel@nldr.net', url='https://github.com/ndokter/dsmr_parser', - version='0.19', + version='0.20', packages=find_packages(), install_requires=[ 'pyserial>=3,<4',