Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a98c9ae4b7 | ||
|
|
14d9869fc3 | ||
|
|
36705f99ca | ||
|
|
0a6316e155 | ||
|
|
64787130bc | ||
|
|
929435c5fb | ||
|
|
d930c1082a | ||
|
|
b7f3af00b9 | ||
|
|
ad25fd4182 | ||
|
|
516850481d | ||
|
|
c7b9966083 | ||
|
|
8dee5edb0d | ||
|
|
7bda3de4d9 | ||
|
|
976681b929 | ||
|
|
0593d4172d | ||
|
|
47db8cad27 | ||
|
|
32854897d8 | ||
|
|
b527e991ef | ||
|
|
253d043b7b | ||
|
|
eab90e7049 | ||
|
|
3ae06f88b7 | ||
|
|
f5d402ad1b | ||
|
|
3152304679 | ||
|
|
98df0922e9 | ||
|
|
ee2db04ec0 | ||
|
|
ef66c8422c | ||
|
|
f92836da2f | ||
|
|
2adcd2b207 | ||
|
|
3e0332963c | ||
|
|
29872ae6bb | ||
|
|
d146565717 |
@@ -12,25 +12,23 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version:
|
python-version:
|
||||||
- '3.6'
|
|
||||||
- '3.7'
|
- '3.7'
|
||||||
- '3.8'
|
- '3.8'
|
||||||
- '3.9'
|
- '3.9'
|
||||||
- '3.10'
|
- '3.10'
|
||||||
- '3.11'
|
- '3.11'
|
||||||
- '3.12'
|
|
||||||
|
|
||||||
name: Python ${{ matrix.python-version }}
|
name: Python ${{ matrix.python-version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python-version }}
|
- name: Setup Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
- name: Cached PIP dependencies
|
- name: Cached PIP dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pip
|
~/.cache/pip
|
||||||
@@ -45,4 +43,4 @@ jobs:
|
|||||||
run: tox
|
run: tox
|
||||||
|
|
||||||
- name: Code coverage upload
|
- name: Code coverage upload
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v3
|
||||||
|
|||||||
@@ -1,55 +1,9 @@
|
|||||||
Change Log
|
Change Log
|
||||||
----------
|
----------
|
||||||
|
|
||||||
**1.4.2** (2024-07-14)
|
|
||||||
|
|
||||||
- Bump Github Actions to latest versions in favor of Node deprecations (`PR #159 <https://github.com/ndokter/dsmr_parser/pull/159>`_ by `dennissiemensma <https://github.com/dennissiemensma>`_)
|
|
||||||
- Swap pyserial-asyncio for pyserial-asyncio-fast (`PR #158 <https://github.com/ndokter/dsmr_parser/pull/158>`_ by `bdraco <https://github.com/bdraco>`_)
|
|
||||||
|
|
||||||
**1.4.1** (2024-06-04)
|
|
||||||
|
|
||||||
- Avoid loading timezone at runtime (`PR #157 <https://github.com/ndokter/dsmr_parser/pull/157>`_ by `elupus <https://github.com/elupus>`_)
|
|
||||||
|
|
||||||
**1.4.0** (2024-03-12)
|
|
||||||
|
|
||||||
- Mbus alt (`PR #142 <https://github.com/ndokter/dsmr_parser/pull/142>`_ by `dupondje <https://github.com/dupondje>`_)
|
|
||||||
- Q3D add CURRENT_ELECTRICITY_DELIVERY (`PR #149 <https://github.com/ndokter/dsmr_parser/pull/149>`_ by `Aeroid <https://github.com/Aeroid>`_)
|
|
||||||
- Copy head_parsers list on construct. (`PR #150 <https://github.com/ndokter/dsmr_parser/pull/150>`_ by `dupondje <https://github.com/dupondje>`_)
|
|
||||||
|
|
||||||
**1.3.2** (2024-01-29)
|
|
||||||
|
|
||||||
- Fix unit test for pyton 3.12 (`PR #148 <https://github.com/ndokter/dsmr_parser/pull/148>`_ by `ndokter <https://github.com/ndokter>`_)
|
|
||||||
|
|
||||||
**1.3.1** (2023-11-06)
|
|
||||||
|
|
||||||
- Fix parsing peak usage with invalid timestamps (`PR #143 <https://github.com/ndokter/dsmr_parser/pull/143>`_ by `dupondje <https://github.com/dupondje>`_)
|
|
||||||
|
|
||||||
**1.3.0** (2023-08-01)
|
|
||||||
|
|
||||||
- added E.ON Hungary; refactored DSMR specifications to fix obis reference conflicts (`PR #137 <https://github.com/ndokter/dsmr_parser/pull/137>`_ by `balazs92117 <https://github.com/balazs92117>`_)
|
|
||||||
|
|
||||||
**1.2.4** (2023-07-11)
|
|
||||||
|
|
||||||
- EQUIPMENT IDENTIFIER is wrong for Fluvius meters when other mbus devices are present (`PR #133 <https://github.com/ndokter/dsmr_parser/pull/133>`_ by `ejpalacios <https://github.com/ejpalacios>`_)
|
|
||||||
|
|
||||||
|
|
||||||
**1.2.3** (2023-04-18)
|
|
||||||
|
|
||||||
- Fix parsing tests and line start matching (`PR #132 <https://github.com/ndokter/dsmr_parser/pull/132>`_ by `dupondje <https://github.com/dupondje>`_)
|
|
||||||
|
|
||||||
**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)
|
**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>`_)
|
- 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)
|
**1.1.0** (2023-02-08)
|
||||||
|
|
||||||
|
|||||||
-30
@@ -293,36 +293,6 @@ To install DSMR Parser:
|
|||||||
|
|
||||||
$ pip install dsmr-parser
|
$ pip install dsmr-parser
|
||||||
|
|
||||||
Development
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Create a virtualenv and activate it followed by the installation of the dsmr-parser:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python3 -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -e .
|
|
||||||
|
|
||||||
Install tox and run it:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install tox
|
|
||||||
tox
|
|
||||||
|
|
||||||
You should see that the tests have succeeded:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
======================================================================================================== 59 passed in 0.91s ========================================================================================================
|
|
||||||
py: commands[1]> pylama dsmr_parser test
|
|
||||||
py: OK (11.55=setup[9.73]+cmd[1.29,0.53] seconds)
|
|
||||||
congratulations :) (11.69 seconds)
|
|
||||||
|
|
||||||
|
|
||||||
Now you can make changes by editing the code and rerunning tox to verify your changes.
|
|
||||||
|
|
||||||
Known issues
|
Known issues
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class FileReader(object):
|
|||||||
try:
|
try:
|
||||||
yield self.telegram_parser.parse(telegram)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.info(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
logger.error('Failed to parse telegram: %s', e)
|
logger.error('Failed to parse telegram: %s', e)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from functools import partial
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from serial_asyncio_fast import create_serial_connection
|
from serial_asyncio import create_serial_connection
|
||||||
|
|
||||||
from dsmr_parser import telegram_specifications
|
from dsmr_parser import telegram_specifications
|
||||||
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
|
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
|
||||||
@@ -21,9 +21,7 @@ def create_dsmr_protocol(dsmr_version, telegram_callback, loop=None, **kwargs):
|
|||||||
return protocol
|
return protocol
|
||||||
|
|
||||||
|
|
||||||
# pylama noqa - because of "complex" (too long) if-elif-else.
|
def _create_dsmr_protocol(dsmr_version, telegram_callback, protocol, loop=None, **kwargs):
|
||||||
# Match - case might be a solution but it is not available in <3.10
|
|
||||||
def _create_dsmr_protocol(dsmr_version, telegram_callback, protocol, loop=None, **kwargs): #noqa
|
|
||||||
"""Creates a DSMR asyncio protocol."""
|
"""Creates a DSMR asyncio protocol."""
|
||||||
|
|
||||||
if dsmr_version == '2.2':
|
if dsmr_version == '2.2':
|
||||||
@@ -53,9 +51,6 @@ def _create_dsmr_protocol(dsmr_version, telegram_callback, protocol, loop=None,
|
|||||||
elif dsmr_version == 'ISKRA_IE':
|
elif dsmr_version == 'ISKRA_IE':
|
||||||
specification = telegram_specifications.ISKRA_IE
|
specification = telegram_specifications.ISKRA_IE
|
||||||
serial_settings = SERIAL_SETTINGS_V5
|
serial_settings = SERIAL_SETTINGS_V5
|
||||||
elif dsmr_version == '5EONHU':
|
|
||||||
specification = telegram_specifications.EON_HUNGARY
|
|
||||||
serial_settings = SERIAL_SETTINGS_V5
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("No telegram parser found for version: %s",
|
raise NotImplementedError("No telegram parser found for version: %s",
|
||||||
dsmr_version)
|
dsmr_version)
|
||||||
@@ -158,7 +153,7 @@ class DSMRProtocol(asyncio.Protocol):
|
|||||||
try:
|
try:
|
||||||
parsed_telegram = self.telegram_parser.parse(telegram)
|
parsed_telegram = self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
self.log.info(str(e))
|
self.log.warning(str(e))
|
||||||
except ParseError:
|
except ParseError:
|
||||||
self.log.exception("failed to parse telegram")
|
self.log.exception("failed to parse telegram")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from serial_asyncio_fast import create_serial_connection
|
from serial_asyncio import create_serial_connection
|
||||||
from .protocol import DSMRProtocol, _create_dsmr_protocol
|
from .protocol import DSMRProtocol, _create_dsmr_protocol
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import serial
|
import serial
|
||||||
import serial_asyncio_fast
|
import serial_asyncio
|
||||||
|
|
||||||
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
|
from dsmr_parser.clients.telegram_buffer import TelegramBuffer
|
||||||
from dsmr_parser.exceptions import ParseError, InvalidChecksumError
|
from dsmr_parser.exceptions import ParseError, InvalidChecksumError
|
||||||
@@ -37,7 +37,7 @@ class SerialReader(object):
|
|||||||
try:
|
try:
|
||||||
yield self.telegram_parser.parse(telegram)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.info(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
logger.error('Failed to parse telegram: %s', e)
|
logger.error('Failed to parse telegram: %s', e)
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class AsyncSerialReader(SerialReader):
|
|||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
# create Serial StreamReader
|
# create Serial StreamReader
|
||||||
conn = serial_asyncio_fast.open_serial_connection(**self.serial_settings)
|
conn = serial_asyncio.open_serial_connection(**self.serial_settings)
|
||||||
reader, _ = await conn
|
reader, _ = await conn
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -107,7 +107,7 @@ class AsyncSerialReader(SerialReader):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# create Serial StreamReader
|
# create Serial StreamReader
|
||||||
conn = serial_asyncio_fast.open_serial_connection(**self.serial_settings)
|
conn = serial_asyncio.open_serial_connection(**self.serial_settings)
|
||||||
reader, _ = await conn
|
reader, _ = await conn
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -31,15 +31,11 @@ class SocketReader(object):
|
|||||||
buffer = b""
|
buffer = b""
|
||||||
|
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_handle:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_handle:
|
||||||
socket_handle.settimeout(60)
|
|
||||||
socket_handle.connect((self.host, self.port))
|
socket_handle.connect((self.host, self.port))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
buffer += socket_handle.recv(self.BUFFER_SIZE)
|
||||||
buffer += socket_handle.recv(self.BUFFER_SIZE)
|
|
||||||
except socket.timeout:
|
|
||||||
logger.error("Socket timeout occurred, exiting")
|
|
||||||
break
|
|
||||||
|
|
||||||
lines = buffer.splitlines(keepends=True)
|
lines = buffer.splitlines(keepends=True)
|
||||||
|
|
||||||
@@ -47,18 +43,13 @@ class SocketReader(object):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for data in lines:
|
for data in lines:
|
||||||
try:
|
self.telegram_buffer.append(data.decode('ascii'))
|
||||||
self.telegram_buffer.append(data.decode('ascii'))
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
# Some garbage came through the channel
|
|
||||||
# E.g.: Happens at EON_HUNGARY, but only once at the start of the socket.
|
|
||||||
logger.error('Failed to parse telegram due to unicode decode error')
|
|
||||||
|
|
||||||
for telegram in self.telegram_buffer.get_all():
|
for telegram in self.telegram_buffer.get_all():
|
||||||
try:
|
try:
|
||||||
yield self.telegram_parser.parse(telegram)
|
yield self.telegram_parser.parse(telegram)
|
||||||
except InvalidChecksumError as e:
|
except InvalidChecksumError as e:
|
||||||
logger.info(str(e))
|
logger.warning(str(e))
|
||||||
except ParseError as e:
|
except ParseError as e:
|
||||||
logger.error('Failed to parse telegram: %s', e)
|
logger.error('Failed to parse telegram: %s', e)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
import re
|
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):
|
class TelegramBuffer(object):
|
||||||
"""
|
"""
|
||||||
@@ -16,14 +8,14 @@ class TelegramBuffer(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._buffer = ""
|
self._buffer = ''
|
||||||
|
|
||||||
def get_all(self):
|
def get_all(self):
|
||||||
"""
|
"""
|
||||||
Remove complete telegrams from buffer and yield them.
|
Remove complete telegrams from buffer and yield them.
|
||||||
:rtype generator:
|
:rtype generator:
|
||||||
"""
|
"""
|
||||||
for telegram in _FIND_TELEGRAMS_REGEX.findall(self._buffer):
|
for telegram in self._find_telegrams():
|
||||||
self._remove(telegram)
|
self._remove(telegram)
|
||||||
yield telegram
|
yield telegram
|
||||||
|
|
||||||
@@ -45,3 +37,21 @@ class TelegramBuffer(object):
|
|||||||
index = self._buffer.index(telegram) + len(telegram)
|
index = self._buffer.index(telegram) + len(telegram)
|
||||||
|
|
||||||
self._buffer = self._buffer[index:]
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
from dsmr_parser import obis_references as obis
|
||||||
|
|
||||||
|
"""
|
||||||
|
dsmr_parser.obis_name_mapping
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This module contains a mapping of obis references to names.
|
||||||
|
"""
|
||||||
|
|
||||||
|
EN = {
|
||||||
|
obis.P1_MESSAGE_HEADER: 'P1_MESSAGE_HEADER',
|
||||||
|
obis.P1_MESSAGE_TIMESTAMP: 'P1_MESSAGE_TIMESTAMP',
|
||||||
|
obis.ELECTRICITY_IMPORTED_TOTAL: 'ELECTRICITY_IMPORTED_TOTAL',
|
||||||
|
obis.ELECTRICITY_REACTIVE_IMPORTED_TOTAL: 'ELECTRICITY_REACTIVE_IMPORTED_TOTAL',
|
||||||
|
obis.ELECTRICITY_USED_TARIFF_1: 'ELECTRICITY_USED_TARIFF_1',
|
||||||
|
obis.ELECTRICITY_USED_TARIFF_2: 'ELECTRICITY_USED_TARIFF_2',
|
||||||
|
obis.ELECTRICITY_EXPORTED_TOTAL: 'ELECTRICITY_EXPORTED_TOTAL',
|
||||||
|
obis.ELECTRICITY_REACTIVE_EXPORTED_TOTAL: 'ELECTRICITY_REACTIVE_EXPORTED_TOTAL',
|
||||||
|
obis.ELECTRICITY_DELIVERED_TARIFF_1: 'ELECTRICITY_DELIVERED_TARIFF_1',
|
||||||
|
obis.ELECTRICITY_DELIVERED_TARIFF_2: 'ELECTRICITY_DELIVERED_TARIFF_2',
|
||||||
|
obis.ELECTRICITY_ACTIVE_TARIFF: 'ELECTRICITY_ACTIVE_TARIFF',
|
||||||
|
obis.CURRENT_REACTIVE_EXPORTED: 'CURRENT_REACTIVE_EXPORTED',
|
||||||
|
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_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.CURRENT_ELECTRICITY_USAGE: 'CURRENT_ELECTRICITY_USAGE',
|
||||||
|
obis.CURRENT_ELECTRICITY_DELIVERY: 'CURRENT_ELECTRICITY_DELIVERY',
|
||||||
|
obis.LONG_POWER_FAILURE_COUNT: 'LONG_POWER_FAILURE_COUNT',
|
||||||
|
obis.SHORT_POWER_FAILURE_COUNT: 'SHORT_POWER_FAILURE_COUNT',
|
||||||
|
obis.POWER_EVENT_FAILURE_LOG: 'POWER_EVENT_FAILURE_LOG',
|
||||||
|
obis.VOLTAGE_SAG_L1_COUNT: 'VOLTAGE_SAG_L1_COUNT',
|
||||||
|
obis.VOLTAGE_SAG_L2_COUNT: 'VOLTAGE_SAG_L2_COUNT',
|
||||||
|
obis.VOLTAGE_SAG_L3_COUNT: 'VOLTAGE_SAG_L3_COUNT',
|
||||||
|
obis.VOLTAGE_SWELL_L1_COUNT: 'VOLTAGE_SWELL_L1_COUNT',
|
||||||
|
obis.VOLTAGE_SWELL_L2_COUNT: 'VOLTAGE_SWELL_L2_COUNT',
|
||||||
|
obis.VOLTAGE_SWELL_L3_COUNT: 'VOLTAGE_SWELL_L3_COUNT',
|
||||||
|
obis.INSTANTANEOUS_VOLTAGE_L1: 'INSTANTANEOUS_VOLTAGE_L1',
|
||||||
|
obis.INSTANTANEOUS_VOLTAGE_L2: 'INSTANTANEOUS_VOLTAGE_L2',
|
||||||
|
obis.INSTANTANEOUS_VOLTAGE_L3: 'INSTANTANEOUS_VOLTAGE_L3',
|
||||||
|
obis.INSTANTANEOUS_CURRENT_L1: 'INSTANTANEOUS_CURRENT_L1',
|
||||||
|
obis.INSTANTANEOUS_CURRENT_L2: 'INSTANTANEOUS_CURRENT_L2',
|
||||||
|
obis.INSTANTANEOUS_CURRENT_L3: 'INSTANTANEOUS_CURRENT_L3',
|
||||||
|
obis.TEXT_MESSAGE_CODE: 'TEXT_MESSAGE_CODE',
|
||||||
|
obis.TEXT_MESSAGE: 'TEXT_MESSAGE',
|
||||||
|
obis.DEVICE_TYPE: 'DEVICE_TYPE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: 'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: 'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE',
|
||||||
|
obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: 'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L1_POSITIVE: 'INSTANTANEOUS_REACTIVE_POWER_L1_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L1_NEGATIVE: 'INSTANTANEOUS_REACTIVE_POWER_L1_NEGATIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L2_POSITIVE: 'INSTANTANEOUS_REACTIVE_POWER_L2_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L2_NEGATIVE: 'INSTANTANEOUS_REACTIVE_POWER_L2_NEGATIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L3_POSITIVE: 'INSTANTANEOUS_REACTIVE_POWER_L3_POSITIVE',
|
||||||
|
obis.INSTANTANEOUS_REACTIVE_POWER_L3_NEGATIVE: 'INSTANTANEOUS_REACTIVE_POWER_L3_NEGATIVE',
|
||||||
|
obis.EQUIPMENT_IDENTIFIER_GAS: 'EQUIPMENT_IDENTIFIER_GAS',
|
||||||
|
obis.HOURLY_GAS_METER_READING: 'HOURLY_GAS_METER_READING',
|
||||||
|
obis.GAS_METER_READING: 'GAS_METER_READING',
|
||||||
|
obis.ACTUAL_TRESHOLD_ELECTRICITY: 'ACTUAL_TRESHOLD_ELECTRICITY',
|
||||||
|
obis.ACTUAL_SWITCH_POSITION: 'ACTUAL_SWITCH_POSITION',
|
||||||
|
obis.VALVE_POSITION_GAS: 'VALVE_POSITION_GAS',
|
||||||
|
obis.BELGIUM_VERSION_INFORMATION: 'BELGIUM_VERSION_INFORMATION',
|
||||||
|
obis.BELGIUM_EQUIPMENT_IDENTIFIER: 'BELGIUM_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.BELGIUM_CURRENT_AVERAGE_DEMAND: 'BELGIUM_CURRENT_AVERAGE_DEMAND',
|
||||||
|
obis.BELGIUM_MAXIMUM_DEMAND_MONTH: 'BELGIUM_MAXIMUM_DEMAND_MONTH',
|
||||||
|
obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS: 'BELGIUM_MAXIMUM_DEMAND_13_MONTHS',
|
||||||
|
obis.BELGIUM_MAX_POWER_PER_PHASE: 'BELGIUM_MAX_POWER_PER_PHASE',
|
||||||
|
obis.BELGIUM_MAX_CURRENT_PER_PHASE: 'BELGIUM_MAX_CURRENT_PER_PHASE',
|
||||||
|
obis.BELGIUM_MBUS1_DEVICE_TYPE: 'BELGIUM_MBUS1_DEVICE_TYPE',
|
||||||
|
obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.BELGIUM_MBUS1_VALVE_POSITION: 'BELGIUM_MBUS1_VALVE_POSITION',
|
||||||
|
obis.BELGIUM_MBUS1_METER_READING1: 'BELGIUM_MBUS1_METER_READING1',
|
||||||
|
obis.BELGIUM_MBUS1_METER_READING2: 'BELGIUM_MBUS1_METER_READING2',
|
||||||
|
obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.BELGIUM_MBUS2_VALVE_POSITION: 'BELGIUM_MBUS2_VALVE_POSITION',
|
||||||
|
obis.BELGIUM_MBUS2_METER_READING1: 'BELGIUM_MBUS2_METER_READING1',
|
||||||
|
obis.BELGIUM_MBUS2_METER_READING2: 'BELGIUM_MBUS2_METER_READING2',
|
||||||
|
obis.BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.BELGIUM_MBUS3_VALVE_POSITION: 'BELGIUM_MBUS3_VALVE_POSITION',
|
||||||
|
obis.BELGIUM_MBUS3_METER_READING1: 'BELGIUM_MBUS3_METER_READING1',
|
||||||
|
obis.BELGIUM_MBUS3_METER_READING2: 'BELGIUM_MBUS3_METER_READING2',
|
||||||
|
obis.BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.BELGIUM_MBUS4_VALVE_POSITION: 'BELGIUM_MBUS4_VALVE_POSITION',
|
||||||
|
obis.BELGIUM_MBUS4_METER_READING1: 'BELGIUM_MBUS4_METER_READING1',
|
||||||
|
obis.BELGIUM_MBUS4_METER_READING2: 'BELGIUM_MBUS4_METER_READING2',
|
||||||
|
obis.LUXEMBOURG_EQUIPMENT_IDENTIFIER: 'LUXEMBOURG_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER',
|
||||||
|
obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE',
|
||||||
|
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()])
|
||||||
+97
-105
@@ -6,88 +6,64 @@ refactored to full line signatures to maintain backwards compatibility.
|
|||||||
Might be refactored in a backwards incompatible way as soon as proper telegram
|
Might be refactored in a backwards incompatible way as soon as proper telegram
|
||||||
objects are introduced.
|
objects are introduced.
|
||||||
"""
|
"""
|
||||||
P1_MESSAGE_HEADER = r'^\d-\d:0\.2\.8.+?\r\n'
|
P1_MESSAGE_HEADER = r'\d-\d:0\.2\.8.+?\r\n'
|
||||||
P1_MESSAGE_TIMESTAMP = r'^\d-\d:1\.0\.0.+?\r\n'
|
P1_MESSAGE_TIMESTAMP = r'\d-\d:1\.0\.0.+?\r\n'
|
||||||
ELECTRICITY_USED_TARIFF_1 = r'^\d-\d:1\.8\.1.+?\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_USED_TARIFF_2 = r'\d-\d:1\.8\.2.+?\r\n'
|
||||||
ELECTRICITY_USED_TARIFF_3 = r'^\d-\d:1\.8\.3.+?\r\n'
|
ELECTRICITY_DELIVERED_TARIFF_1 = r'\d-\d:2\.8\.1.+?\r\n'
|
||||||
ELECTRICITY_USED_TARIFF_4 = r'^\d-\d:1\.8\.4.+?\r\n'
|
ELECTRICITY_DELIVERED_TARIFF_2 = r'\d-\d:2\.8\.2.+?\r\n'
|
||||||
ELECTRICITY_DELIVERED_TARIFF_1 = r'^\d-\d:2\.8\.1.+?\r\n'
|
CURRENT_REACTIVE_IMPORTED = r'\d-\d:3\.7\.0.+?\r\n'
|
||||||
ELECTRICITY_DELIVERED_TARIFF_2 = r'^\d-\d:2\.8\.2.+?\r\n'
|
ELECTRICITY_REACTIVE_IMPORTED_TOTAL = r'\d-\d:3\.8\.0.+?\r\n'
|
||||||
ELECTRICITY_DELIVERED_TARIFF_3 = r'^\d-\d:2\.8\.3.+?\r\n'
|
ELECTRICITY_REACTIVE_IMPORTED_TARIFF_1 = r'\d-\d:3\.8\.1.+?\r\n'
|
||||||
ELECTRICITY_DELIVERED_TARIFF_4 = r'^\d-\d:2\.8\.4.+?\r\n'
|
ELECTRICITY_REACTIVE_IMPORTED_TARIFF_2 = r'\d-\d:3\.8\.2.+?\r\n'
|
||||||
CURRENT_REACTIVE_IMPORTED = r'^\d-\d:3\.7\.0.+?\r\n'
|
CURRENT_REACTIVE_EXPORTED = r'\d-\d:4\.7\.0.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_IMPORTED_TOTAL = r'^\d-\d:3\.8\.0.+?\r\n'
|
ELECTRICITY_REACTIVE_EXPORTED_TOTAL = r'\d-\d:4\.8\.0.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_IMPORTED_TARIFF_1 = r'^\d-\d:3\.8\.1.+?\r\n'
|
ELECTRICITY_REACTIVE_EXPORTED_TARIFF_1 = r'\d-\d:4\.8\.1.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_IMPORTED_TARIFF_2 = r'^\d-\d:3\.8\.2.+?\r\n'
|
ELECTRICITY_REACTIVE_EXPORTED_TARIFF_2 = r'\d-\d:4\.8\.2.+?\r\n'
|
||||||
CURRENT_REACTIVE_EXPORTED = r'^\d-\d:4\.7\.0.+?\r\n'
|
ELECTRICITY_ACTIVE_TARIFF = r'\d-\d:96\.14\.0.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_EXPORTED_TOTAL = r'^\d-\d:4\.8\.0.+?\r\n'
|
EQUIPMENT_IDENTIFIER = r'\d-\d:96\.1\.1.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_EXPORTED_TARIFF_1 = r'^\d-\d:4\.8\.1.+?\r\n'
|
CURRENT_ELECTRICITY_USAGE = r'\d-\d:1\.7\.0.+?\r\n'
|
||||||
ELECTRICITY_REACTIVE_EXPORTED_TARIFF_2 = r'^\d-\d:4\.8\.2.+?\r\n'
|
CURRENT_ELECTRICITY_DELIVERY = r'\d-\d:2\.7\.0.+?\r\n'
|
||||||
ELECTRICITY_ACTIVE_TARIFF = r'^\d-\d:96\.14\.0.+?\r\n'
|
LONG_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.9.+?\r\n'
|
||||||
EQUIPMENT_IDENTIFIER = r'^\d-\d:96\.1\.1.+?\r\n'
|
SHORT_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.21.+?\r\n'
|
||||||
CURRENT_ELECTRICITY_USAGE = r'^\d-\d:1\.7\.0.+?\r\n'
|
POWER_EVENT_FAILURE_LOG = r'\d-\d:99\.97\.0.+?\r\n'
|
||||||
CURRENT_ELECTRICITY_DELIVERY = r'^\d-\d:2\.7\.0.+?\r\n'
|
VOLTAGE_SAG_L1_COUNT = r'\d-\d:32\.32\.0.+?\r\n'
|
||||||
LONG_POWER_FAILURE_COUNT = r'^\d-\d:96\.7\.9.+?\r\n'
|
VOLTAGE_SAG_L2_COUNT = r'\d-\d:52\.32\.0.+?\r\n'
|
||||||
SHORT_POWER_FAILURE_COUNT = r'^\d-\d:96\.7\.21.+?\r\n'
|
VOLTAGE_SAG_L3_COUNT = r'\d-\d:72\.32\.0.+?\r\n'
|
||||||
POWER_EVENT_FAILURE_LOG = r'^\d-\d:99\.97\.0.+?\r\n'
|
VOLTAGE_SWELL_L1_COUNT = r'\d-\d:32\.36\.0.+?\r\n'
|
||||||
VOLTAGE_SAG_L1_COUNT = r'^\d-\d:32\.32\.0.+?\r\n'
|
VOLTAGE_SWELL_L2_COUNT = r'\d-\d:52\.36\.0.+?\r\n'
|
||||||
VOLTAGE_SAG_L2_COUNT = r'^\d-\d:52\.32\.0.+?\r\n'
|
VOLTAGE_SWELL_L3_COUNT = r'\d-\d:72\.36\.0.+?\r\n'
|
||||||
VOLTAGE_SAG_L3_COUNT = r'^\d-\d:72\.32\.0.+?\r\n'
|
INSTANTANEOUS_VOLTAGE_L1 = r'\d-\d:32\.7\.0.+?\r\n'
|
||||||
VOLTAGE_SWELL_L1_COUNT = r'^\d-\d:32\.36\.0.+?\r\n'
|
INSTANTANEOUS_VOLTAGE_L2 = r'\d-\d:52\.7\.0.+?\r\n'
|
||||||
VOLTAGE_SWELL_L2_COUNT = r'^\d-\d:52\.36\.0.+?\r\n'
|
INSTANTANEOUS_VOLTAGE_L3 = r'\d-\d:72\.7\.0.+?\r\n'
|
||||||
VOLTAGE_SWELL_L3_COUNT = r'^\d-\d:72\.36\.0.+?\r\n'
|
INSTANTANEOUS_CURRENT_L1 = r'\d-\d:31\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_VOLTAGE_L1 = r'^\d-\d:32\.7\.0.+?\r\n'
|
INSTANTANEOUS_CURRENT_L2 = r'\d-\d:51\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_VOLTAGE_L2 = r'^\d-\d:52\.7\.0.+?\r\n'
|
INSTANTANEOUS_CURRENT_L3 = r'\d-\d:71\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_VOLTAGE_L3 = r'^\d-\d:72\.7\.0.+?\r\n'
|
TEXT_MESSAGE_CODE = r'\d-\d:96\.13\.1.+?\r\n'
|
||||||
INSTANTANEOUS_CURRENT_L1 = r'^\d-\d:31\.7\.0.+?\r\n'
|
TEXT_MESSAGE = r'\d-\d:96\.13\.0.+?\r\n'
|
||||||
INSTANTANEOUS_CURRENT_L2 = r'^\d-\d:51\.7\.0.+?\r\n'
|
DEVICE_TYPE = r'\d-\d:24\.1\.0.+?\r\n'
|
||||||
INSTANTANEOUS_CURRENT_L3 = r'^\d-\d:71\.7\.0.+?\r\n'
|
INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE = r'\d-\d:21\.7\.0.+?\r\n'
|
||||||
FUSE_THRESHOLD_L1 = r'^\d-\d:31\.4\.0.+?\r\n' # Applicable when current limitation is active
|
INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE = r'\d-\d:41\.7\.0.+?\r\n'
|
||||||
FUSE_THRESHOLD_L2 = r'^\d-\d:51\.4\.0.+?\r\n' # Applicable when current limitation is active
|
INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE = r'\d-\d:61\.7\.0.+?\r\n'
|
||||||
FUSE_THRESHOLD_L3 = r'^\d-\d:71\.4\.0.+?\r\n' # Applicable when current limitation is active
|
INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE = r'\d-\d:22\.7\.0.+?\r\n'
|
||||||
TEXT_MESSAGE_CODE = r'^\d-\d:96\.13\.1.+?\r\n'
|
INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE = r'\d-\d:42\.7\.0.+?\r\n'
|
||||||
TEXT_MESSAGE = r'^\d-\d:96\.13\.0.+?\r\n'
|
INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE = r'\d-\d:62\.7\.0.+?\r\n'
|
||||||
DEVICE_TYPE = r'^\d-\d:24\.1\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L1_POSITIVE = r'\d-\d:23\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE = r'^\d-\d:21\.7\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L1_NEGATIVE = r'\d-\d:24\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE = r'^\d-\d:41\.7\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L2_POSITIVE = r'\d-\d:43\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE = r'^\d-\d:61\.7\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L2_NEGATIVE = r'\d-\d:44\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE = r'^\d-\d:22\.7\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L3_POSITIVE = r'\d-\d:63\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE = r'^\d-\d:42\.7\.0.+?\r\n'
|
INSTANTANEOUS_REACTIVE_POWER_L3_NEGATIVE = r'\d-\d:64\.7\.0.+?\r\n'
|
||||||
INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE = r'^\d-\d:62\.7\.0.+?\r\n'
|
EQUIPMENT_IDENTIFIER_GAS = r'\d-\d:96\.1\.0.+?\r\n'
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L1_POSITIVE = r'^\d-\d:23\.7\.0.+?\r\n'
|
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L1_NEGATIVE = r'^\d-\d:24\.7\.0.+?\r\n'
|
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L2_POSITIVE = r'^\d-\d:43\.7\.0.+?\r\n'
|
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L2_NEGATIVE = r'^\d-\d:44\.7\.0.+?\r\n'
|
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L3_POSITIVE = r'^\d-\d:63\.7\.0.+?\r\n'
|
|
||||||
INSTANTANEOUS_REACTIVE_POWER_L3_NEGATIVE = r'^\d-\d:64\.7\.0.+?\r\n'
|
|
||||||
EQUIPMENT_IDENTIFIER_GAS = r'^\d-\d:96\.1\.0.+?\r\n'
|
|
||||||
# TODO differences between gas meter readings in v3 and lower and v4 and up
|
# TODO differences between gas meter readings in v3 and lower and v4 and up
|
||||||
HOURLY_GAS_METER_READING = r'^\d-\d:24\.2\.1.+?\r\n'
|
HOURLY_GAS_METER_READING = r'\d-\d:24\.2\.1.+?\r\n'
|
||||||
GAS_METER_READING = r'^\d-\d:24\.3\.0.+?\r\n.+?\r\n'
|
GAS_METER_READING = r'\d-\d:24\.3\.0.+?\r\n.+?\r\n'
|
||||||
ACTUAL_TRESHOLD_ELECTRICITY = r'^\d-\d:17\.0\.0.+?\r\n'
|
ACTUAL_TRESHOLD_ELECTRICITY = r'\d-\d:17\.0\.0.+?\r\n'
|
||||||
ACTUAL_SWITCH_POSITION = r'^\d-\d:96\.3\.10.+?\r\n'
|
ACTUAL_SWITCH_POSITION = r'\d-\d:96\.3\.10.+?\r\n'
|
||||||
VALVE_POSITION_GAS = r'^\d-\d:24\.4\.0.+?\r\n'
|
VALVE_POSITION_GAS = r'\d-\d:24\.4\.0.+?\r\n'
|
||||||
|
|
||||||
# Multiple 'slaves' can be linked to the main device.
|
|
||||||
# The type is reported on 24.1.0
|
|
||||||
# Specifications are in EN 13757-3
|
|
||||||
# For example: Water mater = 7, Gas meter = 3
|
|
||||||
# Identifier is on 96.1.0 (in NL for ex) or
|
|
||||||
# on 96.1.1 (in BE for ex)
|
|
||||||
# The values are reported on 24.2.1
|
|
||||||
# With an exception in Belgium for the GAS meter
|
|
||||||
# Be aware that for the gas volume, another OBIS-code is published
|
|
||||||
# than the one listed in section 7 of DSMR P1.
|
|
||||||
# This is due to the fact that in Belgium the not-temperature
|
|
||||||
# corrected gas volume is used while in the Netherlands,
|
|
||||||
# the temperature corrected gas volume is used.
|
|
||||||
MBUS_DEVICE_TYPE = r'^\d-[1-9]:24\.1\.0.+?\r\n'
|
|
||||||
MBUS_EQUIPMENT_IDENTIFIER = r'^\d-[1-9]:96\.1\.[01].+?\r\n'
|
|
||||||
MBUS_VALVE_POSITION = r'^\d-[1-9]:24\.4\.0.+?\r\n'
|
|
||||||
MBUS_METER_READING = r'^\d-[1-9]:24\.2\.[13].+?\r\n'
|
|
||||||
|
|
||||||
# TODO 17.0.0
|
# TODO 17.0.0
|
||||||
|
# TODO 96.3.10
|
||||||
|
|
||||||
ELECTRICITY_USED_TARIFF_ALL = (
|
ELECTRICITY_USED_TARIFF_ALL = (
|
||||||
ELECTRICITY_USED_TARIFF_1,
|
ELECTRICITY_USED_TARIFF_1,
|
||||||
@@ -99,34 +75,50 @@ ELECTRICITY_DELIVERED_TARIFF_ALL = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# International generalized additions
|
# International generalized additions
|
||||||
ELECTRICITY_IMPORTED_TOTAL = r'^\d-\d:1\.8\.0.+?\r\n' # Total imported energy register (P+)
|
ELECTRICITY_IMPORTED_TOTAL = r'\d-\d:1\.8\.0.+?\r\n' # Total imported energy register (P+)
|
||||||
ELECTRICITY_EXPORTED_TOTAL = r'^\d-\d:2\.8\.0.+?\r\n' # Total exported energy register (P-)
|
ELECTRICITY_EXPORTED_TOTAL = r'\d-\d:2\.8\.0.+?\r\n' # Total exported energy register (P-)
|
||||||
|
|
||||||
# International non generalized additions (country specific) / risk for necessary refactoring
|
# International non generalized additions (country specific) / risk for necessary refactoring
|
||||||
BELGIUM_VERSION_INFORMATION = r'^\d-\d:96\.1\.4.+?\r\n'
|
BELGIUM_VERSION_INFORMATION = r'\d-\d:96\.1\.4.+?\r\n'
|
||||||
BELGIUM_EQUIPMENT_IDENTIFIER = r'^\d-0:96\.1\.1.+?\r\n'
|
BELGIUM_EQUIPMENT_IDENTIFIER = r'\d-0:96\.1\.1.+?\r\n'
|
||||||
BELGIUM_CURRENT_AVERAGE_DEMAND = r'^\d-\d:1\.4\.0.+?\r\n'
|
BELGIUM_CURRENT_AVERAGE_DEMAND = r'\d-\d:1\.4\.0.+?\r\n'
|
||||||
BELGIUM_MAXIMUM_DEMAND_MONTH = r'^\d-\d:1\.6\.0.+?\r\n'
|
BELGIUM_MAXIMUM_DEMAND_MONTH = r'\d-\d:1\.6\.0.+?\r\n'
|
||||||
BELGIUM_MAXIMUM_DEMAND_13_MONTHS = r'^\d-\d:98\.1\.0.+?\r\n'
|
BELGIUM_MAXIMUM_DEMAND_13_MONTHS = r'\d-\d:98\.1\.0.+?\r\n'
|
||||||
|
BELGIUM_MAX_POWER_PER_PHASE = r'\d-\d:17\.0\.0.+?\r\n' # Applicable when power limitation is active
|
||||||
|
BELGIUM_MAX_CURRENT_PER_PHASE = r'\d-\d:31\.4\.0.+?\r\n' # Applicable when current limitation is active
|
||||||
|
|
||||||
LUXEMBOURG_EQUIPMENT_IDENTIFIER = r'^\d-\d:42\.0\.0.+?\r\n' # Logical device name
|
# Multiple 'slaves' can be linked to the main device.
|
||||||
|
# Mostly MBUS1 = GAS METER with values on 24.2.3
|
||||||
|
# While WATER METER reports it's values on 24.2.1
|
||||||
|
# The GAS METER also reports its valve state on 24.4.0
|
||||||
|
# Dev type for gas = 7 and water = 8
|
||||||
|
BELGIUM_MBUS1_DEVICE_TYPE = r'\d-1:24\.1\.0.+?\r\n'
|
||||||
|
BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER = r'\d-1:96\.1\.1.+?\r\n'
|
||||||
|
BELGIUM_MBUS1_VALVE_POSITION = r'\d-1:24\.4\.0.+?\r\n'
|
||||||
|
BELGIUM_MBUS1_METER_READING1 = r'\d-1:24\.2\.1.+?\r\n'
|
||||||
|
BELGIUM_MBUS1_METER_READING2 = r'\d-1:24\.2\.3.+?\r\n'
|
||||||
|
|
||||||
Q3D_EQUIPMENT_IDENTIFIER = r'^\d-\d:0\.0\.0.+?\r\n' # Logical device name
|
BELGIUM_MBUS2_DEVICE_TYPE = r'\d-2:24\.1\.0.+?\r\n'
|
||||||
Q3D_EQUIPMENT_STATE = r'^\d-\d:96\.5\.5.+?\r\n' # Device state (hexadecimal)
|
BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER = r'\d-2:96\.1\.1.+?\r\n'
|
||||||
Q3D_EQUIPMENT_SERIALNUMBER = r'^\d-\d:96\.1\.255.+?\r\n' # Device Serialnumber
|
BELGIUM_MBUS2_VALVE_POSITION = r'\d-2:24\.4\.0.+?\r\n'
|
||||||
|
BELGIUM_MBUS2_METER_READING1 = r'\d-2:24\.2\.1.+?\r\n'
|
||||||
|
BELGIUM_MBUS2_METER_READING2 = r'\d-2:24\.2\.3.+?\r\n'
|
||||||
|
|
||||||
# EON Hungary
|
BELGIUM_MBUS3_DEVICE_TYPE = r'\d-3:24\.1\.0.+?\r\n'
|
||||||
EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q1 = r'^\d-\d:5\.8\.0.+?\r\n'
|
BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER = r'\d-3:96\.1\.1.+?\r\n'
|
||||||
EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q2 = r'^\d-\d:6\.8\.0.+?\r\n'
|
BELGIUM_MBUS3_VALVE_POSITION = r'\d-3:24\.4\.0.+?\r\n'
|
||||||
EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q3 = r'^\d-\d:7\.8\.0.+?\r\n'
|
BELGIUM_MBUS3_METER_READING1 = r'\d-3:24\.2\.1.+?\r\n'
|
||||||
EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q4 = r'^\d-\d:8\.8\.0.+?\r\n'
|
BELGIUM_MBUS3_METER_READING2 = r'\d-3:24\.2\.3.+?\r\n'
|
||||||
EON_HU_ELECTRICITY_COMBINED = r'^\d-\d:15\.8\.0.+?\r\n'
|
|
||||||
EON_HU_INSTANTANEOUS_POWER_FACTOR_TOTAL = r'^\d-\d:13\.7\.0.+?\r\n'
|
BELGIUM_MBUS4_DEVICE_TYPE = r'\d-4:24\.1\.0.+?\r\n'
|
||||||
EON_HU_INSTANTANEOUS_POWER_FACTOR_L1 = r'^\d-\d:33\.7\.0.+?\r\n'
|
BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER = r'\d-4:96\.1\.1.+?\r\n'
|
||||||
EON_HU_INSTANTANEOUS_POWER_FACTOR_L2 = r'^\d-\d:53\.7\.0.+?\r\n'
|
BELGIUM_MBUS4_VALVE_POSITION = r'\d-4:24\.4\.0.+?\r\n'
|
||||||
EON_HU_INSTANTANEOUS_POWER_FACTOR_L3 = r'^\d-\d:73\.7\.0.+?\r\n'
|
BELGIUM_MBUS4_METER_READING1 = r'\d-4:24\.2\.1.+?\r\n'
|
||||||
EON_HU_FREQUENCY = r'^\d-\d:14\.7\.0.+?\r\n'
|
BELGIUM_MBUS4_METER_READING2 = r'\d-4:24\.2\.3.+?\r\n'
|
||||||
EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q1 = r'^\d-\d:5\.7\.0.+?\r\n'
|
|
||||||
EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q2 = r'^\d-\d:6\.7\.0.+?\r\n'
|
|
||||||
EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q3 = r'^\d-\d:7\.7\.0.+?\r\n'
|
LUXEMBOURG_EQUIPMENT_IDENTIFIER = r'\d-\d:42\.0\.0.+?\r\n' # Logical device name
|
||||||
EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q4 = r'^\d-\d:8\.7\.0.+?\r\n'
|
|
||||||
|
Q3D_EQUIPMENT_IDENTIFIER = r'\d-\d:0\.0\.0.+?\r\n' # Logical device name
|
||||||
|
Q3D_EQUIPMENT_STATE = r'\d-\d:96\.5\.5.+?\r\n' # Device state (hexadecimal)
|
||||||
|
Q3D_EQUIPMENT_SERIALNUMBER = r'\d-\d:96\.1\.255.+?\r\n' # Device Serialnumber
|
||||||
|
|||||||
+28
-37
@@ -5,6 +5,8 @@ import json
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
from dsmr_parser import obis_name_mapping
|
||||||
|
|
||||||
|
|
||||||
class Telegram(dict):
|
class Telegram(dict):
|
||||||
"""
|
"""
|
||||||
@@ -25,21 +27,22 @@ class Telegram(dict):
|
|||||||
self._mbus_devices = []
|
self._mbus_devices = []
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def add(self, obis_reference, dsmr_object, obis_name):
|
def add(self, obis_reference, dsmr_object):
|
||||||
# Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER
|
# Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER
|
||||||
|
obis_name = obis_name_mapping.EN[obis_reference]
|
||||||
setattr(self, obis_name, dsmr_object)
|
setattr(self, obis_name, dsmr_object)
|
||||||
|
if obis_name not in self._item_names: # TODO repeating obis references
|
||||||
|
self._item_names.append(obis_name)
|
||||||
|
|
||||||
# TODO isinstance check: MaxDemandParser (BELGIUM_MAXIMUM_DEMAND_13_MONTHS) returns a list
|
# TODO isinstance check: MaxDemandParser (BELGIUM_MAXIMUM_DEMAND_13_MONTHS) returns a list
|
||||||
if isinstance(dsmr_object, DSMRObject) and dsmr_object.is_mbus_reading:
|
if isinstance(dsmr_object, DSMRObject) and dsmr_object.is_mbus_reading:
|
||||||
self._add_mbus(obis_reference, dsmr_object, obis_name)
|
self._add_mbus(obis_reference, dsmr_object)
|
||||||
elif obis_name not in self._item_names: # TODO repeating obis references
|
|
||||||
self._item_names.append(obis_name)
|
|
||||||
|
|
||||||
# Fill dict which is only used for backwards compatibility
|
# Fill dict which is only used for backwards compatibility
|
||||||
if obis_reference not in self:
|
if obis_reference not in self:
|
||||||
self[obis_reference] = dsmr_object
|
self[obis_reference] = dsmr_object
|
||||||
|
|
||||||
def _add_mbus(self, obis_reference, dsmr_object, obis_name):
|
def _add_mbus(self, obis_reference, dsmr_object):
|
||||||
"""
|
"""
|
||||||
The given DsmrObject is assumed to be Mbus related and will be grouped into a MbusDevice.
|
The given DsmrObject is assumed to be Mbus related and will be grouped into a MbusDevice.
|
||||||
Grouping is done by the DsmrObject channel ID.
|
Grouping is done by the DsmrObject channel ID.
|
||||||
@@ -52,7 +55,7 @@ class Telegram(dict):
|
|||||||
mbus_device = MbusDevice(channel_id=channel_id)
|
mbus_device = MbusDevice(channel_id=channel_id)
|
||||||
self._mbus_devices.append(mbus_device)
|
self._mbus_devices.append(mbus_device)
|
||||||
|
|
||||||
mbus_device.add(obis_reference, dsmr_object, obis_name)
|
mbus_device.add(obis_reference, dsmr_object)
|
||||||
|
|
||||||
if not hasattr(self, 'MBUS_DEVICES'):
|
if not hasattr(self, 'MBUS_DEVICES'):
|
||||||
setattr(self, 'MBUS_DEVICES', self._mbus_devices)
|
setattr(self, 'MBUS_DEVICES', self._mbus_devices)
|
||||||
@@ -140,25 +143,22 @@ class MBusObject(DSMRObject):
|
|||||||
return self.values[1]['unit']
|
return self.values[1]['unit']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
timestamp = self.datetime
|
|
||||||
if isinstance(timestamp, datetime.datetime):
|
|
||||||
timestamp = timestamp.astimezone().astimezone(pytz.utc).isoformat()
|
|
||||||
output = "{}\t[{}] at {}".format(
|
output = "{}\t[{}] at {}".format(
|
||||||
str(self.value),
|
str(self.value),
|
||||||
str(self.unit),
|
str(self.unit),
|
||||||
str(timestamp)
|
str(self.datetime.astimezone().astimezone(pytz.utc).isoformat())
|
||||||
)
|
)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
timestamp = self.datetime
|
timestamp = self.datetime
|
||||||
if isinstance(timestamp, datetime.datetime):
|
if isinstance(self.datetime, datetime.datetime):
|
||||||
timestamp = timestamp.astimezone().astimezone(pytz.utc).isoformat()
|
timestamp = self.datetime.astimezone().astimezone(pytz.utc).isoformat()
|
||||||
value = self.value
|
value = self.value
|
||||||
if isinstance(value, datetime.datetime):
|
if isinstance(self.value, datetime.datetime):
|
||||||
value = value.astimezone().astimezone(pytz.utc).isoformat()
|
value = self.value.astimezone().astimezone(pytz.utc).isoformat()
|
||||||
if isinstance(value, Decimal):
|
if isinstance(self.value, Decimal):
|
||||||
value = float(value)
|
value = float(self.value)
|
||||||
output = {
|
output = {
|
||||||
'datetime': timestamp,
|
'datetime': timestamp,
|
||||||
'value': value,
|
'value': value,
|
||||||
@@ -186,33 +186,23 @@ class MBusObjectPeak(DSMRObject):
|
|||||||
return self.values[2]['unit']
|
return self.values[2]['unit']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
timestamp = self.datetime
|
|
||||||
if isinstance(timestamp, datetime.datetime):
|
|
||||||
timestamp = timestamp.astimezone().astimezone(pytz.utc).isoformat()
|
|
||||||
timestamp_occurred = self.occurred
|
|
||||||
if isinstance(timestamp_occurred, datetime.datetime):
|
|
||||||
timestamp_occurred = timestamp_occurred.astimezone().astimezone(pytz.utc).isoformat()
|
|
||||||
value = self.value
|
|
||||||
if isinstance(value, datetime.datetime):
|
|
||||||
value = value.astimezone().astimezone(pytz.utc).isoformat()
|
|
||||||
if isinstance(value, Decimal):
|
|
||||||
value = float(value)
|
|
||||||
output = "{}\t[{}] at {} occurred {}"\
|
output = "{}\t[{}] at {} occurred {}"\
|
||||||
.format(str(value), str(self.unit), str(timestamp), str(timestamp_occurred))
|
.format(str(self.value), str(self.unit), str(self.datetime.astimezone().astimezone(pytz.utc).isoformat()),
|
||||||
|
str(self.occurred.astimezone().astimezone(pytz.utc).isoformat()))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
timestamp = self.datetime
|
timestamp = self.datetime
|
||||||
if isinstance(timestamp, datetime.datetime):
|
if isinstance(self.datetime, datetime.datetime):
|
||||||
timestamp = timestamp.astimezone().astimezone(pytz.utc).isoformat()
|
timestamp = self.datetime.astimezone().astimezone(pytz.utc).isoformat()
|
||||||
timestamp_occurred = self.occurred
|
timestamp_occurred = self.occurred
|
||||||
if isinstance(timestamp_occurred, datetime.datetime):
|
if isinstance(self.occurred, datetime.datetime):
|
||||||
timestamp_occurred = timestamp_occurred.astimezone().astimezone(pytz.utc).isoformat()
|
timestamp_occurred = self.occurred.astimezone().astimezone(pytz.utc).isoformat()
|
||||||
value = self.value
|
value = self.value
|
||||||
if isinstance(value, datetime.datetime):
|
if isinstance(self.value, datetime.datetime):
|
||||||
value = value.astimezone().astimezone(pytz.utc).isoformat()
|
value = self.value.astimezone().astimezone(pytz.utc).isoformat()
|
||||||
if isinstance(value, Decimal):
|
if isinstance(self.value, Decimal):
|
||||||
value = float(value)
|
value = float(self.value)
|
||||||
output = {
|
output = {
|
||||||
'datetime': timestamp,
|
'datetime': timestamp,
|
||||||
'occurred': timestamp_occurred,
|
'occurred': timestamp_occurred,
|
||||||
@@ -341,9 +331,10 @@ class MbusDevice:
|
|||||||
self.channel_id = channel_id
|
self.channel_id = channel_id
|
||||||
self._item_names = []
|
self._item_names = []
|
||||||
|
|
||||||
def add(self, obis_reference, dsmr_object, obis_name):
|
def add(self, obis_reference, dsmr_object):
|
||||||
# Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER
|
# Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER
|
||||||
# Also keep track of the added names internally
|
# Also keep track of the added names internally
|
||||||
|
obis_name = obis_name_mapping.EN[obis_reference]
|
||||||
setattr(self, obis_name, dsmr_object)
|
setattr(self, obis_name, dsmr_object)
|
||||||
self._item_names.append(obis_name)
|
self._item_names.append(obis_name)
|
||||||
|
|
||||||
|
|||||||
+11
-27
@@ -25,15 +25,10 @@ class TelegramParser(object):
|
|||||||
telegram DSMR version (v4 and up).
|
telegram DSMR version (v4 and up).
|
||||||
:type telegram_specification: dict
|
:type telegram_specification: dict
|
||||||
"""
|
"""
|
||||||
self.apply_checksum_validation = apply_checksum_validation
|
|
||||||
self.telegram_specification = telegram_specification
|
self.telegram_specification = telegram_specification
|
||||||
# Regexes are compiled once to improve performance
|
self.apply_checksum_validation = apply_checksum_validation
|
||||||
self.telegram_specification_regexes = {
|
|
||||||
object["obis_reference"]: re.compile(object["obis_reference"], re.DOTALL | re.MULTILINE)
|
|
||||||
for object in self.telegram_specification['objects']
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(self, telegram_data, encryption_key="", authentication_key="", throw_ex=False): # noqa: C901
|
def parse(self, telegram_data, encryption_key="", authentication_key=""): # noqa: C901
|
||||||
"""
|
"""
|
||||||
Parse telegram from string to dict.
|
Parse telegram from string to dict.
|
||||||
The telegram str type makes python 2.x integration easier.
|
The telegram str type makes python 2.x integration easier.
|
||||||
@@ -84,31 +79,20 @@ class TelegramParser(object):
|
|||||||
|
|
||||||
telegram = Telegram()
|
telegram = Telegram()
|
||||||
|
|
||||||
for object in self.telegram_specification['objects']:
|
for signature, parser in self.telegram_specification['objects'].items():
|
||||||
pattern = self.telegram_specification_regexes[object["obis_reference"]]
|
pattern = re.compile(signature, re.DOTALL)
|
||||||
matches = pattern.findall(telegram_data)
|
matches = pattern.findall(telegram_data)
|
||||||
|
|
||||||
# Some signatures are optional and may not be present,
|
# Some signatures are optional and may not be present,
|
||||||
# so only parse lines that match
|
# so only parse lines that match
|
||||||
for match in matches:
|
for match in matches:
|
||||||
try:
|
try:
|
||||||
dsmr_object = object["value_parser"].parse(match)
|
dsmr_object = parser.parse(match)
|
||||||
except ParseError:
|
except Exception:
|
||||||
logger.error(
|
logger.error("ignore line with signature {}, because parsing failed.".format(signature),
|
||||||
"ignore line with signature {}, because parsing failed.".format(object["obis_reference"]),
|
exc_info=True)
|
||||||
exc_info=True
|
|
||||||
)
|
|
||||||
if throw_ex:
|
|
||||||
raise
|
|
||||||
except Exception as err:
|
|
||||||
logger.error("Unexpected {}: {}".format(type(err), err))
|
|
||||||
raise
|
|
||||||
else:
|
else:
|
||||||
telegram.add(
|
telegram.add(obis_reference=signature, dsmr_object=dsmr_object)
|
||||||
obis_reference=object["obis_reference"],
|
|
||||||
dsmr_object=dsmr_object,
|
|
||||||
obis_name=object["value_name"]
|
|
||||||
)
|
|
||||||
|
|
||||||
return telegram
|
return telegram
|
||||||
|
|
||||||
@@ -274,7 +258,7 @@ class MaxDemandParser(DSMRObjectParser):
|
|||||||
|
|
||||||
count = int(values[0])
|
count = int(values[0])
|
||||||
for i in range(1, count + 1):
|
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])
|
timestamp_occurred = ValueParser(timestamp).parse(values[i * 3 + 1])
|
||||||
value = ValueParser(Decimal).parse(values[i * 3 + 2])
|
value = ValueParser(Decimal).parse(values[i * 3 + 2])
|
||||||
objects.append(MBusObjectPeak(
|
objects.append(MBusObjectPeak(
|
||||||
@@ -335,7 +319,7 @@ class ProfileGenericParser(DSMRObjectParser):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, buffer_types, head_parsers, parsers_for_unidentified):
|
def __init__(self, buffer_types, head_parsers, parsers_for_unidentified):
|
||||||
self.value_formats = head_parsers.copy()
|
self.value_formats = head_parsers
|
||||||
self.buffer_types = buffer_types
|
self.buffer_types = buffer_types
|
||||||
self.parsers_for_unidentified = parsers_for_unidentified
|
self.parsers_for_unidentified = parsers_for_unidentified
|
||||||
|
|
||||||
|
|||||||
+283
-1312
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,6 @@ import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
# TODO : Use system timezone
|
|
||||||
# Preload timezone to avoid loading in event loop later
|
|
||||||
local_tz = pytz.timezone('Europe/Amsterdam')
|
|
||||||
|
|
||||||
|
|
||||||
def timestamp(value):
|
def timestamp(value):
|
||||||
try:
|
try:
|
||||||
@@ -24,6 +20,8 @@ def timestamp(value):
|
|||||||
else:
|
else:
|
||||||
is_dst = False
|
is_dst = False
|
||||||
|
|
||||||
|
# TODO : Use system timezone
|
||||||
|
local_tz = pytz.timezone('Europe/Amsterdam')
|
||||||
localized_datetime = local_tz.localize(naive_datetime, is_dst=is_dst)
|
localized_datetime = local_tz.localize(naive_datetime, is_dst=is_dst)
|
||||||
|
|
||||||
return localized_datetime.astimezone(pytz.utc)
|
return localized_datetime.astimezone(pytz.utc)
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ setup(
|
|||||||
author_email='mail@nldr.net',
|
author_email='mail@nldr.net',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
url='https://github.com/ndokter/dsmr_parser',
|
url='https://github.com/ndokter/dsmr_parser',
|
||||||
version='1.4.2',
|
version='1.2.0',
|
||||||
packages=find_packages(exclude=('test', 'test.*')),
|
packages=find_packages(exclude=('test', 'test.*')),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'pyserial>=3,<4',
|
'pyserial>=3,<4',
|
||||||
'pyserial-asyncio-fast>=0.11',
|
'pyserial-asyncio<1',
|
||||||
'pytz',
|
'pytz',
|
||||||
'Tailer==0.4.1',
|
'Tailer==0.4.1',
|
||||||
'dlms_cosem==21.3.2'
|
'dlms_cosem==21.3.2'
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ TELEGRAM_V5_TWO_MBUS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
TELEGRAM_FLUVIUS_V171 = (
|
TELEGRAM_FLUVIUS_V171 = (
|
||||||
'/FLU5\\253769484_A\r\n'
|
'/FLU5\253769484_A\r\n'
|
||||||
'\r\n'
|
'\r\n'
|
||||||
'0-0:96.1.4(50217)\r\n'
|
'0-0:96.1.4(50217)\r\n'
|
||||||
'0-0:96.1.1(3153414733313031303231363035)\r\n'
|
'0-0:96.1.1(3153414733313031303231363035)\r\n'
|
||||||
@@ -213,49 +213,7 @@ TELEGRAM_FLUVIUS_V171 = (
|
|||||||
'0-2:24.1.0(007)\r\n'
|
'0-2:24.1.0(007)\r\n'
|
||||||
'0-2:96.1.1(3853414731323334353637383930)\r\n'
|
'0-2:96.1.1(3853414731323334353637383930)\r\n'
|
||||||
'0-2:24.2.1(200512134558S)(00872.234*m3)\r\n'
|
'0-2:24.2.1(200512134558S)(00872.234*m3)\r\n'
|
||||||
'!3AD7\r\n'
|
'!911C\r\n'
|
||||||
)
|
|
||||||
|
|
||||||
TELEGRAM_FLUVIUS_V171_ALT = (
|
|
||||||
'/FLU5\\253769484_A\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'0-0:96.1.4(50217)\r\n'
|
|
||||||
'0-0:96.1.1(3153414733313030373231333236)\r\n'
|
|
||||||
'0-0:1.0.0(231102121548W)\r\n'
|
|
||||||
'1-0:1.8.1(000301.548*kWh)\r\n'
|
|
||||||
'1-0:1.8.2(000270.014*kWh)\r\n'
|
|
||||||
'1-0:2.8.1(000000.005*kWh)\r\n'
|
|
||||||
'1-0:2.8.2(000000.000*kWh)\r\n'
|
|
||||||
'0-0:96.14.0(0001)\r\n'
|
|
||||||
'1-0:1.4.0(00.052*kW)\r\n'
|
|
||||||
'1-0:1.6.0(231102114500W)(03.064*kW)\r\n'
|
|
||||||
'0-0:98.1.0(4)(1-0:1.6.0)(1-0:1.6.0)(230801000000S)(632525252525W)(00.000*kW)(230901000000S)(230831181500S)(01.862*kW)(231001000000S)(230910183000S)(04.229*kW)(231101000000W)(231016130000S)(04.927*kW)\r\n'
|
|
||||||
'1-0:1.7.0(00.338*kW)\r\n'
|
|
||||||
'1-0:2.7.0(00.000*kW)\r\n'
|
|
||||||
'1-0:21.7.0(00.047*kW)\r\n'
|
|
||||||
'1-0:41.7.0(00.179*kW)\r\n'
|
|
||||||
'1-0:61.7.0(00.111*kW)\r\n'
|
|
||||||
'1-0:22.7.0(00.000*kW)\r\n'
|
|
||||||
'1-0:42.7.0(00.000*kW)\r\n'
|
|
||||||
'1-0:62.7.0(00.000*kW)\r\n'
|
|
||||||
'1-0:32.7.0(232.9*V)\r\n'
|
|
||||||
'1-0:52.7.0(228.1*V)\r\n'
|
|
||||||
'1-0:72.7.0(228.1*V)\r\n'
|
|
||||||
'1-0:31.7.0(000.27*A)\r\n'
|
|
||||||
'1-0:51.7.0(000.88*A)\r\n'
|
|
||||||
'1-0:71.7.0(000.52*A)\r\n'
|
|
||||||
'0-0:96.3.10(1)\r\n'
|
|
||||||
'0-0:17.0.0(999.9*kW)\r\n'
|
|
||||||
'1-0:31.4.0(999*A)\r\n'
|
|
||||||
'0-0:96.13.0()\r\n'
|
|
||||||
'0-1:24.1.0(003)\r\n'
|
|
||||||
'0-1:96.1.1(37464C4F32313233303838303237)\r\n'
|
|
||||||
'0-1:24.4.0(1)\r\n'
|
|
||||||
'0-1:24.2.3(231102121002W)(00092.287*m3)\r\n'
|
|
||||||
'0-2:24.1.0(007)\r\n'
|
|
||||||
'0-2:96.1.1(3853455430303030393631313733)\r\n'
|
|
||||||
'0-2:24.2.1(231102121532W)(00008.579*m3)\r\n'
|
|
||||||
'!C4B0\r\n'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# EasyMeter via COM-1 Ethernet Gateway
|
# EasyMeter via COM-1 Ethernet Gateway
|
||||||
@@ -353,55 +311,3 @@ TELEGRAM_ISKRA_IE = (
|
|||||||
'0-1:96.1.1()\r\n'
|
'0-1:96.1.1()\r\n'
|
||||||
'!AD3B\r\n'
|
'!AD3B\r\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
# V5 telegram of EON in Hungary
|
|
||||||
TELEGRAM_V5_EON_HU = (
|
|
||||||
'/SAG5SAG-METER\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'0-0:1.0.0(230724150730S)\r\n'
|
|
||||||
'0-0:42.0.0(53414733303832323030303032313630)\r\n'
|
|
||||||
'0-0:96.1.0(383930303832323030303032313630)\r\n'
|
|
||||||
'0-0:96.14.0(0001)\r\n'
|
|
||||||
'0-0:96.3.10(1)\r\n'
|
|
||||||
'0-0:17.0.0(90.000*kW)\r\n'
|
|
||||||
'1-0:1.8.0(000173.640*kWh)\r\n'
|
|
||||||
'1-0:1.8.1(000047.719*kWh)\r\n'
|
|
||||||
'1-0:1.8.2(000125.921*kWh)\r\n'
|
|
||||||
'1-0:1.8.3(000000.000*kWh)\r\n'
|
|
||||||
'1-0:1.8.4(000000.000*kWh)\r\n'
|
|
||||||
'1-0:2.8.0(000627.177*kWh)\r\n'
|
|
||||||
'1-0:2.8.1(000401.829*kWh)\r\n'
|
|
||||||
'1-0:2.8.2(000225.348*kWh)\r\n'
|
|
||||||
'1-0:2.8.3(000000.000*kWh)\r\n'
|
|
||||||
'1-0:2.8.4(000000.000*kWh)\r\n'
|
|
||||||
'1-0:3.8.0(000000.123*kvarh)\r\n'
|
|
||||||
'1-0:4.8.0(000303.131*kvarh)\r\n'
|
|
||||||
'1-0:5.8.0(000000.668*kvarh)\r\n'
|
|
||||||
'1-0:6.8.0(000000.071*kvarh)\r\n'
|
|
||||||
'1-0:7.8.0(000160.487*kvarh)\r\n'
|
|
||||||
'1-0:8.8.0(000143.346*kvarh)\r\n'
|
|
||||||
'1-0:15.8.0(000800.817*kWh)\r\n'
|
|
||||||
'1-0:32.7.0(240.4*V)\r\n'
|
|
||||||
'1-0:52.7.0(239.1*V)\r\n'
|
|
||||||
'1-0:72.7.0(241.2*V)\r\n'
|
|
||||||
'1-0:31.7.0(003*A)\r\n'
|
|
||||||
'1-0:51.7.0(004*A)\r\n'
|
|
||||||
'1-0:71.7.0(003*A)\r\n'
|
|
||||||
'1-0:13.7.0(4.556)\r\n'
|
|
||||||
'1-0:33.7.0(4.591)\r\n'
|
|
||||||
'1-0:53.7.0(4.542)\r\n'
|
|
||||||
'1-0:73.7.0(4.552)\r\n'
|
|
||||||
'1-0:14.7.0(50.00*Hz)\r\n'
|
|
||||||
'1-0:1.7.0(00.000*kW)\r\n'
|
|
||||||
'1-0:2.7.0(02.601*kW)\r\n'
|
|
||||||
'1-0:5.7.0(00.000*kvar)\r\n'
|
|
||||||
'1-0:6.7.0(00.000*kvar)\r\n'
|
|
||||||
'1-0:7.7.0(00.504*kvar)\r\n'
|
|
||||||
'1-0:8.7.0(00.000*kvar)\r\n'
|
|
||||||
'1-0:31.4.0(200.00*A)\r\n'
|
|
||||||
'1-0:51.4.0(200.00*A)\r\n'
|
|
||||||
'1-0:71.4.0(200.00*A)\r\n'
|
|
||||||
'0-0:98.1.0(230701000000S)(000040.777*kWh)(000008.950*kWh)(000031.827*kWh)(000142.250*kWh)(000111.164*kWh)(000031.086*kWh)(000000.030*kvarh)(000073.988*kvarh)(000000.205*kvarh)(000000.048*kvarh)(000039.199*kvarh)(000035.020*kvarh)(000183.027*kWh)(03.564*kW)(02.156*kW)(03.564*kW)(04.104*kW)(04.104*kW)(03.400*kW)\r\n'
|
|
||||||
'0-0:96.13.0()\r\n'
|
|
||||||
'!99DA\r\n'
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -12,62 +12,50 @@ class MbusDeviceTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
v5_objects = telegram_specifications.V5['objects']
|
v5_objects = telegram_specifications.V5['objects']
|
||||||
|
|
||||||
device_type_parser = [
|
device_type_parser = v5_objects[obis_references.DEVICE_TYPE]
|
||||||
object["value_parser"]
|
|
||||||
for object in v5_objects
|
|
||||||
if object["obis_reference"] == obis_references.MBUS_DEVICE_TYPE
|
|
||||||
][0]
|
|
||||||
device_type = device_type_parser.parse('0-2:24.1.0(003)\r\n')
|
device_type = device_type_parser.parse('0-2:24.1.0(003)\r\n')
|
||||||
|
|
||||||
equipment_parser = [
|
equipment_parser = v5_objects[obis_references.EQUIPMENT_IDENTIFIER_GAS]
|
||||||
object["value_parser"]
|
|
||||||
for object in v5_objects
|
|
||||||
if object["obis_reference"] == obis_references.MBUS_EQUIPMENT_IDENTIFIER
|
|
||||||
][0]
|
|
||||||
equipment = equipment_parser.parse('0-2:96.1.0(4730303339303031393336393930363139)\r\n')
|
equipment = equipment_parser.parse('0-2:96.1.0(4730303339303031393336393930363139)\r\n')
|
||||||
|
|
||||||
gas_reading_parser = [
|
gas_reading_parser = v5_objects[obis_references.HOURLY_GAS_METER_READING]
|
||||||
object["value_parser"]
|
|
||||||
for object in v5_objects
|
|
||||||
if object["obis_reference"] == obis_references.MBUS_METER_READING
|
|
||||||
][0]
|
|
||||||
gas_reading = gas_reading_parser.parse('0-2:24.2.1(200426223001S)(00246.138*m3)\r\n')
|
gas_reading = gas_reading_parser.parse('0-2:24.2.1(200426223001S)(00246.138*m3)\r\n')
|
||||||
|
|
||||||
mbus_device = MbusDevice(channel_id=2)
|
mbus_device = MbusDevice(channel_id=1)
|
||||||
mbus_device.add(obis_references.MBUS_DEVICE_TYPE, device_type, "MBUS_DEVICE_TYPE")
|
mbus_device.add(obis_references.DEVICE_TYPE, device_type)
|
||||||
mbus_device.add(obis_references.MBUS_EQUIPMENT_IDENTIFIER, equipment, "MBUS_EQUIPMENT_IDENTIFIER")
|
mbus_device.add(obis_references.EQUIPMENT_IDENTIFIER_GAS, equipment)
|
||||||
mbus_device.add(obis_references.MBUS_METER_READING, gas_reading, "MBUS_METER_READING")
|
mbus_device.add(obis_references.HOURLY_GAS_METER_READING, gas_reading)
|
||||||
|
|
||||||
self.mbus_device = mbus_device
|
self.mbus_device = mbus_device
|
||||||
|
|
||||||
def test_attributes(self):
|
def test_attributes(self):
|
||||||
self.assertEqual(self.mbus_device.MBUS_DEVICE_TYPE.value, 3)
|
self.assertEqual(self.mbus_device.DEVICE_TYPE.value, 3)
|
||||||
self.assertEqual(self.mbus_device.MBUS_DEVICE_TYPE.unit, None)
|
self.assertEqual(self.mbus_device.DEVICE_TYPE.unit, None)
|
||||||
|
|
||||||
self.assertEqual(self.mbus_device.MBUS_EQUIPMENT_IDENTIFIER.value,
|
self.assertEqual(self.mbus_device.EQUIPMENT_IDENTIFIER_GAS.value,
|
||||||
'4730303339303031393336393930363139')
|
'4730303339303031393336393930363139')
|
||||||
self.assertEqual(self.mbus_device.MBUS_EQUIPMENT_IDENTIFIER.unit, None)
|
self.assertEqual(self.mbus_device.EQUIPMENT_IDENTIFIER_GAS.unit, None)
|
||||||
|
|
||||||
self.assertEqual(self.mbus_device.MBUS_METER_READING.value, Decimal('246.138'))
|
self.assertEqual(self.mbus_device.HOURLY_GAS_METER_READING.value, Decimal('246.138'))
|
||||||
self.assertEqual(self.mbus_device.MBUS_METER_READING.unit, 'm3')
|
self.assertEqual(self.mbus_device.HOURLY_GAS_METER_READING.unit, 'm3')
|
||||||
|
|
||||||
def test_to_json(self):
|
def test_to_json(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
json.loads(self.mbus_device.to_json()),
|
json.loads(self.mbus_device.to_json()),
|
||||||
{
|
{
|
||||||
'CHANNEL_ID': 2,
|
'CHANNEL_ID': 1,
|
||||||
'MBUS_DEVICE_TYPE': {'value': 3, 'unit': None},
|
'DEVICE_TYPE': {'value': 3, 'unit': None},
|
||||||
'MBUS_EQUIPMENT_IDENTIFIER': {'value': '4730303339303031393336393930363139', 'unit': None},
|
'EQUIPMENT_IDENTIFIER_GAS': {'value': '4730303339303031393336393930363139', 'unit': None},
|
||||||
'MBUS_METER_READING': {'datetime': '2020-04-26T20:30:01+00:00', 'value': 246.138, 'unit': 'm3'}}
|
'HOURLY_GAS_METER_READING': {'datetime': '2020-04-26T20:30:01+00:00', 'value': 246.138, 'unit': 'm3'}}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(self.mbus_device),
|
str(self.mbus_device),
|
||||||
(
|
(
|
||||||
'MBUS DEVICE (channel 2)\n'
|
'MBUS DEVICE (channel 1)\n'
|
||||||
'\tMBUS_DEVICE_TYPE: 3 [None]\n'
|
'\tDEVICE_TYPE: 3 [None]\n'
|
||||||
'\tMBUS_EQUIPMENT_IDENTIFIER: 4730303339303031393336393930363139 [None]\n'
|
'\tEQUIPMENT_IDENTIFIER_GAS: 4730303339303031393336393930363139 [None]\n'
|
||||||
'\tMBUS_METER_READING: 246.138 [m3] at 2020-04-26T20:30:01+00:00\n'
|
'\tHOURLY_GAS_METER_READING: 246.138 [m3] at 2020-04-26T20:30:01+00:00\n'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import datetime
|
|||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from dsmr_parser import telegram_specifications, obis_references
|
from dsmr_parser import telegram_specifications, obis_references
|
||||||
|
from dsmr_parser import obis_name_mapping
|
||||||
from dsmr_parser.objects import CosemObject
|
from dsmr_parser.objects import CosemObject
|
||||||
from dsmr_parser.objects import MBusObject
|
from dsmr_parser.objects import MBusObject
|
||||||
from dsmr_parser.objects import ProfileGenericObject
|
from dsmr_parser.objects import ProfileGenericObject
|
||||||
@@ -216,6 +216,14 @@ class TelegramTest(unittest.TestCase):
|
|||||||
value_type=Decimal,
|
value_type=Decimal,
|
||||||
value_val=Decimal('2'))
|
value_val=Decimal('2'))
|
||||||
|
|
||||||
|
# DEVICE_TYPE (0-x:24.1.0)
|
||||||
|
self.verify_telegram_item(telegram,
|
||||||
|
'DEVICE_TYPE',
|
||||||
|
object_type=CosemObject,
|
||||||
|
unit_val=None,
|
||||||
|
value_type=int,
|
||||||
|
value_val=3)
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
||||||
self.verify_telegram_item(telegram,
|
self.verify_telegram_item(telegram,
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE',
|
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE',
|
||||||
@@ -264,15 +272,7 @@ class TelegramTest(unittest.TestCase):
|
|||||||
value_type=Decimal,
|
value_type=Decimal,
|
||||||
value_val=Decimal('0'))
|
value_val=Decimal('0'))
|
||||||
|
|
||||||
# DEVICE_TYPE (0-1:24.1.0)
|
# EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0)
|
||||||
self.verify_telegram_item(telegram,
|
|
||||||
'DEVICE_TYPE',
|
|
||||||
object_type=CosemObject,
|
|
||||||
unit_val=None,
|
|
||||||
value_type=int,
|
|
||||||
value_val=3)
|
|
||||||
|
|
||||||
# EQUIPMENT_IDENTIFIER_GAS (0-1:96.1.0)
|
|
||||||
self.verify_telegram_item(telegram,
|
self.verify_telegram_item(telegram,
|
||||||
'EQUIPMENT_IDENTIFIER_GAS',
|
'EQUIPMENT_IDENTIFIER_GAS',
|
||||||
object_type=CosemObject,
|
object_type=CosemObject,
|
||||||
@@ -314,8 +314,8 @@ class TelegramTest(unittest.TestCase):
|
|||||||
self.item_names_tested.append(testitem_name)
|
self.item_names_tested.append(testitem_name)
|
||||||
|
|
||||||
# check if all items in telegram V4 specification are covered
|
# check if all items in telegram V4 specification are covered
|
||||||
V4_name_list = [object["value_name"] for object in
|
V4_name_list = [obis_name_mapping.EN[signature] for signature, parser in
|
||||||
telegram_specifications.V4['objects']]
|
telegram_specifications.V4['objects'].items()]
|
||||||
V4_name_set = set(V4_name_list)
|
V4_name_set = set(V4_name_list)
|
||||||
item_names_tested_set = set(self.item_names_tested)
|
item_names_tested_set = set(self.item_names_tested)
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ class TelegramTest(unittest.TestCase):
|
|||||||
break
|
break
|
||||||
|
|
||||||
# Verify that the iterator works for at least one value
|
# Verify that the iterator works for at least one value
|
||||||
self.assertEqual(obis_name, "P1_MESSAGE_HEADER")
|
self.assertEqual(obis_name, obis_name_mapping.EN[obis_references.P1_MESSAGE_HEADER])
|
||||||
self.assertEqual(dsmr_object.value, '50')
|
self.assertEqual(dsmr_object.value, '50')
|
||||||
|
|
||||||
def test_mbus_devices(self):
|
def test_mbus_devices(self):
|
||||||
@@ -340,28 +340,28 @@ class TelegramTest(unittest.TestCase):
|
|||||||
self.assertEqual(len(mbus_devices), 2)
|
self.assertEqual(len(mbus_devices), 2)
|
||||||
|
|
||||||
mbus_device_1 = mbus_devices[0]
|
mbus_device_1 = mbus_devices[0]
|
||||||
self.assertEqual(mbus_device_1.MBUS_DEVICE_TYPE.value, 3)
|
self.assertEqual(mbus_device_1.DEVICE_TYPE.value, 3)
|
||||||
self.assertEqual(mbus_device_1.MBUS_EQUIPMENT_IDENTIFIER.value, None)
|
self.assertEqual(mbus_device_1.EQUIPMENT_IDENTIFIER_GAS.value, None)
|
||||||
self.assertEqual(mbus_device_1.MBUS_METER_READING.value, Decimal('0'))
|
self.assertEqual(mbus_device_1.HOURLY_GAS_METER_READING.value, Decimal('0'))
|
||||||
|
|
||||||
mbus_device_2 = mbus_devices[1]
|
mbus_device_2 = mbus_devices[1]
|
||||||
self.assertEqual(mbus_device_2.MBUS_DEVICE_TYPE.value, 3)
|
self.assertEqual(mbus_device_2.DEVICE_TYPE.value, 3)
|
||||||
self.assertEqual(mbus_device_2.MBUS_EQUIPMENT_IDENTIFIER.value, '4730303339303031393336393930363139')
|
self.assertEqual(mbus_device_2.EQUIPMENT_IDENTIFIER_GAS.value, '4730303339303031393336393930363139')
|
||||||
self.assertEqual(mbus_device_2.MBUS_METER_READING.value, Decimal('246.138'))
|
self.assertEqual(mbus_device_2.HOURLY_GAS_METER_READING.value, Decimal('246.138'))
|
||||||
|
|
||||||
def test_get_mbus_device_by_channel(self):
|
def test_get_mbus_device_by_channel(self):
|
||||||
parser = TelegramParser(telegram_specifications.V5)
|
parser = TelegramParser(telegram_specifications.V5)
|
||||||
telegram = parser.parse(TELEGRAM_V5_TWO_MBUS)
|
telegram = parser.parse(TELEGRAM_V5_TWO_MBUS)
|
||||||
|
|
||||||
mbus_device_1 = telegram.get_mbus_device_by_channel(1)
|
mbus_device_1 = telegram.get_mbus_device_by_channel(1)
|
||||||
self.assertEqual(mbus_device_1.MBUS_DEVICE_TYPE.value, 3)
|
self.assertEqual(mbus_device_1.DEVICE_TYPE.value, 3)
|
||||||
self.assertEqual(mbus_device_1.MBUS_EQUIPMENT_IDENTIFIER.value, None)
|
self.assertEqual(mbus_device_1.EQUIPMENT_IDENTIFIER_GAS.value, None)
|
||||||
self.assertEqual(mbus_device_1.MBUS_METER_READING.value, Decimal('0'))
|
self.assertEqual(mbus_device_1.HOURLY_GAS_METER_READING.value, Decimal('0'))
|
||||||
|
|
||||||
mbus_device_2 = telegram.get_mbus_device_by_channel(2)
|
mbus_device_2 = telegram.get_mbus_device_by_channel(2)
|
||||||
self.assertEqual(mbus_device_2.MBUS_DEVICE_TYPE.value, 3)
|
self.assertEqual(mbus_device_2.DEVICE_TYPE.value, 3)
|
||||||
self.assertEqual(mbus_device_2.MBUS_EQUIPMENT_IDENTIFIER.value, '4730303339303031393336393930363139')
|
self.assertEqual(mbus_device_2.EQUIPMENT_IDENTIFIER_GAS.value, '4730303339303031393336393930363139')
|
||||||
self.assertEqual(mbus_device_2.MBUS_METER_READING.value, Decimal('246.138'))
|
self.assertEqual(mbus_device_2.HOURLY_GAS_METER_READING.value, Decimal('246.138'))
|
||||||
|
|
||||||
def test_without_mbus_devices(self):
|
def test_without_mbus_devices(self):
|
||||||
parser = TelegramParser(telegram_specifications.V5, apply_checksum_validation=False)
|
parser = TelegramParser(telegram_specifications.V5, apply_checksum_validation=False)
|
||||||
@@ -375,12 +375,11 @@ class TelegramTest(unittest.TestCase):
|
|||||||
telegram = parser.parse(TELEGRAM_V5)
|
telegram = parser.parse(TELEGRAM_V5)
|
||||||
json_data = json.loads(telegram.to_json())
|
json_data = json.loads(telegram.to_json())
|
||||||
|
|
||||||
self.maxDiff = None
|
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
json_data,
|
json_data,
|
||||||
{'CURRENT_ELECTRICITY_DELIVERY': {'unit': 'kW', 'value': 0.0},
|
{'CURRENT_ELECTRICITY_DELIVERY': {'unit': 'kW', 'value': 0.0},
|
||||||
'CURRENT_ELECTRICITY_USAGE': {'unit': 'kW', 'value': 0.244},
|
'CURRENT_ELECTRICITY_USAGE': {'unit': 'kW', 'value': 0.244},
|
||||||
|
'DEVICE_TYPE': {'unit': None, 'value': 3},
|
||||||
'ELECTRICITY_ACTIVE_TARIFF': {'unit': None, 'value': '0002'},
|
'ELECTRICITY_ACTIVE_TARIFF': {'unit': None, 'value': '0002'},
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_1': {'unit': 'kWh', 'value': 2.444},
|
'ELECTRICITY_DELIVERED_TARIFF_1': {'unit': 'kWh', 'value': 2.444},
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_2': {'unit': 'kWh', 'value': 0.0},
|
'ELECTRICITY_DELIVERED_TARIFF_2': {'unit': 'kWh', 'value': 0.0},
|
||||||
@@ -388,6 +387,10 @@ class TelegramTest(unittest.TestCase):
|
|||||||
'ELECTRICITY_USED_TARIFF_2': {'unit': 'kWh', 'value': 2.399},
|
'ELECTRICITY_USED_TARIFF_2': {'unit': 'kWh', 'value': 2.399},
|
||||||
'EQUIPMENT_IDENTIFIER': {'unit': None,
|
'EQUIPMENT_IDENTIFIER': {'unit': None,
|
||||||
'value': '4B384547303034303436333935353037'},
|
'value': '4B384547303034303436333935353037'},
|
||||||
|
'EQUIPMENT_IDENTIFIER_GAS': {'unit': None, 'value': None},
|
||||||
|
'HOURLY_GAS_METER_READING': {'datetime': '2017-01-02T15:10:05+00:00',
|
||||||
|
'unit': 'm3',
|
||||||
|
'value': 0.107},
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE': {'unit': 'kW', 'value': 0.0},
|
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE': {'unit': 'kW', 'value': 0.0},
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE': {'unit': 'kW', 'value': 0.07},
|
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE': {'unit': 'kW', 'value': 0.07},
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE': {'unit': 'kW', 'value': 0.0},
|
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE': {'unit': 'kW', 'value': 0.0},
|
||||||
@@ -402,16 +405,15 @@ class TelegramTest(unittest.TestCase):
|
|||||||
'INSTANTANEOUS_VOLTAGE_L3': {'unit': 'V', 'value': 229.0},
|
'INSTANTANEOUS_VOLTAGE_L3': {'unit': 'V', 'value': 229.0},
|
||||||
'LONG_POWER_FAILURE_COUNT': {'unit': None, 'value': 0},
|
'LONG_POWER_FAILURE_COUNT': {'unit': None, 'value': 0},
|
||||||
'MBUS_DEVICES': [{'CHANNEL_ID': 1,
|
'MBUS_DEVICES': [{'CHANNEL_ID': 1,
|
||||||
'MBUS_DEVICE_TYPE': {'unit': None, 'value': 3},
|
'DEVICE_TYPE': {'unit': None, 'value': 3},
|
||||||
'MBUS_EQUIPMENT_IDENTIFIER': {'unit': None,
|
'EQUIPMENT_IDENTIFIER_GAS': {'unit': None,
|
||||||
'value': '3232323241424344313233343536373839'},
|
'value': '3232323241424344313233343536373839'},
|
||||||
'MBUS_METER_READING': {'datetime': '2017-01-02T15:10:05+00:00',
|
'HOURLY_GAS_METER_READING': {'datetime': '2017-01-02T15:10:05+00:00',
|
||||||
'unit': 'm3',
|
'unit': 'm3',
|
||||||
'value': 0.107}},
|
'value': 0.107}},
|
||||||
{'CHANNEL_ID': 2,
|
{'CHANNEL_ID': 2,
|
||||||
'MBUS_DEVICE_TYPE': {'unit': None, 'value': 3},
|
'DEVICE_TYPE': {'unit': None, 'value': 3},
|
||||||
'MBUS_EQUIPMENT_IDENTIFIER': {'unit': None,
|
'EQUIPMENT_IDENTIFIER_GAS': {'unit': None, 'value': None}}],
|
||||||
'value': None}}],
|
|
||||||
'P1_MESSAGE_HEADER': {'unit': None, 'value': '50'},
|
'P1_MESSAGE_HEADER': {'unit': None, 'value': '50'},
|
||||||
'P1_MESSAGE_TIMESTAMP': {'unit': None, 'value': '2017-01-02T18:20:02+00:00'},
|
'P1_MESSAGE_TIMESTAMP': {'unit': None, 'value': '2017-01-02T18:20:02+00:00'},
|
||||||
'POWER_EVENT_FAILURE_LOG': {'buffer': [],
|
'POWER_EVENT_FAILURE_LOG': {'buffer': [],
|
||||||
@@ -431,8 +433,6 @@ class TelegramTest(unittest.TestCase):
|
|||||||
parser = TelegramParser(telegram_specifications.V5)
|
parser = TelegramParser(telegram_specifications.V5)
|
||||||
telegram = parser.parse(TELEGRAM_V5)
|
telegram = parser.parse(TELEGRAM_V5)
|
||||||
|
|
||||||
self.maxDiff = None
|
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(telegram),
|
str(telegram),
|
||||||
(
|
(
|
||||||
@@ -463,19 +463,22 @@ class TelegramTest(unittest.TestCase):
|
|||||||
'INSTANTANEOUS_CURRENT_L2: 0.44 [A]\n'
|
'INSTANTANEOUS_CURRENT_L2: 0.44 [A]\n'
|
||||||
'INSTANTANEOUS_CURRENT_L3: 0.86 [A]\n'
|
'INSTANTANEOUS_CURRENT_L3: 0.86 [A]\n'
|
||||||
'TEXT_MESSAGE: None [None]\n'
|
'TEXT_MESSAGE: None [None]\n'
|
||||||
|
'DEVICE_TYPE: 3 [None]\n'
|
||||||
|
'MBUS DEVICE (channel 1)\n'
|
||||||
|
' DEVICE_TYPE: 3 [None]\n'
|
||||||
|
' EQUIPMENT_IDENTIFIER_GAS: 3232323241424344313233343536373839 [None]\n'
|
||||||
|
' HOURLY_GAS_METER_READING: 0.107 [m3] at 2017-01-02T15:10:05+00:00\n'
|
||||||
|
'MBUS DEVICE (channel 2)\n'
|
||||||
|
' DEVICE_TYPE: 3 [None]\n'
|
||||||
|
' EQUIPMENT_IDENTIFIER_GAS: None [None]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 0.070 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 0.070 [kW]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 0.032 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 0.032 [kW]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 0.142 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 0.142 [kW]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: 0.000 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: 0.000 [kW]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: 0.000 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: 0.000 [kW]\n'
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: 0.000 [kW]\n'
|
'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: 0.000 [kW]\n'
|
||||||
'MBUS DEVICE (channel 1)\n'
|
'EQUIPMENT_IDENTIFIER_GAS: None [None]\n'
|
||||||
' MBUS_DEVICE_TYPE: 3 [None]\n'
|
'HOURLY_GAS_METER_READING: 0.107 [m3] at 2017-01-02T15:10:05+00:00\n'
|
||||||
' MBUS_EQUIPMENT_IDENTIFIER: 3232323241424344313233343536373839 [None]\n'
|
|
||||||
' MBUS_METER_READING: 0.107 [m3] at 2017-01-02T15:10:05+00:00\n'
|
|
||||||
'MBUS DEVICE (channel 2)\n'
|
|
||||||
' MBUS_DEVICE_TYPE: 3 [None]\n'
|
|
||||||
' MBUS_EQUIPMENT_IDENTIFIER: None [None]\n'
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+165
-310
@@ -1,16 +1,16 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
from dsmr_parser import obis_references as obis
|
||||||
from dsmr_parser import telegram_specifications
|
from dsmr_parser import telegram_specifications
|
||||||
from dsmr_parser.exceptions import InvalidChecksumError, ParseError
|
from dsmr_parser.exceptions import InvalidChecksumError, ParseError
|
||||||
from dsmr_parser.objects import CosemObject, MBusObject, MBusObjectPeak
|
from dsmr_parser.objects import CosemObject, MBusObject, MBusObjectPeak
|
||||||
from dsmr_parser.parsers import TelegramParser
|
from dsmr_parser.parsers import TelegramParser
|
||||||
from test.example_telegrams import TELEGRAM_FLUVIUS_V171, TELEGRAM_FLUVIUS_V171_ALT
|
from test.example_telegrams import TELEGRAM_FLUVIUS_V171
|
||||||
|
|
||||||
|
|
||||||
class TelegramParserFluviusTest(unittest.TestCase):
|
class TelegramParserFluviusTest(unittest.TestCase):
|
||||||
@@ -18,263 +18,233 @@ class TelegramParserFluviusTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.BELGIUM_FLUVIUS)
|
parser = TelegramParser(telegram_specifications.BELGIUM_FLUVIUS)
|
||||||
try:
|
result = parser.parse(TELEGRAM_FLUVIUS_V171)
|
||||||
result = parser.parse(TELEGRAM_FLUVIUS_V171, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# BELGIUM_VERSION_INFORMATION (0-0:96.1.4)
|
# BELGIUM_VERSION_INFORMATION (0-0:96.1.4)
|
||||||
assert isinstance(result.BELGIUM_VERSION_INFORMATION, CosemObject)
|
assert isinstance(result[obis.BELGIUM_VERSION_INFORMATION], CosemObject)
|
||||||
assert result.BELGIUM_VERSION_INFORMATION.unit is None
|
assert result[obis.BELGIUM_VERSION_INFORMATION].unit is None
|
||||||
assert isinstance(result.BELGIUM_VERSION_INFORMATION.value, str)
|
assert isinstance(result[obis.BELGIUM_VERSION_INFORMATION].value, str)
|
||||||
assert result.BELGIUM_VERSION_INFORMATION.value == '50217'
|
assert result[obis.BELGIUM_VERSION_INFORMATION].value == '50217'
|
||||||
|
|
||||||
# EQUIPMENT_IDENTIFIER (0-0:96.1.1)
|
# EQUIPMENT_IDENTIFIER (0-0:96.1.1)
|
||||||
assert isinstance(result.BELGIUM_EQUIPMENT_IDENTIFIER, CosemObject)
|
assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject)
|
||||||
assert result.BELGIUM_EQUIPMENT_IDENTIFIER.unit is None
|
assert result[obis.EQUIPMENT_IDENTIFIER].unit is None
|
||||||
assert isinstance(result.BELGIUM_EQUIPMENT_IDENTIFIER.value, str)
|
assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str)
|
||||||
assert result.BELGIUM_EQUIPMENT_IDENTIFIER.value == '3153414733313031303231363035'
|
assert result[obis.EQUIPMENT_IDENTIFIER].value == '3153414733313031303231363035'
|
||||||
|
|
||||||
# P1_MESSAGE_TIMESTAMP (0-0:1.0.0)
|
# P1_MESSAGE_TIMESTAMP (0-0:1.0.0)
|
||||||
assert isinstance(result.P1_MESSAGE_TIMESTAMP, CosemObject)
|
assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP], CosemObject)
|
||||||
assert result.P1_MESSAGE_TIMESTAMP.unit is None
|
assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None
|
||||||
assert isinstance(result.P1_MESSAGE_TIMESTAMP.value, datetime.datetime)
|
assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime)
|
||||||
assert result.P1_MESSAGE_TIMESTAMP.value == \
|
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)
|
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
||||||
assert isinstance(result.ELECTRICITY_USED_TARIFF_1, CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
|
||||||
assert result.ELECTRICITY_USED_TARIFF_1.unit == 'kWh'
|
assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh'
|
||||||
assert isinstance(result.ELECTRICITY_USED_TARIFF_1.value, Decimal)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal)
|
||||||
assert result.ELECTRICITY_USED_TARIFF_1.value == Decimal('0.034')
|
assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal('0.034')
|
||||||
|
|
||||||
# ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2)
|
# ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2)
|
||||||
assert isinstance(result.ELECTRICITY_USED_TARIFF_2, CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject)
|
||||||
assert result.ELECTRICITY_USED_TARIFF_2.unit == 'kWh'
|
assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh'
|
||||||
assert isinstance(result.ELECTRICITY_USED_TARIFF_2.value, Decimal)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal)
|
||||||
assert result.ELECTRICITY_USED_TARIFF_2.value == Decimal('15.758')
|
assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal('15.758')
|
||||||
|
|
||||||
# ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1)
|
# ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1)
|
||||||
assert isinstance(result.ELECTRICITY_DELIVERED_TARIFF_1, CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject)
|
||||||
assert result.ELECTRICITY_DELIVERED_TARIFF_1.unit == 'kWh'
|
assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh'
|
||||||
assert isinstance(result.ELECTRICITY_DELIVERED_TARIFF_1.value, Decimal)
|
assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal)
|
||||||
assert result.ELECTRICITY_DELIVERED_TARIFF_1.value == Decimal('0.000')
|
assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal('0.000')
|
||||||
|
|
||||||
# ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2)
|
# ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2)
|
||||||
assert isinstance(result.ELECTRICITY_DELIVERED_TARIFF_2, CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject)
|
||||||
assert result.ELECTRICITY_DELIVERED_TARIFF_2.unit == 'kWh'
|
assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh'
|
||||||
assert isinstance(result.ELECTRICITY_DELIVERED_TARIFF_2.value, Decimal)
|
assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal)
|
||||||
assert result.ELECTRICITY_DELIVERED_TARIFF_2.value == Decimal('0.011')
|
assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal('0.011')
|
||||||
|
|
||||||
# ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0)
|
# ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0)
|
||||||
assert isinstance(result.ELECTRICITY_ACTIVE_TARIFF, CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject)
|
||||||
assert result.ELECTRICITY_ACTIVE_TARIFF.unit is None
|
assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None
|
||||||
assert isinstance(result.ELECTRICITY_ACTIVE_TARIFF.value, str)
|
assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str)
|
||||||
assert result.ELECTRICITY_ACTIVE_TARIFF.value == '0001'
|
assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0001'
|
||||||
|
|
||||||
# BELGIUM_CURRENT_AVERAGE_DEMAND (1-0:1.4.0)
|
# BELGIUM_CURRENT_AVERAGE_DEMAND (1-0:1.4.0)
|
||||||
assert isinstance(result.BELGIUM_CURRENT_AVERAGE_DEMAND, CosemObject)
|
assert isinstance(result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND], CosemObject)
|
||||||
assert result.BELGIUM_CURRENT_AVERAGE_DEMAND.unit == 'kW'
|
assert result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].unit == 'kW'
|
||||||
assert isinstance(result.BELGIUM_CURRENT_AVERAGE_DEMAND.value, Decimal)
|
assert isinstance(result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].value, Decimal)
|
||||||
assert result.BELGIUM_CURRENT_AVERAGE_DEMAND.value == Decimal('2.351')
|
assert result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].value == Decimal('2.351')
|
||||||
|
|
||||||
# BELGIUM_MAXIMUM_DEMAND_MONTH (1-0:1.6.0)
|
# BELGIUM_MAXIMUM_DEMAND_MONTH (1-0:1.6.0)
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_MONTH, MBusObject)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH], MBusObject)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_MONTH.unit == 'kW'
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].unit == 'kW'
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_MONTH.value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value, Decimal)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_MONTH.value == Decimal('2.589')
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value == Decimal('2.589')
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_MONTH.datetime, datetime.datetime)
|
|
||||||
assert result.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
|
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 0
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0], MBusObjectPeak)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0], MBusObjectPeak)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].unit == 'kW'
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].unit == 'kW'
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value, Decimal)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].value == Decimal('3.695')
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value == Decimal('3.695')
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].datetime, datetime.datetime)
|
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].datetime == \
|
|
||||||
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 5, 1, 0, 0, 0))
|
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[0].occurred, datetime.datetime)
|
|
||||||
assert result.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
|
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 1
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1], MBusObjectPeak)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1], MBusObjectPeak)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].unit == 'kW'
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].unit == 'kW'
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value, Decimal)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].value == Decimal('5.980')
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value == Decimal('5.980')
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].datetime, datetime.datetime)
|
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].datetime == \
|
|
||||||
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 4, 1, 0, 0, 0))
|
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[1].occurred, datetime.datetime)
|
|
||||||
assert result.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
|
# BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 2
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2], MBusObjectPeak)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2], MBusObjectPeak)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].unit == 'kW'
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].unit == 'kW'
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value, Decimal)
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].value == Decimal('4.318')
|
assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value == Decimal('4.318')
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].datetime, datetime.datetime)
|
|
||||||
assert result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].datetime == \
|
|
||||||
pytz.timezone("Europe/Brussels").localize(datetime.datetime(2020, 3, 1, 0, 0, 0))
|
|
||||||
assert isinstance(result.BELGIUM_MAXIMUM_DEMAND_13_MONTHS[2].occurred, datetime.datetime)
|
|
||||||
assert result.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)
|
# CURRENT_ELECTRICITY_USAGE (1-0:1.7.0)
|
||||||
assert isinstance(result.CURRENT_ELECTRICITY_USAGE, CosemObject)
|
assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject)
|
||||||
assert result.CURRENT_ELECTRICITY_USAGE.unit == 'kW'
|
assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW'
|
||||||
assert isinstance(result.CURRENT_ELECTRICITY_USAGE.value, Decimal)
|
assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal)
|
||||||
assert result.CURRENT_ELECTRICITY_USAGE.value == Decimal('0.000')
|
assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('0.000')
|
||||||
|
|
||||||
# CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0)
|
# CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0)
|
||||||
assert isinstance(result.CURRENT_ELECTRICITY_DELIVERY, CosemObject)
|
assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject)
|
||||||
assert result.CURRENT_ELECTRICITY_DELIVERY.unit == 'kW'
|
assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW'
|
||||||
assert isinstance(result.CURRENT_ELECTRICITY_DELIVERY.value, Decimal)
|
assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal)
|
||||||
assert result.CURRENT_ELECTRICITY_DELIVERY.value == Decimal('0.000')
|
assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE], CosemObject)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE.unit == 'kW'
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].unit == 'kW'
|
||||||
assert isinstance(result.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L1 (1-0:32.7.0)
|
# INSTANTANEOUS_VOLTAGE_L1 (1-0:32.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L1, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1], CosemObject)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L1.unit == 'V'
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L1].unit == 'V'
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L1.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L1.value == Decimal('234.7')
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L1].value == Decimal('234.7')
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0)
|
# INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L2, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2], CosemObject)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L2.unit == 'V'
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L2].unit == 'V'
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L2.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L2.value == Decimal('234.7')
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L2].value == Decimal('234.7')
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0)
|
# INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L3, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3], CosemObject)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L3.unit == 'V'
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L3].unit == 'V'
|
||||||
assert isinstance(result.INSTANTANEOUS_VOLTAGE_L3.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_VOLTAGE_L3.value == Decimal('234.7')
|
assert result[obis.INSTANTANEOUS_VOLTAGE_L3].value == Decimal('234.7')
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0)
|
# INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L1, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1], CosemObject)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L1.unit == 'A'
|
assert result[obis.INSTANTANEOUS_CURRENT_L1].unit == 'A'
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L1.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L1.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_CURRENT_L1].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0)
|
# INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L2, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2], CosemObject)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L2.unit == 'A'
|
assert result[obis.INSTANTANEOUS_CURRENT_L2].unit == 'A'
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L2.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L2.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_CURRENT_L2].value == Decimal('0.000')
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0)
|
# INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0)
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L3, CosemObject)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3], CosemObject)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L3.unit == 'A'
|
assert result[obis.INSTANTANEOUS_CURRENT_L3].unit == 'A'
|
||||||
assert isinstance(result.INSTANTANEOUS_CURRENT_L3.value, Decimal)
|
assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3].value, Decimal)
|
||||||
assert result.INSTANTANEOUS_CURRENT_L3.value == Decimal('0.000')
|
assert result[obis.INSTANTANEOUS_CURRENT_L3].value == Decimal('0.000')
|
||||||
|
|
||||||
# ACTUAL_SWITCH_POSITION (0-0:96.3.10)
|
# ACTUAL_SWITCH_POSITION (0-0:96.3.10)
|
||||||
assert isinstance(result.ACTUAL_SWITCH_POSITION, CosemObject)
|
assert isinstance(result[obis.ACTUAL_SWITCH_POSITION], CosemObject)
|
||||||
assert result.ACTUAL_SWITCH_POSITION.unit is None
|
assert result[obis.ACTUAL_SWITCH_POSITION].unit is None
|
||||||
assert isinstance(result.ACTUAL_SWITCH_POSITION.value, int)
|
assert isinstance(result[obis.ACTUAL_SWITCH_POSITION].value, int)
|
||||||
assert result.ACTUAL_SWITCH_POSITION.value == 1
|
assert result[obis.ACTUAL_SWITCH_POSITION].value == 1
|
||||||
|
|
||||||
# ACTUAL_TRESHOLD_ELECTRICITY (0-0:17.0.0)
|
# BELGIUM_MAX_POWER_PER_PHASE (0-0:17.0.0)
|
||||||
assert isinstance(result.ACTUAL_TRESHOLD_ELECTRICITY, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MAX_POWER_PER_PHASE], CosemObject)
|
||||||
assert result.ACTUAL_TRESHOLD_ELECTRICITY.unit == 'kW'
|
assert result[obis.BELGIUM_MAX_POWER_PER_PHASE].unit == 'kW'
|
||||||
assert isinstance(result.ACTUAL_TRESHOLD_ELECTRICITY.value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAX_POWER_PER_PHASE].value, Decimal)
|
||||||
assert result.ACTUAL_TRESHOLD_ELECTRICITY.value == Decimal('999.9')
|
assert result[obis.BELGIUM_MAX_POWER_PER_PHASE].value == Decimal('999.9')
|
||||||
|
|
||||||
# FUSE_THRESHOLD_L1 (1-0:31.4.0)
|
# BELGIUM_MAX_POWER_PER_PHASE (1-0:31.4.0)
|
||||||
assert isinstance(result.FUSE_THRESHOLD_L1, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MAX_CURRENT_PER_PHASE], CosemObject)
|
||||||
assert result.FUSE_THRESHOLD_L1.unit == 'A'
|
assert result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].unit == 'A'
|
||||||
assert isinstance(result.FUSE_THRESHOLD_L1.value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].value, Decimal)
|
||||||
assert result.FUSE_THRESHOLD_L1.value == Decimal('999')
|
assert result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].value == Decimal('999')
|
||||||
|
|
||||||
# TEXT_MESSAGE (0-0:96.13.0)
|
# TEXT_MESSAGE (0-0:96.13.0)
|
||||||
assert isinstance(result.TEXT_MESSAGE, CosemObject)
|
assert isinstance(result[obis.TEXT_MESSAGE], CosemObject)
|
||||||
assert result.TEXT_MESSAGE.unit is None
|
assert result[obis.TEXT_MESSAGE].unit is None
|
||||||
assert result.TEXT_MESSAGE.value is None
|
assert result[obis.TEXT_MESSAGE].value is None
|
||||||
|
|
||||||
# MBUS DEVICE 1
|
# BELGIUM_MBUS1_DEVICE_TYPE (0-1:24.1.0)
|
||||||
mbus1 = result.get_mbus_device_by_channel(1)
|
assert isinstance(result[obis.BELGIUM_MBUS1_DEVICE_TYPE], CosemObject)
|
||||||
|
assert result[obis.BELGIUM_MBUS1_DEVICE_TYPE].unit is None
|
||||||
|
assert isinstance(result[obis.BELGIUM_MBUS1_DEVICE_TYPE].value, int)
|
||||||
|
assert result[obis.BELGIUM_MBUS1_DEVICE_TYPE].value == 3
|
||||||
|
|
||||||
# MBUS_DEVICE_TYPE (0-1:24.1.0)
|
# BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER (0-1:96.1.1)
|
||||||
assert isinstance(mbus1.MBUS_DEVICE_TYPE, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER], CosemObject)
|
||||||
assert mbus1.MBUS_DEVICE_TYPE.unit is None
|
assert result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].unit is None
|
||||||
assert isinstance(mbus1.MBUS_DEVICE_TYPE.value, int)
|
assert isinstance(result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].value, str)
|
||||||
assert mbus1.MBUS_DEVICE_TYPE.value == 3
|
assert result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].value == '37464C4F32313139303333373333'
|
||||||
|
|
||||||
# MBUS_EQUIPMENT_IDENTIFIER (0-1:96.1.1)
|
# BELGIUM_MBUS1_VALVE_POSITION (0-1:24.4.0)
|
||||||
assert isinstance(mbus1.MBUS_EQUIPMENT_IDENTIFIER, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MBUS1_VALVE_POSITION], CosemObject)
|
||||||
assert mbus1.MBUS_EQUIPMENT_IDENTIFIER.unit is None
|
assert result[obis.BELGIUM_MBUS1_VALVE_POSITION].unit is None
|
||||||
assert isinstance(mbus1.MBUS_EQUIPMENT_IDENTIFIER.value, str)
|
assert isinstance(result[obis.BELGIUM_MBUS1_VALVE_POSITION].value, int)
|
||||||
assert mbus1.MBUS_EQUIPMENT_IDENTIFIER.value == '37464C4F32313139303333373333'
|
assert result[obis.BELGIUM_MBUS1_VALVE_POSITION].value == 1
|
||||||
|
|
||||||
# MBUS_VALVE_POSITION (0-1:24.4.0)
|
# BELGIUM_MBUS1_METER_READING2 (0-1:24.2.3)
|
||||||
assert isinstance(result.MBUS_VALVE_POSITION, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MBUS1_METER_READING2], MBusObject)
|
||||||
assert result.MBUS_VALVE_POSITION.unit is None
|
assert result[obis.BELGIUM_MBUS1_METER_READING2].unit == 'm3'
|
||||||
assert isinstance(result.MBUS_VALVE_POSITION.value, int)
|
assert isinstance(result[obis.BELGIUM_MBUS1_METER_READING2].value, Decimal)
|
||||||
assert result.MBUS_VALVE_POSITION.value == 1
|
assert result[obis.BELGIUM_MBUS1_METER_READING2].value == Decimal('112.384')
|
||||||
|
|
||||||
# MBUS_METER_READING (0-1:24.2.3)
|
# BELGIUM_MBUS2_DEVICE_TYPE (0-2:24.1.0)
|
||||||
assert isinstance(mbus1.MBUS_METER_READING, MBusObject)
|
assert isinstance(result[obis.BELGIUM_MBUS2_DEVICE_TYPE], CosemObject)
|
||||||
assert mbus1.MBUS_METER_READING.unit == 'm3'
|
assert result[obis.BELGIUM_MBUS2_DEVICE_TYPE].unit is None
|
||||||
assert isinstance(mbus1.MBUS_METER_READING.value, Decimal)
|
assert isinstance(result[obis.BELGIUM_MBUS2_DEVICE_TYPE].value, int)
|
||||||
assert mbus1.MBUS_METER_READING.value == Decimal('112.384')
|
assert result[obis.BELGIUM_MBUS2_DEVICE_TYPE].value == 7
|
||||||
|
|
||||||
# MBUS DEVICE 2
|
# BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER (0-2:96.1.1)
|
||||||
mbus2 = result.get_mbus_device_by_channel(2)
|
assert isinstance(result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER], CosemObject)
|
||||||
|
assert result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].unit is None
|
||||||
|
assert isinstance(result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].value, str)
|
||||||
|
assert result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].value == '3853414731323334353637383930'
|
||||||
|
|
||||||
# MBUS_DEVICE_TYPE (0-2:24.1.0)
|
# BELGIUM_MBUS2_METER_READING1 (0-1:24.2.1)
|
||||||
assert isinstance(mbus2.MBUS_DEVICE_TYPE, CosemObject)
|
assert isinstance(result[obis.BELGIUM_MBUS2_METER_READING1], MBusObject)
|
||||||
assert mbus2.MBUS_DEVICE_TYPE.unit is None
|
assert result[obis.BELGIUM_MBUS2_METER_READING1].unit == 'm3'
|
||||||
assert isinstance(mbus2.MBUS_DEVICE_TYPE.value, int)
|
assert isinstance(result[obis.BELGIUM_MBUS2_METER_READING1].value, Decimal)
|
||||||
assert mbus2.MBUS_DEVICE_TYPE.value == 7
|
assert result[obis.BELGIUM_MBUS2_METER_READING1].value == Decimal('872.234')
|
||||||
|
|
||||||
# MBUS_EQUIPMENT_IDENTIFIER (0-2:96.1.1)
|
|
||||||
assert isinstance(mbus2.MBUS_EQUIPMENT_IDENTIFIER, CosemObject)
|
|
||||||
assert mbus2.MBUS_EQUIPMENT_IDENTIFIER.unit is None
|
|
||||||
assert isinstance(mbus2.MBUS_EQUIPMENT_IDENTIFIER.value, str)
|
|
||||||
assert mbus2.MBUS_EQUIPMENT_IDENTIFIER.value == '3853414731323334353637383930'
|
|
||||||
|
|
||||||
# MBUS_METER_READING (0-1:24.2.1)
|
|
||||||
assert isinstance(mbus2.MBUS_METER_READING, MBusObject)
|
|
||||||
assert mbus2.MBUS_METER_READING.unit == 'm3'
|
|
||||||
assert isinstance(mbus2.MBUS_METER_READING.value, Decimal)
|
|
||||||
assert mbus2.MBUS_METER_READING.value == Decimal('872.234')
|
|
||||||
|
|
||||||
def test_checksum_valid(self):
|
def test_checksum_valid(self):
|
||||||
# No exception is raised.
|
# No exception is raised.
|
||||||
@@ -293,121 +263,6 @@ class TelegramParserFluviusTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_checksum_missing(self):
|
def test_checksum_missing(self):
|
||||||
# Remove the checksum value causing a ParseError.
|
# Remove the checksum value causing a ParseError.
|
||||||
corrupted_telegram = TELEGRAM_FLUVIUS_V171.replace('!3AD7\r\n', '')
|
corrupted_telegram = TELEGRAM_FLUVIUS_V171.replace('!911C\r\n', '')
|
||||||
with self.assertRaises(ParseError):
|
with self.assertRaises(ParseError):
|
||||||
TelegramParser.validate_checksum(corrupted_telegram)
|
TelegramParser.validate_checksum(corrupted_telegram)
|
||||||
|
|
||||||
def test_to_json(self):
|
|
||||||
parser = TelegramParser(telegram_specifications.BELGIUM_FLUVIUS)
|
|
||||||
telegram = parser.parse(TELEGRAM_FLUVIUS_V171_ALT)
|
|
||||||
json_data = json.loads(telegram.to_json())
|
|
||||||
|
|
||||||
self.maxDiff = None
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
json_data,
|
|
||||||
{'BELGIUM_VERSION_INFORMATION': {'value': '50217', 'unit': None},
|
|
||||||
'BELGIUM_EQUIPMENT_IDENTIFIER': {'value': '3153414733313030373231333236', 'unit': None},
|
|
||||||
'P1_MESSAGE_TIMESTAMP': {'value': '2023-11-02T11:15:48+00:00', 'unit': None},
|
|
||||||
'ELECTRICITY_USED_TARIFF_1': {'value': 301.548, 'unit': 'kWh'},
|
|
||||||
'ELECTRICITY_USED_TARIFF_2': {'value': 270.014, 'unit': 'kWh'},
|
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_1': {'value': 0.005, 'unit': 'kWh'},
|
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_2': {'value': 0.0, 'unit': 'kWh'},
|
|
||||||
'ELECTRICITY_ACTIVE_TARIFF': {'value': '0001', 'unit': None},
|
|
||||||
'BELGIUM_CURRENT_AVERAGE_DEMAND': {'value': 0.052, 'unit': 'kW'},
|
|
||||||
'BELGIUM_MAXIMUM_DEMAND_MONTH': {'datetime': '2023-11-02T10:45:00+00:00',
|
|
||||||
'value': 3.064, 'unit': 'kW'},
|
|
||||||
'BELGIUM_MAXIMUM_DEMAND_13_MONTHS': [{'datetime': '2023-07-31T22:00:00+00:00',
|
|
||||||
'occurred': None, 'value': 0.0, 'unit': 'kW'},
|
|
||||||
{'datetime': '2023-08-31T22:00:00+00:00',
|
|
||||||
'occurred': '2023-08-31T16:15:00+00:00',
|
|
||||||
'value': 1.862, 'unit': 'kW'},
|
|
||||||
{'datetime': '2023-09-30T22:00:00+00:00',
|
|
||||||
'occurred': '2023-09-10T16:30:00+00:00',
|
|
||||||
'value': 4.229, 'unit': 'kW'},
|
|
||||||
{'datetime': '2023-10-31T23:00:00+00:00',
|
|
||||||
'occurred': '2023-10-16T11:00:00+00:00',
|
|
||||||
'value': 4.927, 'unit': 'kW'}],
|
|
||||||
'CURRENT_ELECTRICITY_USAGE': {'value': 0.338, 'unit': 'kW'},
|
|
||||||
'CURRENT_ELECTRICITY_DELIVERY': {'value': 0.0, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE': {'value': 0.047, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE': {'value': 0.179, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE': {'value': 0.111, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE': {'value': 0.0, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE': {'value': 0.0, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE': {'value': 0.0, 'unit': 'kW'},
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L1': {'value': 232.9, 'unit': 'V'},
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L2': {'value': 228.1, 'unit': 'V'},
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L3': {'value': 228.1, 'unit': 'V'},
|
|
||||||
'INSTANTANEOUS_CURRENT_L1': {'value': 0.27, 'unit': 'A'},
|
|
||||||
'INSTANTANEOUS_CURRENT_L2': {'value': 0.88, 'unit': 'A'},
|
|
||||||
'INSTANTANEOUS_CURRENT_L3': {'value': 0.52, 'unit': 'A'},
|
|
||||||
'ACTUAL_SWITCH_POSITION': {'value': 1, 'unit': None},
|
|
||||||
'ACTUAL_TRESHOLD_ELECTRICITY': {'value': 999.9, 'unit': 'kW'},
|
|
||||||
'FUSE_THRESHOLD_L1': {'value': 999.0, 'unit': 'A'},
|
|
||||||
'TEXT_MESSAGE': {'value': None, 'unit': None},
|
|
||||||
'MBUS_DEVICES': [{'MBUS_DEVICE_TYPE': {'value': 3, 'unit': None},
|
|
||||||
'MBUS_EQUIPMENT_IDENTIFIER': {'value': '37464C4F32313233303838303237',
|
|
||||||
'unit': None},
|
|
||||||
'MBUS_VALVE_POSITION': {'value': 1, 'unit': None},
|
|
||||||
'MBUS_METER_READING': {'datetime': '2023-11-02T11:10:02+00:00',
|
|
||||||
'value': 92.287, 'unit': 'm3'},
|
|
||||||
'CHANNEL_ID': 1},
|
|
||||||
{'MBUS_DEVICE_TYPE': {'value': 7, 'unit': None},
|
|
||||||
'MBUS_EQUIPMENT_IDENTIFIER': {'value': '3853455430303030393631313733',
|
|
||||||
'unit': None},
|
|
||||||
'MBUS_METER_READING': {'datetime': '2023-11-02T11:15:32+00:00',
|
|
||||||
'value': 8.579, 'unit': 'm3'},
|
|
||||||
'CHANNEL_ID': 2}]}
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_to_str(self):
|
|
||||||
parser = TelegramParser(telegram_specifications.BELGIUM_FLUVIUS)
|
|
||||||
telegram = parser.parse(TELEGRAM_FLUVIUS_V171_ALT)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(telegram),
|
|
||||||
(
|
|
||||||
'BELGIUM_VERSION_INFORMATION: 50217 [None]\n'
|
|
||||||
'BELGIUM_EQUIPMENT_IDENTIFIER: 3153414733313030373231333236 [None]\n'
|
|
||||||
'P1_MESSAGE_TIMESTAMP: 2023-11-02T11:15:48+00:00 [None]\n'
|
|
||||||
'ELECTRICITY_USED_TARIFF_1: 301.548 [kWh]\n'
|
|
||||||
'ELECTRICITY_USED_TARIFF_2: 270.014 [kWh]\n'
|
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_1: 0.005 [kWh]\n'
|
|
||||||
'ELECTRICITY_DELIVERED_TARIFF_2: 0.000 [kWh]\n'
|
|
||||||
'ELECTRICITY_ACTIVE_TARIFF: 0001 [None]\n'
|
|
||||||
'BELGIUM_CURRENT_AVERAGE_DEMAND: 0.052 [kW]\n'
|
|
||||||
'BELGIUM_MAXIMUM_DEMAND_MONTH: 3.064 [kW] at 2023-11-02T10:45:00+00:00\n'
|
|
||||||
'0.0 [kW] at 2023-07-31T22:00:00+00:00 occurred None'
|
|
||||||
'1.862 [kW] at 2023-08-31T22:00:00+00:00 occurred 2023-08-31T16:15:00+00:00'
|
|
||||||
'4.229 [kW] at 2023-09-30T22:00:00+00:00 occurred 2023-09-10T16:30:00+00:00'
|
|
||||||
'4.927 [kW] at 2023-10-31T23:00:00+00:00 occurred 2023-10-16T11:00:00+00:00'
|
|
||||||
'CURRENT_ELECTRICITY_USAGE: 0.338 [kW]\n'
|
|
||||||
'CURRENT_ELECTRICITY_DELIVERY: 0.000 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 0.047 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 0.179 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 0.111 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: 0.000 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: 0.000 [kW]\n'
|
|
||||||
'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: 0.000 [kW]\n'
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L1: 232.9 [V]\n'
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L2: 228.1 [V]\n'
|
|
||||||
'INSTANTANEOUS_VOLTAGE_L3: 228.1 [V]\n'
|
|
||||||
'INSTANTANEOUS_CURRENT_L1: 0.27 [A]\n'
|
|
||||||
'INSTANTANEOUS_CURRENT_L2: 0.88 [A]\n'
|
|
||||||
'INSTANTANEOUS_CURRENT_L3: 0.52 [A]\n'
|
|
||||||
'ACTUAL_SWITCH_POSITION: 1 [None]\n'
|
|
||||||
'ACTUAL_TRESHOLD_ELECTRICITY: 999.9 [kW]\n'
|
|
||||||
'FUSE_THRESHOLD_L1: 999 [A]\n'
|
|
||||||
'TEXT_MESSAGE: None [None]\n'
|
|
||||||
'MBUS DEVICE (channel 1)\n'
|
|
||||||
' MBUS_DEVICE_TYPE: 3 [None]\n'
|
|
||||||
' MBUS_EQUIPMENT_IDENTIFIER: 37464C4F32313233303838303237 [None]\n'
|
|
||||||
' MBUS_VALVE_POSITION: 1 [None]\n'
|
|
||||||
' MBUS_METER_READING: 92.287 [m3] at 2023-11-02T11:10:02+00:00\n'
|
|
||||||
'MBUS DEVICE (channel 2)\n'
|
|
||||||
' MBUS_DEVICE_TYPE: 7 [None]\n'
|
|
||||||
' MBUS_EQUIPMENT_IDENTIFIER: 3853455430303030393631313733 [None]\n'
|
|
||||||
' MBUS_METER_READING: 8.579 [m3] at 2023-11-02T11:15:32+00:00\n'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ class TelegramParserIskraIETest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.ISKRA_IE)
|
parser = TelegramParser(telegram_specifications.ISKRA_IE)
|
||||||
try:
|
result = parser.parse(TELEGRAM_ISKRA_IE)
|
||||||
result = parser.parse(TELEGRAM_ISKRA_IE, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# EQUIPMENT_IDENTIFIER_GAS (0-0:96.1.0)
|
# EQUIPMENT_IDENTIFIER_GAS (0-0:96.1.0)
|
||||||
assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject)
|
assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject)
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ class TelegramParserV2_2Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.V2_2)
|
parser = TelegramParser(telegram_specifications.V2_2)
|
||||||
try:
|
result = parser.parse(TELEGRAM_V2_2)
|
||||||
result = parser.parse(TELEGRAM_V2_2, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
||||||
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ class TelegramParserV3Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.V3)
|
parser = TelegramParser(telegram_specifications.V3)
|
||||||
try:
|
result = parser.parse(TELEGRAM_V3)
|
||||||
result = parser.parse(TELEGRAM_V3, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
||||||
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
|
assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject)
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ class TelegramParserV4_2Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.V4)
|
parser = TelegramParser(telegram_specifications.V4)
|
||||||
try:
|
result = parser.parse(TELEGRAM_V4_2)
|
||||||
result = parser.parse(TELEGRAM_V4_2, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# P1_MESSAGE_HEADER (1-3:0.2.8)
|
# P1_MESSAGE_HEADER (1-3:0.2.8)
|
||||||
assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject)
|
assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject)
|
||||||
|
|||||||
+29
-29
@@ -17,11 +17,8 @@ class TelegramParserV5Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
parser = TelegramParser(telegram_specifications.V5)
|
parser = TelegramParser(telegram_specifications.V5)
|
||||||
try:
|
telegram = parser.parse(TELEGRAM_V5)
|
||||||
telegram = parser.parse(TELEGRAM_V5, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
print('test: ', type(telegram.P1_MESSAGE_HEADER), telegram.P1_MESSAGE_HEADER.__dict__)
|
|
||||||
# P1_MESSAGE_HEADER (1-3:0.2.8)
|
# P1_MESSAGE_HEADER (1-3:0.2.8)
|
||||||
assert isinstance(telegram.P1_MESSAGE_HEADER, CosemObject)
|
assert isinstance(telegram.P1_MESSAGE_HEADER, CosemObject)
|
||||||
assert telegram.P1_MESSAGE_HEADER.unit is None
|
assert telegram.P1_MESSAGE_HEADER.unit is None
|
||||||
@@ -172,6 +169,12 @@ class TelegramParserV5Test(unittest.TestCase):
|
|||||||
assert telegram.TEXT_MESSAGE.unit is None
|
assert telegram.TEXT_MESSAGE.unit is None
|
||||||
assert telegram.TEXT_MESSAGE.value is None
|
assert telegram.TEXT_MESSAGE.value is None
|
||||||
|
|
||||||
|
# DEVICE_TYPE (0-x:24.1.0)
|
||||||
|
assert isinstance(telegram.DEVICE_TYPE, CosemObject)
|
||||||
|
assert telegram.DEVICE_TYPE.unit is None
|
||||||
|
assert isinstance(telegram.DEVICE_TYPE.value, int)
|
||||||
|
assert telegram.DEVICE_TYPE.value == 3
|
||||||
|
|
||||||
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
# INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0)
|
||||||
assert isinstance(telegram.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE, CosemObject)
|
assert isinstance(telegram.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE, CosemObject)
|
||||||
assert telegram.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE.unit == 'kW'
|
assert telegram.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE.unit == 'kW'
|
||||||
@@ -209,27 +212,27 @@ class TelegramParserV5Test(unittest.TestCase):
|
|||||||
assert telegram.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE.value == Decimal('0')
|
assert telegram.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE.value == Decimal('0')
|
||||||
|
|
||||||
# There's only one Mbus device (gas meter) in this case. Alternatively
|
# There's only one Mbus device (gas meter) in this case. Alternatively
|
||||||
# use get_mbus_device_by_channel
|
# use get_mbget_mbus_device_by_channel
|
||||||
gas_meter_devices = telegram.MBUS_DEVICES
|
gas_meter_devices = telegram.MBUS_DEVICES
|
||||||
gas_meter_device = gas_meter_devices[0]
|
gas_meter_device = gas_meter_devices[0]
|
||||||
|
|
||||||
# MBUS_DEVICE_TYPE (0-1:96.1.0)
|
# EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0)
|
||||||
assert isinstance(gas_meter_device.MBUS_DEVICE_TYPE, CosemObject)
|
assert isinstance(gas_meter_device.DEVICE_TYPE, CosemObject)
|
||||||
assert gas_meter_device.MBUS_DEVICE_TYPE.unit is None
|
assert gas_meter_device.DEVICE_TYPE.unit is None
|
||||||
assert isinstance(gas_meter_device.MBUS_DEVICE_TYPE.value, int)
|
assert isinstance(gas_meter_device.DEVICE_TYPE.value, int)
|
||||||
assert gas_meter_device.MBUS_DEVICE_TYPE.value == 3
|
assert gas_meter_device.DEVICE_TYPE.value == 3
|
||||||
|
|
||||||
# MBUS_EQUIPMENT_IDENTIFIER (0-1:96.1.0)
|
# EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0)
|
||||||
assert isinstance(gas_meter_device.MBUS_EQUIPMENT_IDENTIFIER, CosemObject)
|
assert isinstance(gas_meter_device.EQUIPMENT_IDENTIFIER_GAS, CosemObject)
|
||||||
assert gas_meter_device.MBUS_EQUIPMENT_IDENTIFIER.unit is None
|
assert gas_meter_device.EQUIPMENT_IDENTIFIER_GAS.unit is None
|
||||||
assert isinstance(gas_meter_device.MBUS_EQUIPMENT_IDENTIFIER.value, str)
|
assert isinstance(gas_meter_device.EQUIPMENT_IDENTIFIER_GAS.value, str)
|
||||||
assert gas_meter_device.MBUS_EQUIPMENT_IDENTIFIER.value == '3232323241424344313233343536373839'
|
assert gas_meter_device.EQUIPMENT_IDENTIFIER_GAS.value == '3232323241424344313233343536373839'
|
||||||
|
|
||||||
# MBUS_METER_READING (0-1:24.2.1)
|
# HOURLY_GAS_METER_READING (0-1:24.2.1)
|
||||||
assert isinstance(gas_meter_device.MBUS_METER_READING, MBusObject)
|
assert isinstance(gas_meter_device.HOURLY_GAS_METER_READING, MBusObject)
|
||||||
assert gas_meter_device.MBUS_METER_READING.unit == 'm3'
|
assert gas_meter_device.HOURLY_GAS_METER_READING.unit == 'm3'
|
||||||
assert isinstance(telegram.MBUS_METER_READING.value, Decimal)
|
assert isinstance(telegram.HOURLY_GAS_METER_READING.value, Decimal)
|
||||||
assert gas_meter_device.MBUS_METER_READING.value == Decimal('0.107')
|
assert gas_meter_device.HOURLY_GAS_METER_READING.value == Decimal('0.107')
|
||||||
|
|
||||||
def test_checksum_valid(self):
|
def test_checksum_valid(self):
|
||||||
# No exception is raised.
|
# No exception is raised.
|
||||||
@@ -264,11 +267,8 @@ class TelegramParserV5Test(unittest.TestCase):
|
|||||||
parser = TelegramParser(telegram_specifications.V5)
|
parser = TelegramParser(telegram_specifications.V5)
|
||||||
telegram = parser.parse(invalid_date_telegram)
|
telegram = parser.parse(invalid_date_telegram)
|
||||||
|
|
||||||
# MBUS DEVICE 1
|
# HOURLY_GAS_METER_READING (0-1:24.2.1)
|
||||||
mbus1 = telegram.get_mbus_device_by_channel(1)
|
assert isinstance(telegram.HOURLY_GAS_METER_READING, MBusObject)
|
||||||
|
assert telegram.HOURLY_GAS_METER_READING.unit is None
|
||||||
# MBUS_METER_READING (0-1:24.2.1)
|
assert isinstance(telegram.HOURLY_GAS_METER_READING.value, Decimal)
|
||||||
assert isinstance(mbus1.MBUS_METER_READING, MBusObject)
|
assert telegram.HOURLY_GAS_METER_READING.value == Decimal('0.000')
|
||||||
assert mbus1.MBUS_METER_READING.unit is None
|
|
||||||
assert isinstance(mbus1.MBUS_METER_READING.value, Decimal)
|
|
||||||
assert mbus1.MBUS_METER_READING.value == Decimal('0.000')
|
|
||||||
|
|||||||
@@ -1,308 +0,0 @@
|
|||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
|
|
||||||
from dsmr_parser import telegram_specifications
|
|
||||||
from dsmr_parser.exceptions import InvalidChecksumError, ParseError
|
|
||||||
from dsmr_parser.objects import CosemObject
|
|
||||||
from dsmr_parser.parsers import TelegramParser
|
|
||||||
from test.example_telegrams import TELEGRAM_V5_EON_HU
|
|
||||||
|
|
||||||
|
|
||||||
class TelegramParserV5EONHUTest(unittest.TestCase):
|
|
||||||
""" Test parsing of a DSMR v5 EON Hungary telegram. """
|
|
||||||
|
|
||||||
def test_parse(self):
|
|
||||||
parser = TelegramParser(telegram_specifications.EON_HUNGARY)
|
|
||||||
try:
|
|
||||||
telegram = parser.parse(TELEGRAM_V5_EON_HU, throw_ex=True)
|
|
||||||
except Exception as ex:
|
|
||||||
assert False, f"parse trigged an exception {ex}"
|
|
||||||
|
|
||||||
# P1_MESSAGE_TIMESTAMP (0-0:1.0.0)
|
|
||||||
assert isinstance(telegram.P1_MESSAGE_TIMESTAMP, CosemObject)
|
|
||||||
assert telegram.P1_MESSAGE_TIMESTAMP.unit is None
|
|
||||||
assert isinstance(telegram.P1_MESSAGE_TIMESTAMP.value, datetime.datetime)
|
|
||||||
assert telegram.P1_MESSAGE_TIMESTAMP.value == \
|
|
||||||
pytz.timezone("Europe/Budapest").localize(datetime.datetime(2023, 7, 24, 15, 7, 30))
|
|
||||||
|
|
||||||
# EON_HU_COSEM_LOGICAL_DEVICE_NAME (0-0:42.0.0)
|
|
||||||
assert isinstance(telegram.COSEM_LOGICAL_DEVICE_NAME, CosemObject)
|
|
||||||
assert telegram.COSEM_LOGICAL_DEVICE_NAME.unit is None
|
|
||||||
assert isinstance(telegram.COSEM_LOGICAL_DEVICE_NAME.value, str)
|
|
||||||
assert telegram.COSEM_LOGICAL_DEVICE_NAME.value == '53414733303832323030303032313630'
|
|
||||||
|
|
||||||
# EON_HU_EQUIPMENT_SERIAL_NUMBER (0-0:96.1.0)
|
|
||||||
assert isinstance(telegram.EQUIPMENT_SERIAL_NUMBER, CosemObject)
|
|
||||||
assert telegram.EQUIPMENT_SERIAL_NUMBER.unit is None
|
|
||||||
assert isinstance(telegram.EQUIPMENT_SERIAL_NUMBER.value, str)
|
|
||||||
assert telegram.EQUIPMENT_SERIAL_NUMBER.value == '383930303832323030303032313630'
|
|
||||||
|
|
||||||
# ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_ACTIVE_TARIFF, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_ACTIVE_TARIFF.unit is None
|
|
||||||
assert isinstance(telegram.ELECTRICITY_ACTIVE_TARIFF.value, str)
|
|
||||||
assert telegram.ELECTRICITY_ACTIVE_TARIFF.value == '0001'
|
|
||||||
|
|
||||||
# ACTUAL_SWITCH_POSITION (0-0:96.3.10)
|
|
||||||
assert isinstance(telegram.ACTUAL_SWITCH_POSITION, CosemObject)
|
|
||||||
assert telegram.ACTUAL_SWITCH_POSITION.unit is None
|
|
||||||
assert isinstance(telegram.ACTUAL_SWITCH_POSITION.value, str)
|
|
||||||
assert telegram.ACTUAL_SWITCH_POSITION.value == '1'
|
|
||||||
|
|
||||||
# ACTUAL_TRESHOLD_ELECTRICITY (0-0:17.0.0)
|
|
||||||
assert isinstance(telegram.ACTUAL_TRESHOLD_ELECTRICITY, CosemObject)
|
|
||||||
assert telegram.ACTUAL_TRESHOLD_ELECTRICITY.unit == 'kW'
|
|
||||||
assert isinstance(telegram.ACTUAL_TRESHOLD_ELECTRICITY.value, Decimal)
|
|
||||||
assert telegram.ACTUAL_TRESHOLD_ELECTRICITY.value == Decimal('90.000')
|
|
||||||
|
|
||||||
# ELECTRICITY_IMPORTED_TOTAL (1-0:1.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_IMPORTED_TOTAL, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_IMPORTED_TOTAL.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_IMPORTED_TOTAL.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_IMPORTED_TOTAL.value == Decimal('000173.640')
|
|
||||||
|
|
||||||
# ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_1, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_1.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_1.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_1.value == Decimal('000047.719')
|
|
||||||
|
|
||||||
# ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_2, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_2.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_2.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_2.value == Decimal('000125.921')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_USED_TARIFF_3 (1-0:1.8.3)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_3, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_3.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_3.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_3.value == Decimal('000000.000')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_USED_TARIFF_4 (1-0:1.8.4)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_4, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_4.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_USED_TARIFF_4.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_USED_TARIFF_4.value == Decimal('000000.000')
|
|
||||||
|
|
||||||
# ELECTRICITY_EXPORTED_TOTAL (1-0:2.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_EXPORTED_TOTAL, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_EXPORTED_TOTAL.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_EXPORTED_TOTAL.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_EXPORTED_TOTAL.value == Decimal('000627.177')
|
|
||||||
|
|
||||||
# ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_1, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_1.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_1.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_1.value == Decimal('000401.829')
|
|
||||||
|
|
||||||
# ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_2, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_2.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_2.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_2.value == Decimal('000225.348')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_DELIVERED_TARIFF_3 (1-0:2.8.3)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_3, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_3.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_3.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_3.value == Decimal('000000.000')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_DELIVERED_TARIFF_4 (1-0:2.8.4)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_4, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_4.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_4.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_DELIVERED_TARIFF_4.value == Decimal('000000.000')
|
|
||||||
|
|
||||||
# ELECTRICITY_REACTIVE_IMPORTED_TOTAL (1-0:3.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.value == Decimal('000000.123')
|
|
||||||
|
|
||||||
# ELECTRICITY_REACTIVE_EXPORTED_TOTAL (1-0:4.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.value == Decimal('000303.131')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q1 (1-0:5.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q1, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.value == Decimal('000000.668')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q2 (1-0:6.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q2, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.value == Decimal('000000.071')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q3 (1-0:7.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q3, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.value == Decimal('000160.487')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q4 (1-0:8.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q4, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.unit == 'kvarh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.value == Decimal('000143.346')
|
|
||||||
|
|
||||||
# EON_HU_ELECTRICITY_COMBINED (1-0:15.8.0)
|
|
||||||
assert isinstance(telegram.ELECTRICITY_COMBINED, CosemObject)
|
|
||||||
assert telegram.ELECTRICITY_COMBINED.unit == 'kWh'
|
|
||||||
assert isinstance(telegram.ELECTRICITY_COMBINED.value, Decimal)
|
|
||||||
assert telegram.ELECTRICITY_COMBINED.value == Decimal('000800.817')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L2 (1-0:32.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L1, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L1.unit == 'V'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L1.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L1.value == Decimal('240.4')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L2, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L2.unit == 'V'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L2.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L2.value == Decimal('239.1')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L3, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L3.unit == 'V'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L3.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_VOLTAGE_L3.value == Decimal('241.2')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L1, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L1.unit == 'A'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L1.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L1.value == Decimal('003')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L2, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L2.unit == 'A'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L2.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L2.value == Decimal('004')
|
|
||||||
|
|
||||||
# INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L3, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L3.unit == 'A'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_CURRENT_L3.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_CURRENT_L3.value == Decimal('003')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_POWER_FACTOR_TOTAL (1-0:13.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.unit is None
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.value == Decimal('4.556')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_POWER_FACTOR_L1 (1-0:33.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L1, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L1.unit is None
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L1.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L1.value == Decimal('4.591')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_POWER_FACTOR_L2 (1-0:53.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L2, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L2.unit is None
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L2.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L2.value == Decimal('4.542')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_POWER_FACTOR_L3 (1-0:73.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L3, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L3.unit is None
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L3.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_POWER_FACTOR_L3.value == Decimal('4.552')
|
|
||||||
|
|
||||||
# EON_HU_FREQUENCY (1-0:14.7.0)
|
|
||||||
assert isinstance(telegram.FREQUENCY, CosemObject)
|
|
||||||
assert telegram.FREQUENCY.unit == "Hz"
|
|
||||||
assert isinstance(telegram.FREQUENCY.value, Decimal)
|
|
||||||
assert telegram.FREQUENCY.value == Decimal('50.00')
|
|
||||||
|
|
||||||
# CURRENT_ELECTRICITY_USAGE (1-0:1.7.0)
|
|
||||||
assert isinstance(telegram.CURRENT_ELECTRICITY_USAGE, CosemObject)
|
|
||||||
assert telegram.CURRENT_ELECTRICITY_USAGE.unit == 'kW'
|
|
||||||
assert isinstance(telegram.CURRENT_ELECTRICITY_USAGE.value, Decimal)
|
|
||||||
assert telegram.CURRENT_ELECTRICITY_USAGE.value == Decimal('00.000')
|
|
||||||
|
|
||||||
# CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0)
|
|
||||||
assert isinstance(telegram.CURRENT_ELECTRICITY_DELIVERY, CosemObject)
|
|
||||||
assert telegram.CURRENT_ELECTRICITY_DELIVERY.unit == 'kW'
|
|
||||||
assert isinstance(telegram.CURRENT_ELECTRICITY_DELIVERY.value, Decimal)
|
|
||||||
assert telegram.CURRENT_ELECTRICITY_DELIVERY.value == Decimal('02.601')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q1 (1-0:5.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q1, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.unit == 'kvar'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.value == Decimal('00.000')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q2 (1-0:6.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q2, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.unit == 'kvar'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.value == Decimal('00.000')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q3 (1-0:7.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q3, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.unit == 'kvar'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.value == Decimal('00.504')
|
|
||||||
|
|
||||||
# EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q4 (1-0:8.7.0)
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q4, CosemObject)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.unit == 'kvar'
|
|
||||||
assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.value, Decimal)
|
|
||||||
assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.value == Decimal('00.000')
|
|
||||||
|
|
||||||
# FUSE_THRESHOLD_L1 (1-0:31.4.0)
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L1, CosemObject)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L1.unit == 'A'
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L1.value, Decimal)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L1.value == Decimal('200.00')
|
|
||||||
|
|
||||||
# FUSE_THRESHOLD_L2 (1-0:31.4.0)
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L2, CosemObject)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L2.unit == 'A'
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L2.value, Decimal)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L2.value == Decimal('200.00')
|
|
||||||
|
|
||||||
# FUSE_THRESHOLD_L3 (1-0:31.4.0)
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L3, CosemObject)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L3.unit == 'A'
|
|
||||||
assert isinstance(telegram.FUSE_THRESHOLD_L3.value, Decimal)
|
|
||||||
assert telegram.FUSE_THRESHOLD_L3.value == Decimal('200.00')
|
|
||||||
|
|
||||||
# TEXT_MESSAGE (0-0:96.13.0)
|
|
||||||
assert isinstance(telegram.TEXT_MESSAGE, CosemObject)
|
|
||||||
assert telegram.TEXT_MESSAGE.unit is None
|
|
||||||
assert telegram.TEXT_MESSAGE.value is None
|
|
||||||
|
|
||||||
def test_checksum_valid(self):
|
|
||||||
# No exception is raised.
|
|
||||||
TelegramParser.validate_checksum(TELEGRAM_V5_EON_HU)
|
|
||||||
|
|
||||||
def test_checksum_invalid(self):
|
|
||||||
# Remove the electricty used data value. This causes the checksum to
|
|
||||||
# not match anymore.
|
|
||||||
corrupted_telegram = TELEGRAM_V5_EON_HU.replace(
|
|
||||||
'1-0:1.8.1(000047.719*kWh)\r\n',
|
|
||||||
''
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(InvalidChecksumError):
|
|
||||||
TelegramParser.validate_checksum(corrupted_telegram)
|
|
||||||
|
|
||||||
def test_checksum_missing(self):
|
|
||||||
# Remove the checksum value causing a ParseError.
|
|
||||||
corrupted_telegram = TELEGRAM_V5_EON_HU.replace('!99DA\r\n', '')
|
|
||||||
with self.assertRaises(ParseError):
|
|
||||||
TelegramParser.validate_checksum(corrupted_telegram)
|
|
||||||
@@ -68,6 +68,6 @@ class ProtocolTest(unittest.TestCase):
|
|||||||
|
|
||||||
# 2nd call of keep_alive should close the transport
|
# 2nd call of keep_alive should close the transport
|
||||||
self.protocol.keep_alive()
|
self.protocol.keep_alive()
|
||||||
mock_transport.close.assert_called_once()
|
assert mock_transport.close.called_once()
|
||||||
|
|
||||||
self.protocol.connection_lost(None)
|
self.protocol.connection_lost(None)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ deps=
|
|||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
pytest-mock
|
pytest-mock
|
||||||
dlms_cosem
|
dlms_cosem
|
||||||
setuptools
|
|
||||||
commands=
|
commands=
|
||||||
py.test --cov=dsmr_parser test {posargs}
|
py.test --cov=dsmr_parser test {posargs}
|
||||||
pylama dsmr_parser test
|
pylama dsmr_parser test
|
||||||
@@ -14,9 +13,6 @@ commands=
|
|||||||
[pylama:dsmr_parser/clients/__init__.py]
|
[pylama:dsmr_parser/clients/__init__.py]
|
||||||
ignore = W0611
|
ignore = W0611
|
||||||
|
|
||||||
[pylama:dsmr_parser/clients/socket_.py]
|
|
||||||
ignore = C901
|
|
||||||
|
|
||||||
[pylama:dsmr_parser/parsers.py]
|
[pylama:dsmr_parser/parsers.py]
|
||||||
ignore = W605
|
ignore = W605
|
||||||
|
|
||||||
@@ -27,4 +23,4 @@ ignore = E501
|
|||||||
max_line_length = 120
|
max_line_length = 120
|
||||||
|
|
||||||
[pylama:pycodestyle]
|
[pylama:pycodestyle]
|
||||||
max_line_length = 120
|
max_line_length = 120
|
||||||
Reference in New Issue
Block a user