Compare commits

..
Author SHA1 Message Date
Nigel a98c9ae4b7 issue-51-telegram made Telegram str and json methods more generic 2023-02-19 12:21:20 +01:00
Nigel 14d9869fc3 issue-51-telegram feedback from lowdef 2023-02-18 19:55:27 +01:00
Nigel 36705f99ca issue-51-telegram refining 2023-02-18 15:04:31 +01:00
Nigel 0a6316e155 issue-51-telegram make Telegram completely backwards compatible for now 2023-02-18 10:16:31 +01:00
Nigel 64787130bc issue-51-telegram make Telegram completely backwards compatible for now 2023-02-18 10:13:43 +01:00
Nigel 929435c5fb issue-51-telegram convert all datetime objects to UTC 2023-02-15 15:43:26 +01:00
Nigel d930c1082a issue-51-telegram add test for Telegram.__str__ 2023-02-15 15:11:23 +01:00
Nigel b7f3af00b9 issue-51-telegram work in progress 2023-02-15 13:55:26 +01:00
Nigel ad25fd4182 issue-51-telegram work in progress 2023-02-15 11:55:28 +01:00
Nigel 516850481d issue-51-telegram removed Telegram.__getattr__ and refactored __iter__ as well 2023-02-13 21:47:59 +01:00
Nigel c7b9966083 issue-51-telegram code style 2023-02-12 20:22:24 +01:00
Nigel 8dee5edb0d issue-51-telegram code style 2023-02-12 18:40:52 +01:00
Nigel 7bda3de4d9 issue-51-telegram fix compatibility with changes from master 2023-02-12 18:34:26 +01:00
Nigel 976681b929 Merge branch 'master' into issue-51-telegram 2023-02-12 18:32:14 +01:00
Nigel 0593d4172d issue-51-telegram fix bug when no mbus devices are present 2023-02-12 18:06:01 +01:00
Nigel 47db8cad27 issue-51-telegram fix Telegram.get_mbus_device_by_channel 2023-02-12 11:28:02 +01:00
Nigel 32854897d8 issue-51-telegram updated code comment 2023-02-12 11:18:05 +01:00
Nigel b527e991ef issue-51-telegram updated documentation; refactored V5 unittest to use telegram attributes instead of keys; 2023-02-12 11:14:47 +01:00
Nigel 253d043b7b issue-51-telegram updated Telegram object docs and cleaned it up a bit 2023-02-11 17:38:25 +01:00
Nigel eab90e7049 issue-51-telegram work in progress 2023-02-11 09:44:54 +01:00
Nigel 3ae06f88b7 issue-51-telegram work in progress 2023-02-11 09:39:44 +01:00
Nigel f5d402ad1b issue-51-telegram work in progress 2023-02-08 19:43:35 +01:00
Nigel 3152304679 issue-51-telegram work in progress 2023-02-08 19:39:10 +01:00
Nigel 98df0922e9 Merge branch 'master' into issue-51-telegram 2023-02-08 12:07:29 +01:00
Nigel ee2db04ec0 issue-51-telegram work in progress 2023-02-08 11:53:08 +01:00
Nigel ef66c8422c issue-51-telegram work in progress 2023-02-07 19:48:56 +01:00
Nigel f92836da2f issue-51-telegram WIP 2023-01-15 14:01:48 +01:00
Nigel 2adcd2b207 issue-51-telegram WIP 2023-01-15 13:59:15 +01:00
Nigel 3e0332963c issue-51-telegram work in progress 2023-01-14 19:47:24 +01:00
Nigel 29872ae6bb issue-51-telegram remove unused imports 2023-01-14 13:42:42 +01:00
Nigel d146565717 issue-51-telegram refactored TelegramParser.parse to return Telegram object. Telegram object now does not do parsing anymore. 2023-01-14 13:39:44 +01:00
5 changed files with 25 additions and 51 deletions
-10
View File
@@ -1,19 +1,9 @@
Change Log
----------
**1.2.2** (2023-04-12)
- Improve performance. Thanks to `ejpalacios <https://github.com/bdraco>`_ (`PR #130 <https://github.com/ndokter/dsmr_parser/pull/130>`_ by `ndokter <https://github.com/ndokter>`_)
**1.2.1** (2023-04-05)
- Bug/duplicate index BELGIUM_MAXIMUM_DEMAND_13_MONTHS (`PR #129 <https://github.com/ndokter/dsmr_parser/pull/129>`_ by `ejpalacios <https://github.com/ejpalacios>`_)
**1.2.0** (2023-02-18)
- Improved gas meter (mbus devices) support and replaced Telegram dictionary with backwards compatible object (`PR #121 <https://github.com/ndokter/dsmr_parser/pull/121>`_ by `ndokter <https://github.com/ndokter>`_)
- Fix parsing with invalid timestamps (`PR #125 <https://github.com/ndokter/dsmr_parser/pull/125>`_ by `dupondje <https://github.com/dupondje>`_)
- Add Iskra IE.x meters specification (`PR #126 <https://github.com/ndokter/dsmr_parser/pull/126>`_ by `jchevalier7 <https://github.com/jchevalier7>`_)
**1.1.0** (2023-02-08)
+20 -10
View File
@@ -1,13 +1,5 @@
import re
# - Match all characters after start of telegram except for the start
# itself again '^\/]+', which eliminates incomplete preceding telegrams.
# - Do non greedy match using '?' so start is matched up to the first
# checksum that's found.
# - The checksum is optional '{0,4}' because not all telegram versions
# support it.
_FIND_TELEGRAMS_REGEX = re.compile(r"\/[^\/]+?\![A-F0-9]{0,4}\0?\r\n", re.DOTALL)
class TelegramBuffer(object):
"""
@@ -16,14 +8,14 @@ class TelegramBuffer(object):
"""
def __init__(self):
self._buffer = ""
self._buffer = ''
def get_all(self):
"""
Remove complete telegrams from buffer and yield them.
:rtype generator:
"""
for telegram in _FIND_TELEGRAMS_REGEX.findall(self._buffer):
for telegram in self._find_telegrams():
self._remove(telegram)
yield telegram
@@ -45,3 +37,21 @@ class TelegramBuffer(object):
index = self._buffer.index(telegram) + len(telegram)
self._buffer = self._buffer[index:]
def _find_telegrams(self):
"""
Find complete telegrams in buffer from start ('/') till ending
checksum ('!AB12\r\n').
:rtype: list
"""
# - Match all characters after start of telegram except for the start
# itself again '^\/]+', which eliminates incomplete preceding telegrams.
# - Do non greedy match using '?' so start is matched up to the first
# checksum that's found.
# - The checksum is optional '{0,4}' because not all telegram versions
# support it.
return re.findall(
r'\/[^\/]+?\![A-F0-9]{0,4}\0?\r\n',
self._buffer,
re.DOTALL
)
+3 -8
View File
@@ -25,13 +25,8 @@ class TelegramParser(object):
telegram DSMR version (v4 and up).
:type telegram_specification: dict
"""
self.apply_checksum_validation = apply_checksum_validation
self.telegram_specification = telegram_specification
# Regexes are compiled once to improve performance
self.telegram_specification_regexes = {
signature: re.compile(signature, re.DOTALL)
for signature in self.telegram_specification['objects'].keys()
}
self.apply_checksum_validation = apply_checksum_validation
def parse(self, telegram_data, encryption_key="", authentication_key=""): # noqa: C901
"""
@@ -85,7 +80,7 @@ class TelegramParser(object):
telegram = Telegram()
for signature, parser in self.telegram_specification['objects'].items():
pattern = self.telegram_specification_regexes[signature]
pattern = re.compile(signature, re.DOTALL)
matches = pattern.findall(telegram_data)
# Some signatures are optional and may not be present,
@@ -263,7 +258,7 @@ class MaxDemandParser(DSMRObjectParser):
count = int(values[0])
for i in range(1, count + 1):
timestamp_month = ValueParser(timestamp).parse(values[i * 3 + 0])
timestamp_month = ValueParser(timestamp).parse(values[i * 3 + 1])
timestamp_occurred = ValueParser(timestamp).parse(values[i * 3 + 1])
value = ValueParser(Decimal).parse(values[i * 3 + 2])
objects.append(MBusObjectPeak(
+1 -1
View File
@@ -7,7 +7,7 @@ setup(
author_email='mail@nldr.net',
license='MIT',
url='https://github.com/ndokter/dsmr_parser',
version='1.2.2',
version='1.2.0',
packages=find_packages(exclude=('test', 'test.*')),
install_requires=[
'pyserial>=3,<4',
+1 -22
View File
@@ -37,7 +37,7 @@ class TelegramParserFluviusTest(unittest.TestCase):
assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None
assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime)
assert result[obis.P1_MESSAGE_TIMESTAMP].value == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 5, 12, 13, 54, 9))
datetime.datetime(2020, 5, 12, 11, 54, 9, tzinfo=pytz.UTC)
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
@@ -80,43 +80,22 @@ class TelegramParserFluviusTest(unittest.TestCase):
assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].unit == 'kW'
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value, Decimal)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value == Decimal('2.589')
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].datetime, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].datetime == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 5, 9, 13, 45, 58))
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 0
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0], MBusObjectPeak)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].unit == 'kW'
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value, Decimal)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value == Decimal('3.695')
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].datetime, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].datetime == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 5, 1, 0, 0, 0))
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].occurred, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].occurred == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 4, 23, 19, 25, 38))
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 1
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1], MBusObjectPeak)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].unit == 'kW'
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value, Decimal)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value == Decimal('5.980')
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].datetime, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].datetime == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 4, 1, 0, 0, 0))
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].occurred, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].occurred == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 3, 5, 12, 21, 39))
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 2
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2], MBusObjectPeak)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].unit == 'kW'
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value, Decimal)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value == Decimal('4.318')
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].datetime, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].datetime == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 3, 1, 0, 0, 0))
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].occurred, datetime.datetime)
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].occurred == \
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 2, 10, 3, 54, 21))
# CURRENT_ELECTRICITY_USAGE (1-0:1.7.0)
assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject)