Compare commits

..
34 Commits
Author SHA1 Message Date
Nigel b31bcd61fc Updated version number 2019-10-08 22:13:58 +02:00
Nigel Dokter 50a5cb9203 Merge pull request #37 from tneele/master
Improve performance: read more data from serial port at once
2019-07-29 10:13:13 +02:00
Thomas Neele 8388624721 Read more data from serial port at once
A telegram can contain dozens of lines. Reading them one by one is somewhat inefficient.
With this change, the client tries to read all data that is available.
This significantly reduced CPU load for me.
2019-07-22 21:33:15 +02:00
Nigel c04b0a5add Updated version number 2019-03-04 20:31:51 +01:00
Nigel Dokter ed2290a597 Merge pull request #33 from mleenaerts/patch-1
Fix DSMR v5.0 serial settings which were not used
2019-01-22 19:27:56 +01:00
Mark Leenaerts 85c67464a1 Fix DSMR v5.0 serial settings which were not used
While analysing some CRC check errors I encounter within the home-assistant plugin (which uses this component) I encountered this oversight in the code.
2019-01-19 16:11:12 +01:00
Nigel Dokter 48783acc00 Update CHANGELOG.rst 2018-09-23 13:01:22 +02:00
Nigel Dokter 41f6a7ac16 Update CHANGELOG.rst 2018-09-23 13:01:04 +02:00
Nigel Dokter 59811dbf9f Update setup.py 2018-09-23 12:59:02 +02:00
Nigel Dokter 9b09969763 Merge pull request #31 from tneele/master
Add serial settings for DSMR v5.0
2018-09-23 12:50:01 +02:00
Nigel Dokter 64f5dc2e87 Merge pull request #32 from bossjl/master
Lux-creos-obis-1.8.0
2018-09-23 12:49:42 +02:00
bossjl 887dd3a2aa Lux-creos-obis-1.8.0 2018-09-21 18:37:32 +02:00
Thomas Neele ad6ab304f5 Added serial settings for DSMR v5.0 2018-09-15 21:23:22 +02:00
Nigel Dokter 8582395017 Merge pull request #30 from jk-5/sagemcom-t210-d
Added missing values for 3-phase sagemcom TD210-D meter
2018-09-12 23:45:29 +02:00
jk-5 3327c78c0e Updated unittests 2018-09-06 15:49:11 +02:00
jk-5 472c54968e Corrected meter types 2018-09-06 15:40:02 +02:00
jk-5 d534b1d8b0 Added missing values for 3-phase sagemcom TD210-D meter 2018-09-06 14:53:30 +02:00
Nigel Dokter d94bc8de03 updated version 2017-09-18 12:02:36 +02:00
Nigel Dokter 41381f1705 Merge pull request #26 from vavdb/patch-1
Optional NUL after checksum
2017-09-18 11:55:31 +02:00
Vincent van den Braken e3203a5334 Optional NUL after checksum
My smart meter returns 00 0D 0A after the checksum, not just 0D 0A.
2017-09-15 13:48:10 +02:00
Nigel Dokter c78ebe3e2d fixed import errors 2017-06-05 21:06:48 +02:00
Nigel Dokter d6e28db116 log checksum errors as warning; dont force full telegram signatures; removed unused code for automatic telegram version detection; 2017-06-05 21:02:59 +02:00
Nigel Dokter 5f1afeb1f8 Merge pull request #25 from AlexMekkering/optional_telegram_lines
Support optional telegram signatures
2017-06-05 20:45:38 +02:00
Alex Mekkering dcb59fddb1 Support optional telegram signatures 2017-06-05 09:07:47 +02:00
Nigel Dokter 9b0a85e84b updated version 2017-05-12 21:37:54 +02:00
Nigel Dokter 1dca6ab396 Merge pull request #23 from aequitas/dsmr5
Add DSMR5 option to protocol.
2017-05-12 21:34:06 +02:00
Johan Bloemberg efc09df71f Add DSMR5 option to protocol. 2017-05-12 20:30:53 +02:00
Nigel Dokter de5c884d8d Small comment improvement 2017-02-27 20:44:18 +01:00
Nigel Dokter d2f57a8926 fixed pep8 2017-02-27 20:35:19 +01:00
Nigel Dokter 3d64fea247 Updated README 2017-02-27 20:26:15 +01:00
Nigel Dokter 46860e04c1 Formatting 2017-02-03 22:42:31 +01:00
Nigel Dokter 148bdabc12 Updated docs 2017-02-03 22:40:39 +01:00
Nigel Dokter 9d20bb8ad5 experimenting with version detection 2017-01-28 17:01:33 +01:00
Nigel Dokter 24ab9aa712 experimenting with version detection 2017-01-28 17:01:02 +01:00
13 changed files with 235 additions and 67 deletions
+27
View File
@@ -1,6 +1,33 @@
Change Log
----------
**0.14** (2019-10-08)
- Changed serial reading to reduce CPU usage (`pull request #37 <https://github.com/ndokter/dsmr_parser/pull/37>`_).
**0.13** (2019-03-04)
- Fix DSMR v5.0 serial settings which were not used (`pull request #33 <https://github.com/ndokter/dsmr_parser/pull/33>`_).
**0.12** (2018-09-23)
- Add serial settings for DSMR v5.0 (`pull request #31 <https://github.com/ndokter/dsmr_parser/pull/31>`_).
- Lux-creos-obis-1.8.0 (`pull request #32 <https://github.com/ndokter/dsmr_parser/pull/32>`_).
**0.11** (2017-09-18)
- NULL value fix in checksum (`pull request #26 <https://github.com/ndokter/dsmr_parser/pull/26>`_)
**0.10** (2017-06-05)
- bugix: don't force full telegram signatures (`pull request #25 <https://github.com/ndokter/dsmr_parser/pull/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
**0.9** (2017-05-12)
- added DSMR v5 serial settings
**0.8** (2017-01-26)
- added support for DSMR v3
+111 -26
View File
@@ -8,7 +8,7 @@ DSMR Parser
:target: https://travis-ci.org/ndokter/dsmr_parser
A library for parsing Dutch Smart Meter Requirements (DSMR) telegram data. It
also includes a serial client to directly read and parse smart meter data.
also includes client implementation to directly read and parse smart meter data.
Features
@@ -17,41 +17,126 @@ Features
DSMR Parser supports DSMR versions 2, 3, 4 and 5. It has been tested with Python 3.4, 3.5 and 3.6.
Examples
--------
Client module usage
-------------------
Using the serial reader to connect to your smart meter and parse it's telegrams:
**Serial client**
Read the serial port and work with the parsed telegrams. It should be run in a separate
process because the code is blocking (not asynchronous):
.. code-block:: python
from dsmr_parser import telegram_specifications
from dsmr_parser.clients import SerialReader, SERIAL_SETTINGS_V4
serial_reader = SerialReader(
device='/dev/ttyUSB0',
serial_settings=SERIAL_SETTINGS_V4,
telegram_specification=telegram_specifications.V4
)
for telegram in serial_reader.read():
print(telegram) # see 'Telegram object' docs below
**AsyncIO client**
To be documented.
Parsing module usage
--------------------
The parsing module accepts complete unaltered telegram strings and parses these
into a dictionary.
.. code-block:: python
from dsmr_parser import telegram_specifications
from dsmr_parser.parsers import TelegramParser
# String is formatted in separate lines for readability.
telegram_str = (
'/ISk5\2MT382-1000\r\n'
'\r\n'
'0-0:96.1.1(4B384547303034303436333935353037)\r\n'
'1-0:1.8.1(12345.678*kWh)\r\n'
'1-0:1.8.2(12345.678*kWh)\r\n'
'1-0:2.8.1(12345.678*kWh)\r\n'
'1-0:2.8.2(12345.678*kWh)\r\n'
'0-0:96.14.0(0002)\r\n'
'1-0:1.7.0(001.19*kW)\r\n'
'1-0:2.7.0(000.00*kW)\r\n'
'0-0:17.0.0(016*A)\r\n'
'0-0:96.3.10(1)\r\n'
'0-0:96.13.1(303132333435363738)\r\n'
'0-0:96.13.0(303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E'
'3F303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E3F30313233'
'3435363738393A3B3C3D3E3F)\r\n'
'0-1:96.1.0(3232323241424344313233343536373839)\r\n'
'0-1:24.1.0(03)\r\n'
'0-1:24.3.0(090212160000)(00)(60)(1)(0-1:24.2.1)(m3)\r\n'
'(00001.001)\r\n'
'0-1:24.4.0(1)\r\n'
'!\r\n'
)
parser = TelegramParser(telegram_specifications.V3)
telegram = parser.parse(telegram_str)
print(telegram) # see 'Telegram object' docs below
Telegram object
---------------
A dictionary of which the key indicates the field type. These regex values
correspond to one of dsmr_parser.obis_reference constants.
The value is either a CosemObject or MBusObject. These have a 'value' and 'unit'
property. MBusObject's additionally have a 'datetime' property. The 'value' can
contain any python type (int, str, Decimal) depending on the field. The 'unit'
contains 'kW', 'A', 'kWh' or 'm3'.
.. code-block:: python
# Contents of a parsed DSMR v3 telegram
{'\\d-\\d:17\\.0\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39eb8>,
'\\d-\\d:1\\.7\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10f916390>,
'\\d-\\d:1\\.8\\.1.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39e10>,
'\\d-\\d:1\\.8\\.2.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39ef0>,
'\\d-\\d:24\\.1\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fbaef28>,
'\\d-\\d:24\\.3\\.0.+?\\r\\n.+?\\r\\n': <dsmr_parser.objects.MBusObject object at 0x10f9163c8>,
'\\d-\\d:24\\.4\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39f60>,
'\\d-\\d:2\\.7\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39fd0>,
'\\d-\\d:2\\.8\\.1.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fbaee10>,
'\\d-\\d:2\\.8\\.2.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39e80>,
'\\d-\\d:96\\.13\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39d30>,
'\\d-\\d:96\\.13\\.1.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fbaeeb8>,
'\\d-\\d:96\\.14\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fbaef98>,
'\\d-\\d:96\\.1\\.0.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fbaef60>,
'\\d-\\d:96\\.1\\.1.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39f98>,
'\\d-\\d:96\\.3\\.10.+?\\r\\n': <dsmr_parser.objects.CosemObject object at 0x10fc39dd8>}
Example to get some of the values:
.. code-block:: python
from dsmr_parser import telegram_specifications
from dsmr_parser import obis_references
from dsmr_parser.clients import SerialReader, SERIAL_SETTINGS_V4
serial_reader = SerialReader(
device='/dev/ttyUSB0',
serial_settings=SERIAL_SETTINGS_V4,
telegram_specification=telegram_specifications.V4
)
# The telegram message timestamp.
message_datetime = telegram[obis_references.P1_MESSAGE_TIMESTAMP]
for telegram in serial_reader.read():
# Using the active tariff to determine the electricity being used and
# delivered for the right tariff.
active_tariff = telegram[obis_references.ELECTRICITY_ACTIVE_TARIFF]
active_tariff = int(tariff.value)
# The telegram message timestamp.
message_datetime = telegram[obis_references.P1_MESSAGE_TIMESTAMP]
electricity_used_total = telegram[obis_references.ELECTRICITY_USED_TARIFF_ALL[active_tariff - 1]]
electricity_delivered_total = telegram[obis_references.ELECTRICITY_DELIVERED_TARIFF_ALL[active_tariff - 1]]
# Using the active tariff to determine the electricity being used and
# delivered for the right tariff.
tariff = telegram[obis_references.ELECTRICITY_ACTIVE_TARIFF]
tariff = int(tariff.value)
gas_reading = telegram[obis_references.HOURLY_GAS_METER_READING]
electricity_used_total \
= telegram[obis_references.ELECTRICITY_USED_TARIFF_ALL[tariff - 1]]
electricity_delivered_total = \
telegram[obis_referencesELECTRICITY_DELIVERED_TARIFF_ALL[tariff - 1]]
gas_reading = telegram[obis_references.HOURLY_GAS_METER_READING]
# See dsmr_reader.obis_references for all readable telegram values.
# See dsmr_reader.obis_references for all readable telegram values.
# Note that the avilable values differ per DSMR version.
Installation
+1 -1
View File
@@ -1,5 +1,5 @@
from dsmr_parser.clients.settings import SERIAL_SETTINGS_V2_2, \
SERIAL_SETTINGS_V4
SERIAL_SETTINGS_V4, SERIAL_SETTINGS_V5
from dsmr_parser.clients.serial_ import SerialReader, AsyncSerialReader
from dsmr_parser.clients.protocol import create_dsmr_protocol, \
create_dsmr_reader, create_tcp_dsmr_reader
+7 -2
View File
@@ -8,10 +8,10 @@ from serial_asyncio import create_serial_connection
from dsmr_parser import telegram_specifications
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
from dsmr_parser.exceptions import ParseError
from dsmr_parser.exceptions import ParseError, InvalidChecksumError
from dsmr_parser.parsers import TelegramParser
from dsmr_parser.clients.settings import SERIAL_SETTINGS_V2_2, \
SERIAL_SETTINGS_V4
SERIAL_SETTINGS_V4, SERIAL_SETTINGS_V5
def create_dsmr_protocol(dsmr_version, telegram_callback, loop=None):
@@ -23,6 +23,9 @@ def create_dsmr_protocol(dsmr_version, telegram_callback, loop=None):
elif dsmr_version == '4':
specification = telegram_specifications.V4
serial_settings = SERIAL_SETTINGS_V4
elif dsmr_version == '5':
specification = telegram_specifications.V5
serial_settings = SERIAL_SETTINGS_V5
else:
raise NotImplementedError("No telegram parser found for version: %s",
dsmr_version)
@@ -98,6 +101,8 @@ class DSMRProtocol(asyncio.Protocol):
try:
parsed_telegram = self.telegram_parser.parse(telegram)
except InvalidChecksumError as e:
self.log.warning(str(e))
except ParseError:
self.log.exception("failed to parse telegram")
else:
+4 -2
View File
@@ -4,7 +4,7 @@ import serial
import serial_asyncio
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
from dsmr_parser.exceptions import ParseError
from dsmr_parser.exceptions import ParseError, InvalidChecksumError
from dsmr_parser.parsers import TelegramParser
@@ -30,12 +30,14 @@ class SerialReader(object):
"""
with serial.Serial(**self.serial_settings) as serial_handle:
while True:
data = serial_handle.readline()
data = serial_handle.read(max(1, min(1024, serial_handle.in_waiting)))
self.telegram_buffer.append(data.decode('ascii'))
for telegram in self.telegram_buffer.get_all():
try:
yield self.telegram_parser.parse(telegram)
except InvalidChecksumError as e:
logger.warning(str(e))
except ParseError as e:
logger.error('Failed to parse telegram: %s', e)
+10
View File
@@ -20,3 +20,13 @@ SERIAL_SETTINGS_V4 = {
'rtscts': 0,
'timeout': 20
}
SERIAL_SETTINGS_V5 = {
'baudrate': 115200,
'bytesize': serial.EIGHTBITS,
'parity': serial.PARITY_NONE,
'stopbits': serial.STOPBITS_ONE,
'xonxoff': 0,
'rtscts': 0,
'timeout': 20
}
+1 -1
View File
@@ -51,7 +51,7 @@ class TelegramBuffer(object):
# - The checksum is optional '{0,4}' because not all telegram versions
# support it.
return re.findall(
r'\/[^\/]+?\![A-F0-9]{0,4}\r\n',
r'\/[^\/]+?\![A-F0-9]{0,4}\0?\r\n',
self._buffer,
re.DOTALL
)
+8
View File
@@ -8,6 +8,7 @@ objects are introduced.
"""
P1_MESSAGE_HEADER = r'\d-\d:0\.2\.8.+?\r\n'
P1_MESSAGE_TIMESTAMP = r'\d-\d:1\.0\.0.+?\r\n'
ELECTRICITY_IMPORTED_TOTAL = r'\d-\d:1\.8\.0.+?\r\n'
ELECTRICITY_USED_TARIFF_1 = r'\d-\d:1\.8\.1.+?\r\n'
ELECTRICITY_USED_TARIFF_2 = r'\d-\d:1\.8\.2.+?\r\n'
ELECTRICITY_DELIVERED_TARIFF_1 = r'\d-\d:2\.8\.1.+?\r\n'
@@ -17,6 +18,7 @@ EQUIPMENT_IDENTIFIER = r'\d-\d:96\.1\.1.+?\r\n'
CURRENT_ELECTRICITY_USAGE = r'\d-\d:1\.7\.0.+?\r\n'
CURRENT_ELECTRICITY_DELIVERY = r'\d-\d:2\.7\.0.+?\r\n'
LONG_POWER_FAILURE_COUNT = r'96\.7\.9.+?\r\n'
SHORT_POWER_FAILURE_COUNT = r'96\.7\.21.+?\r\n'
POWER_EVENT_FAILURE_LOG = r'99\.97\.0.+?\r\n'
VOLTAGE_SAG_L1_COUNT = r'\d-\d:32\.32\.0.+?\r\n'
VOLTAGE_SAG_L2_COUNT = r'\d-\d:52\.32\.0.+?\r\n'
@@ -24,6 +26,12 @@ VOLTAGE_SAG_L3_COUNT = r'\d-\d:72\.32\.0.+?\r\n'
VOLTAGE_SWELL_L1_COUNT = r'\d-\d:32\.36\.0.+?\r\n'
VOLTAGE_SWELL_L2_COUNT = r'\d-\d:52\.36\.0.+?\r\n'
VOLTAGE_SWELL_L3_COUNT = r'\d-\d:72\.36\.0.+?\r\n'
INSTANTANEOUS_VOLTAGE_L1 = r'\d-\d:32\.7\.0.+?\r\n'
INSTANTANEOUS_VOLTAGE_L2 = r'\d-\d:52\.7\.0.+?\r\n'
INSTANTANEOUS_VOLTAGE_L3 = r'\d-\d:72\.7\.0.+?\r\n'
INSTANTANEOUS_CURRENT_L1 = r'\d-\d:31\.7\.0.+?\r\n'
INSTANTANEOUS_CURRENT_L2 = r'\d-\d:51\.7\.0.+?\r\n'
INSTANTANEOUS_CURRENT_L3 = r'\d-\d:71\.7\.0.+?\r\n'
TEXT_MESSAGE_CODE = r'\d-\d:96\.13\.1.+?\r\n'
TEXT_MESSAGE = r'\d-\d:96\.13\.0.+?\r\n'
DEVICE_TYPE = r'\d-\d:24\.1\.0.+?\r\n'
+3
View File
@@ -1,4 +1,7 @@
class DSMRObject(object):
"""
Represents all data from a single telegram line.
"""
def __init__(self, values):
self.values = values
+8 -5
View File
@@ -27,8 +27,8 @@ class TelegramParser(object):
The telegram str type makes python 2.x integration easier.
:param str telegram: full telegram from start ('/') to checksum
('!ABCD') including line endings inbetween the telegram's lines
:param str telegram_data: full telegram from start ('/') to checksum
('!ABCD') including line endings in between the telegram's lines
:rtype: dict
:returns: Shortened example:
{
@@ -51,6 +51,8 @@ class TelegramParser(object):
for signature, parser in self.telegram_specification['objects'].items():
match = re.search(signature, telegram_data, re.DOTALL)
# Some signatures are optional and may not be present,
# so only parse lines that match
if match:
telegram[signature] = parser.parse(match.group(0))
@@ -147,10 +149,11 @@ class CosemParser(DSMRObjectParser):
1 23 45
1) OBIS Reduced ID-code
2) Separator “(“, ASCII 28h
2) Separator "(", ASCII 28h
3) COSEM object attribute value
4) Unit of measurement values (Unit of capture objects attribute) – only if applicable
5) Separator “)”, ASCII 29h
4) Unit of measurement values (Unit of capture objects attribute) - only if
applicable
5) Separator ")", ASCII 29h
"""
def parse(self, line):
+11 -28
View File
@@ -42,34 +42,7 @@ V2_2 = {
}
}
V3 = {
'checksum_support': False,
'objects': {
obis.EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)),
obis.ELECTRICITY_USED_TARIFF_1: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_USED_TARIFF_2: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_DELIVERED_TARIFF_1: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_DELIVERED_TARIFF_2: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_ACTIVE_TARIFF: CosemParser(ValueParser(str)),
obis.CURRENT_ELECTRICITY_USAGE: CosemParser(ValueParser(Decimal)),
obis.CURRENT_ELECTRICITY_DELIVERY: CosemParser(ValueParser(Decimal)),
obis.ACTUAL_TRESHOLD_ELECTRICITY: CosemParser(ValueParser(Decimal)),
obis.ACTUAL_SWITCH_POSITION: CosemParser(ValueParser(str)),
obis.TEXT_MESSAGE_CODE: CosemParser(ValueParser(int)),
obis.TEXT_MESSAGE: CosemParser(ValueParser(str)),
obis.EQUIPMENT_IDENTIFIER_GAS: CosemParser(ValueParser(str)),
obis.DEVICE_TYPE: CosemParser(ValueParser(str)),
obis.VALVE_POSITION_GAS: CosemParser(ValueParser(str)),
obis.GAS_METER_READING: MBusParser(
ValueParser(timestamp),
ValueParser(int),
ValueParser(int),
ValueParser(int),
ValueParser(str),
ValueParser(Decimal),
),
}
}
V3 = V2_2
V4 = {
'checksum_support': True,
@@ -115,6 +88,7 @@ V5 = {
obis.P1_MESSAGE_HEADER: CosemParser(ValueParser(str)),
obis.P1_MESSAGE_TIMESTAMP: CosemParser(ValueParser(timestamp)),
obis.EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)),
obis.ELECTRICITY_IMPORTED_TOTAL: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_USED_TARIFF_1: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_USED_TARIFF_2: CosemParser(ValueParser(Decimal)),
obis.ELECTRICITY_DELIVERED_TARIFF_1: CosemParser(ValueParser(Decimal)),
@@ -123,6 +97,7 @@ V5 = {
obis.CURRENT_ELECTRICITY_USAGE: CosemParser(ValueParser(Decimal)),
obis.CURRENT_ELECTRICITY_DELIVERY: CosemParser(ValueParser(Decimal)),
obis.LONG_POWER_FAILURE_COUNT: CosemParser(ValueParser(int)),
obis.SHORT_POWER_FAILURE_COUNT: CosemParser(ValueParser(int)),
# POWER_EVENT_FAILURE_LOG: ProfileGenericParser(), TODO
obis.VOLTAGE_SAG_L1_COUNT: CosemParser(ValueParser(int)),
obis.VOLTAGE_SAG_L2_COUNT: CosemParser(ValueParser(int)),
@@ -130,6 +105,12 @@ V5 = {
obis.VOLTAGE_SWELL_L1_COUNT: CosemParser(ValueParser(int)),
obis.VOLTAGE_SWELL_L2_COUNT: CosemParser(ValueParser(int)),
obis.VOLTAGE_SWELL_L3_COUNT: CosemParser(ValueParser(int)),
obis.INSTANTANEOUS_VOLTAGE_L1: CosemParser(ValueParser(Decimal)),
obis.INSTANTANEOUS_VOLTAGE_L2: CosemParser(ValueParser(Decimal)),
obis.INSTANTANEOUS_VOLTAGE_L3: CosemParser(ValueParser(Decimal)),
obis.INSTANTANEOUS_CURRENT_L1: CosemParser(ValueParser(Decimal)),
obis.INSTANTANEOUS_CURRENT_L2: CosemParser(ValueParser(Decimal)),
obis.INSTANTANEOUS_CURRENT_L3: CosemParser(ValueParser(Decimal)),
obis.TEXT_MESSAGE: CosemParser(ValueParser(str)),
obis.DEVICE_TYPE: CosemParser(ValueParser(int)),
obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: CosemParser(ValueParser(Decimal)),
@@ -145,3 +126,5 @@ V5 = {
)
}
}
ALL = (V2_2, V3, V4, V5)
+2 -2
View File
@@ -4,9 +4,9 @@ setup(
name='dsmr-parser',
description='Library to parse Dutch Smart Meter Requirements (DSMR)',
author='Nigel Dokter',
author_email='nigeldokter@gmail.com',
author_email='nigel@nldr.net',
url='https://github.com/ndokter/dsmr_parser',
version='0.8',
version='0.14',
packages=find_packages(),
install_requires=[
'pyserial>=3,<4',
+42
View File
@@ -87,6 +87,12 @@ class TelegramParserV5Test(unittest.TestCase):
assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT].value, int)
assert result[obis.LONG_POWER_FAILURE_COUNT].value == 0
# SHORT_POWER_FAILURE_COUNT (1-0:96.7.21)
assert isinstance(result[obis.SHORT_POWER_FAILURE_COUNT], CosemObject)
assert result[obis.SHORT_POWER_FAILURE_COUNT].unit is None
assert isinstance(result[obis.SHORT_POWER_FAILURE_COUNT].value, int)
assert result[obis.SHORT_POWER_FAILURE_COUNT].value == 13
# VOLTAGE_SAG_L1_COUNT (1-0:32.32.0)
assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT], CosemObject)
assert result[obis.VOLTAGE_SAG_L1_COUNT].unit is None
@@ -123,6 +129,42 @@ class TelegramParserV5Test(unittest.TestCase):
assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT].value, int)
assert result[obis.VOLTAGE_SWELL_L3_COUNT].value == 0
# INSTANTANEOUS_VOLTAGE_L1 (1-0:32.7.0)
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1], CosemObject)
assert result[obis.INSTANTANEOUS_VOLTAGE_L1].unit == 'V'
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1].value, Decimal)
assert result[obis.INSTANTANEOUS_VOLTAGE_L1].value == Decimal('230.0')
# INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0)
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2], CosemObject)
assert result[obis.INSTANTANEOUS_VOLTAGE_L2].unit == 'V'
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2].value, Decimal)
assert result[obis.INSTANTANEOUS_VOLTAGE_L2].value == Decimal('230.0')
# INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0)
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3], CosemObject)
assert result[obis.INSTANTANEOUS_VOLTAGE_L3].unit == 'V'
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3].value, Decimal)
assert result[obis.INSTANTANEOUS_VOLTAGE_L3].value == Decimal('229.0')
# INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0)
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1], CosemObject)
assert result[obis.INSTANTANEOUS_CURRENT_L1].unit == 'A'
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1].value, Decimal)
assert result[obis.INSTANTANEOUS_CURRENT_L1].value == Decimal('0.48')
# INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0)
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2], CosemObject)
assert result[obis.INSTANTANEOUS_CURRENT_L2].unit == 'A'
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2].value, Decimal)
assert result[obis.INSTANTANEOUS_CURRENT_L2].value == Decimal('0.44')
# INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0)
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3], CosemObject)
assert result[obis.INSTANTANEOUS_CURRENT_L3].unit == 'A'
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3].value, Decimal)
assert result[obis.INSTANTANEOUS_CURRENT_L3].value == Decimal('0.86')
# TEXT_MESSAGE (0-0:96.13.0)
assert isinstance(result[obis.TEXT_MESSAGE], CosemObject)
assert result[obis.TEXT_MESSAGE].unit is None