Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60af45be25 | ||
|
|
00248f490e | ||
|
|
45cc88942a | ||
|
|
26ac27c347 | ||
|
|
7a89d6e97b | ||
|
|
de4dc2ec98 | ||
|
|
6866e7d585 | ||
|
|
df59f3a498 | ||
|
|
4073917d3e | ||
|
|
3a4fcd7da1 | ||
|
|
d5b427ba4f | ||
|
|
c1202f33e9 | ||
|
|
3092ba8b1f | ||
|
|
8e2bdd3279 | ||
|
|
2b724b87c3 | ||
|
|
17b56ae07b | ||
|
|
e4f384c2b7 | ||
|
|
8b8b952ce1 | ||
|
|
007b3ea089 | ||
|
|
761aaccb3f | ||
|
|
dc608f9da3 | ||
|
|
88ef4f4921 | ||
|
|
61de170a79 | ||
|
|
947fd64377 | ||
|
|
62aa0ac3ab | ||
|
|
da98cf1d05 | ||
|
|
fcb0dc600b | ||
|
|
b3a705a74d | ||
|
|
4688cf9058 | ||
|
|
fb9e488102 | ||
|
|
e30c951c7f |
@@ -0,0 +1,45 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push: ~
|
||||
pull_request: ~
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10 # Don't run forever when stale
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.8
|
||||
- 3.9
|
||||
|
||||
name: Python ${{ matrix.python-version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Cached PIP dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.tox/python/.pytest_cache
|
||||
key: pip-${{ matrix.python-version }}-${{ hashFiles('setup.py', 'tox.ini') }}
|
||||
restore-keys: pip-${{ matrix.python-version }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox
|
||||
|
||||
- name: Code coverage upload
|
||||
uses: codecov/codecov-action@v1
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- 2.7
|
||||
- 3.5
|
||||
- 3.6
|
||||
- 3.8
|
||||
|
||||
install: pip install tox-travis codecov
|
||||
|
||||
script: tox
|
||||
|
||||
after_success:
|
||||
- codecov
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: 2.7
|
||||
@@ -1,6 +1,9 @@
|
||||
Change Log
|
||||
----------
|
||||
|
||||
**0.31** (2021-11-21)
|
||||
- Support for (German) EasyMeter Q3D using COM-1 Ethernet Gateway (`pull request #92 <https://github.com/ndokter/dsmr_parser/pull/92>`_).
|
||||
|
||||
**0.30** (2021-08-18)
|
||||
- Add support for Swedish smart meters (`pull request #86 <https://github.com/ndokter/dsmr_parser/pull/86>`_).
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
**Notice:** this repository is in need of a new maintainer. If you are interested or have ideas about this, please let me know.
|
||||
|
||||
|
||||
DSMR Parser
|
||||
===========
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ def console():
|
||||
help='alternatively connect using TCP host.')
|
||||
parser.add_argument('--port', default=None,
|
||||
help='TCP port to use for connection')
|
||||
parser.add_argument('--version', default='2.2', choices=['2.2', '4', '5', '5B', '5L', '5S'],
|
||||
help='DSMR version (2.2, 4, 5, 5B, 5L, 5S)')
|
||||
parser.add_argument('--version', default='2.2', choices=['2.2', '4', '5', '5B', '5L', '5S', 'Q3D'],
|
||||
help='DSMR version (2.2, 4, 5, 5B, 5L, 5S, Q3D)')
|
||||
parser.add_argument('--verbose', '-v', action='count')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -23,6 +23,9 @@ def create_dsmr_protocol(dsmr_version, telegram_callback, loop=None, **kwargs):
|
||||
elif dsmr_version == '4':
|
||||
specification = telegram_specifications.V4
|
||||
serial_settings = SERIAL_SETTINGS_V4
|
||||
elif dsmr_version == '4+':
|
||||
specification = telegram_specifications.V5
|
||||
serial_settings = SERIAL_SETTINGS_V4
|
||||
elif dsmr_version == '5':
|
||||
specification = telegram_specifications.V5
|
||||
serial_settings = SERIAL_SETTINGS_V5
|
||||
@@ -35,6 +38,9 @@ def create_dsmr_protocol(dsmr_version, telegram_callback, loop=None, **kwargs):
|
||||
elif dsmr_version == "5S":
|
||||
specification = telegram_specifications.SWEDEN
|
||||
serial_settings = SERIAL_SETTINGS_V5
|
||||
elif dsmr_version == "Q3D":
|
||||
specification = telegram_specifications.Q3D
|
||||
serial_settings = SERIAL_SETTINGS_V5
|
||||
else:
|
||||
raise NotImplementedError("No telegram parser found for version: %s",
|
||||
dsmr_version)
|
||||
@@ -99,12 +105,16 @@ class DSMRProtocol(asyncio.Protocol):
|
||||
|
||||
def data_received(self, data):
|
||||
"""Add incoming data to buffer."""
|
||||
data = data.decode('ascii')
|
||||
|
||||
# accept latin-1 (8-bit) on the line, to allow for non-ascii transport or padding
|
||||
data = data.decode("latin1")
|
||||
self._active = True
|
||||
self.log.debug('received data: %s', data)
|
||||
self.telegram_buffer.append(data)
|
||||
|
||||
for telegram in self.telegram_buffer.get_all():
|
||||
# ensure actual telegram is ascii (7-bit) only (IEC 646 required in section 5.4 of IEC 62056-21)
|
||||
telegram = telegram.encode("latin1").decode("ascii")
|
||||
self.handle_telegram(telegram)
|
||||
|
||||
def keep_alive(self):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import serial
|
||||
import serial_asyncio
|
||||
|
||||
@@ -13,6 +13,7 @@ EN = {
|
||||
obis.ELECTRICITY_IMPORTED_TOTAL: 'ELECTRICITY_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_DELIVERED_TARIFF_1: 'ELECTRICITY_DELIVERED_TARIFF_1',
|
||||
obis.ELECTRICITY_DELIVERED_TARIFF_2: 'ELECTRICITY_DELIVERED_TARIFF_2',
|
||||
obis.ELECTRICITY_ACTIVE_TARIFF: 'ELECTRICITY_ACTIVE_TARIFF',
|
||||
@@ -55,6 +56,9 @@ EN = {
|
||||
obis.LUXEMBOURG_ELECTRICITY_DELIVERED_TARIFF_GLOBAL: 'LUXEMBOURG_ELECTRICITY_DELIVERED_TARIFF_GLOBAL',
|
||||
obis.SWEDEN_ELECTRICITY_USED_TARIFF_GLOBAL: 'SWEDEN_ELECTRICITY_USED_TARIFF_GLOBAL',
|
||||
obis.SWEDEN_ELECTRICITY_DELIVERED_TARIFF_GLOBAL: 'SWEDEN_ELECTRICITY_DELIVERED_TARIFF_GLOBAL',
|
||||
obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER',
|
||||
obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE',
|
||||
obis.Q3D_EQUIPMENT_SERIALNUMBER: 'Q3D_EQUIPMENT_SERIALNUMBER',
|
||||
}
|
||||
|
||||
REVERSE_EN = dict([(v, k) for k, v in EN.items()])
|
||||
|
||||
@@ -11,6 +11,7 @@ P1_MESSAGE_TIMESTAMP = r'\d-\d:1\.0\.0.+?\r\n'
|
||||
ELECTRICITY_IMPORTED_TOTAL = r'\d-\d:1\.8\.0.+?\r\n'
|
||||
ELECTRICITY_USED_TARIFF_1 = r'\d-\d:1\.8\.1.+?\r\n'
|
||||
ELECTRICITY_USED_TARIFF_2 = r'\d-\d:1\.8\.2.+?\r\n'
|
||||
ELECTRICITY_EXPORTED_TOTAL = r'\d-\d:2\.8\.0.+?\r\n'
|
||||
ELECTRICITY_DELIVERED_TARIFF_1 = r'\d-\d:2\.8\.1.+?\r\n'
|
||||
ELECTRICITY_DELIVERED_TARIFF_2 = r'\d-\d:2\.8\.2.+?\r\n'
|
||||
ELECTRICITY_ACTIVE_TARIFF = r'\d-\d:96\.14\.0.+?\r\n'
|
||||
@@ -68,3 +69,6 @@ LUXEMBOURG_ELECTRICITY_USED_TARIFF_GLOBAL = r'\d-\d:1\.8\.0.+?\r\n' # Total imp
|
||||
LUXEMBOURG_ELECTRICITY_DELIVERED_TARIFF_GLOBAL = r'\d-\d:2\.8\.0.+?\r\n' # Total exported energy register (P-)
|
||||
SWEDEN_ELECTRICITY_USED_TARIFF_GLOBAL = r'\d-\d:1\.8\.0.+?\r\n' # Total imported energy register (P+)
|
||||
SWEDEN_ELECTRICITY_DELIVERED_TARIFF_GLOBAL = r'\d-\d:2\.8\.0.+?\r\n' # Total exported energy register (P-)
|
||||
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
|
||||
|
||||
@@ -157,7 +157,8 @@ LUXEMBOURG_SMARTY['objects'].update({
|
||||
obis.LUXEMBOURG_ELECTRICITY_DELIVERED_TARIFF_GLOBAL: CosemParser(ValueParser(Decimal)),
|
||||
})
|
||||
|
||||
# Source: https://www.energiforetagen.se/globalassets/energiforetagen/det-erbjuder-vi/kurser-och-konferenser/elnat/branschrekommendation-lokalt-granssnitt-v2_0-201912.pdf
|
||||
# Source: https://www.energiforetagen.se/globalassets/energiforetagen/det-erbjuder-vi/kurser-och-konferenser/elnat/
|
||||
# branschrekommendation-lokalt-granssnitt-v2_0-201912.pdf
|
||||
SWEDEN = {
|
||||
'checksum_support': True,
|
||||
'objects': {
|
||||
@@ -181,3 +182,18 @@ SWEDEN = {
|
||||
obis.INSTANTANEOUS_CURRENT_L3: CosemParser(ValueParser(Decimal)),
|
||||
}
|
||||
}
|
||||
|
||||
Q3D = {
|
||||
"checksum_support": False,
|
||||
"objects": {
|
||||
obis.Q3D_EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)),
|
||||
obis.ELECTRICITY_IMPORTED_TOTAL: CosemParser(ValueParser(Decimal)),
|
||||
obis.ELECTRICITY_EXPORTED_TOTAL: CosemParser(ValueParser(Decimal)),
|
||||
obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: CosemParser(ValueParser(Decimal)),
|
||||
obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: CosemParser(ValueParser(Decimal)),
|
||||
obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: CosemParser(ValueParser(Decimal)),
|
||||
obis.CURRENT_ELECTRICITY_USAGE: CosemParser(ValueParser(Decimal)),
|
||||
obis.Q3D_EQUIPMENT_STATE: CosemParser(ValueParser(str)),
|
||||
obis.Q3D_EQUIPMENT_SERIALNUMBER: CosemParser(ValueParser(str)),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ setup(
|
||||
author_email='nigel@nldr.net',
|
||||
license='MIT',
|
||||
url='https://github.com/ndokter/dsmr_parser',
|
||||
version='0.30',
|
||||
version='0.31',
|
||||
packages=find_packages(exclude=('test', 'test.*')),
|
||||
install_requires=[
|
||||
'pyserial>=3,<4',
|
||||
|
||||
@@ -128,3 +128,43 @@ TELEGRAM_V5 = (
|
||||
'0-2:96.1.0()\r\n'
|
||||
'!6EEE\r\n'
|
||||
)
|
||||
|
||||
# EasyMeter via COM-1 Ethernet Gateway
|
||||
# Q3D Manual (german) https://www.easymeter.com/downloads/products/zaehler/Q3D/Easymeter_Q3D_DE_2016-06-15.pdf
|
||||
# - type code on page 8
|
||||
# - D0-Specs on page 20
|
||||
#
|
||||
# last two lines are added by the COM-1 Ethernet Gateway
|
||||
|
||||
TELEGRAM_ESY5Q3DB1024_V304 = ( # Easymeter an Hauptstromzähler
|
||||
'/ESY5Q3DB1024 V3.04\r\n'
|
||||
'\r\n'
|
||||
'1-0:0.0.0*255(0272031312565)\r\n'
|
||||
'1-0:1.8.0*255(00052185.7825309*kWh)\r\n'
|
||||
'1-0:2.8.0*255(00019949.3221493*kWh)\r\n'
|
||||
'1-0:21.7.0*255(000747.85*W)\r\n'
|
||||
'1-0:41.7.0*255(000737.28*W)\r\n'
|
||||
'1-0:61.7.0*255(000639.73*W)\r\n'
|
||||
'1-0:1.7.0*255(002124.86*W)\r\n'
|
||||
'1-0:96.5.5*255(80)\r\n'
|
||||
'0-0:96.1.255*255(1ESY1313002565)\r\n'
|
||||
'!\r\n'
|
||||
' 25803103\r\n'
|
||||
'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\r\n'
|
||||
)
|
||||
|
||||
TELEGRAM_ESY5Q3DA1004_V304 = ( # Easymeter an Wärmepumpe
|
||||
'/ESY5Q3DA1004 V3.04\r\n'
|
||||
'\r\n'
|
||||
'1-0:0.0.0*255(1336001560)\r\n'
|
||||
'1-0:1.8.0*255(00032549.5061662*kWh)\r\n'
|
||||
'1-0:21.7.0*255(000557.29*W)\r\n'
|
||||
'1-0:41.7.0*255(000521.62*W)\r\n'
|
||||
'1-0:61.7.0*255(000609.30*W)\r\n'
|
||||
'1-0:1.7.0*255(001688.21*W)\r\n'
|
||||
'1-0:96.5.5*255(80)\r\n'
|
||||
'0-0:96.1.255*255(1ESY1336001560)\r\n'
|
||||
'!\r\n'
|
||||
' 25818685\r\n'
|
||||
'DE0000000000000000000000000000003\r\n'
|
||||
)
|
||||
|
||||
@@ -3,8 +3,6 @@ from unittest.mock import Mock
|
||||
import unittest
|
||||
|
||||
from dsmr_parser import obis_references as obis
|
||||
from dsmr_parser import telegram_specifications
|
||||
from dsmr_parser.parsers import TelegramParser
|
||||
from dsmr_parser.clients.protocol import create_dsmr_protocol
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user