Skip to content

Commit

Permalink
1.3
Browse files Browse the repository at this point in the history
- Updated some obis descriptions
- Fixed some type hints
- Updated readme
- Update CI
  • Loading branch information
spacemanspiff2007 committed Oct 18, 2023
1 parent 863ec15 commit 90ded5f
Show file tree
Hide file tree
Showing 19 changed files with 130 additions and 54 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: master
- name: Set up Python 3.8
uses: actions/setup-python@v2
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: '3.10'

- name: Install setuptools
run: |
Expand Down
20 changes: 16 additions & 4 deletions .github/workflows/run_tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@ name: Tests
on: [push, pull_request]

jobs:
test:
pre-commit:
name: pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- uses: pre-commit/[email protected]


tests:
needs: pre-commit
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
python-version: ['3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
23 changes: 19 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.5.0
hooks:
- id: check-ast
- id: check-builtin-literals
- id: check-docstring-first
- id: check-merge-conflict
# - id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https://github.com/pycqa/isort
rev: 5.8.0
rev: 5.12.0
hooks:
- id: isort
name: isort (python)

- repo: https://gitlab.com/PyCQA/flake8
rev: '3.9.1'
- repo: https://github.com/PyCQA/flake8
rev: '6.1.0'
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear==23.9.16
- flake8-comprehensions==3.14
- flake8-noqa==1.3

- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include LICENSE
include src/smllib/py.typed
include py.typed
6 changes: 5 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ if sml_frame is None:
stream.add(b'BytesFromSerialPort')
sml_frame = stream.get_frame()

# Shortcut to extract all values without parsing the whole frame
# A quick Shortcut to extract all values without parsing the whole frame
# In rare cases this might raise an InvalidBufferPos exception, then you have to use sml_frame.parse_frame()
obis_values = sml_frame.get_obis()

# return all values but slower
Expand All @@ -39,6 +40,9 @@ for msg in parsed_msgs:
# prints a nice overview over the received values
print(msg.format_msg())

# In the parsed message the obis values are typically found like this
obis_values = parsed_msgs[1].message_body.val_list

# The obis attribute of the SmlListEntry carries different obis representations as attributes
list_entry = obis_values[0]
print(list_entry.obis) # 0100010800ff
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pre-commit==2.20.0
pytest==7.1.3
pytest == 7.4.2
pre-commit == 3.5.0
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def load_version() -> str:
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Home Automation"
],
Expand Down
2 changes: 1 addition & 1 deletion src/smllib/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.2'
__version__ = '1.3'
4 changes: 2 additions & 2 deletions src/smllib/builder/_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, Generic, Tuple, Type, TypeVar
from typing import Dict, Generic, Type, TypeVar

from smllib.errors import WrongArgCount, WrongValueType
from smllib.sml import inspect_obj, SmlBaseObj, SmlObjFieldInfo, T_SML_OBJ
Expand All @@ -19,7 +19,7 @@ def build(self, obj: SmlFrameSnippet, classes: Dict[Type[SmlBaseObj], 'SmlObjBui
raise WrongArgCount()

out = self.BUILDS()
for i, a in enumerate(self.fields.items()): # type: int, Tuple[str, SmlObjFieldInfo]
for i, a in enumerate(self.fields.items()): # type: int, tuple[str, SmlObjFieldInfo]
name, field = a
value = lst[i].value

Expand Down
4 changes: 2 additions & 2 deletions src/smllib/builder/default_context.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Dict, Type

from smllib.sml import SmlCloseResponse, SmlGetListResponse, SmlListEntry, SmlMessage, SmlOpenResponse, T_SML_OBJ
from smllib.sml import SmlBaseObj, SmlCloseResponse, SmlGetListResponse, SmlListEntry, SmlMessage, SmlOpenResponse

from . import SmlCloseResponseBuilder, SmlGetListResponseBuilder, \
SmlListEntryBuilder, SmlMessageBuilder, SmlOpenResponseBuilder, T_SML_BUILDER

CTX_HINT = Dict[Type[T_SML_OBJ], T_SML_BUILDER]
CTX_HINT = Dict[Type[SmlBaseObj], T_SML_BUILDER]


def create_context() -> CTX_HINT:
Expand Down
55 changes: 38 additions & 17 deletions src/smllib/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,24 +72,46 @@
# https://www.promotic.eu/en/pmdoc/Subsystems/Comm/PmDrivers/IEC62056_OBIS.htm
OBIS_NAMES = {
'0100000009ff': 'Geräteeinzelidentifikation',
'0100010800ff': 'Zählerstand Total',
'0100010801ff': 'Zählerstand Tarif 1',
'0100010802ff': 'Zählerstand Tarif 2',
'0100010800ff': 'Zählerstand Bezug Total',
'0100010801ff': 'Zählerstand Bezug Tarif 1',
'0100010802ff': 'Zählerstand Bezug Tarif 2',
'0100010803ff': 'Zählerstand Bezug Tarif 3',
'0100010804ff': 'Zählerstand Bezug Tarif 4',
'0100011100ff': 'Total-Zählerstand',
'0100020800ff': 'Wirkenergie Total',
'0100020800ff': 'Zählerstand Einspeisung Total',
'0100020801ff': 'Zählerstand Einspeisung Tarif 1',
'0100020802ff': 'Zählerstand Einspeisung Tarif 2',
'0100020803ff': 'Zählerstand Einspeisung Tarif 3',
'0100020804ff': 'Zählerstand Einspeisung Tarif 4',
'01000b0600ff': 'Maximalstrom Total',
'01000b0700ff': 'Momentanstrom Total',
'01000c0700ff': 'Momentanspannung Total',
'01000e0700ff': 'Netzfrequenz',
'0100100700ff': 'aktuelle Wirkleistung',
'0100170700ff': 'Momentanblindleistung L1',
'01001f0700ff': 'Strom L1',
'0100200700ff': 'Spannung L1',
'0100240700ff': 'Wirkleistung L1',
'01002b0700ff': 'Momentanblindleistung L2',
'0100330700ff': 'Strom L2',
'0100340700ff': 'Spannung L2',
'0100380700ff': 'Wirkleistung L2',
'01003f0700ff': 'Momentanblindleistung L3',
'0100470700ff': 'Strom L3',
'0100480700ff': 'Spannung L3',
'01004c0700ff': 'Wirkleistung L3',
'0100150700ff': 'Momentanwirkleistung Bezug L1',
'0100160700ff': 'Momentanwirkleistung Einspeisung L1',
'0100170700ff': 'Momentanblindleistung Bezug L1',
'0100180700ff': 'Momentanblindleistung Einspeisung L1',
'01001f0600ff': 'Maximalstrom L1',
'01001f0700ff': 'Momentanstrom L1',
'0100200700ff': 'Momentanspannung L1',
'0100240700ff': 'Summenwirkleistung L1',
'0100290700ff': 'Momentanwirkleistung Bezug L2',
'01002a0700ff': 'Momentanwirkleistung Einspeisung L2',
'01002b0700ff': 'Momentanblindleistung Bezug L2',
'01002c0700ff': 'Momentanblindleistung Einspeisung L2',
'0100330600ff': 'Maximalstrom L2',
'0100330700ff': 'Momentanstrom L2',
'0100340700ff': 'Momentanspannung L2',
'0100380700ff': 'Summenwirkleistung L2',
'01003d0700ff': 'Momentanwirkleistung Bezug L3',
'01003e0700ff': 'Momentanwirkleistung Einspeisung L3',
'01003f0700ff': 'Momentanblindleistung Bezug L3',
'0100400700ff': 'Momentanblindleistung Einspeisung L3',
'0100470600ff': 'Maximalstrom L3',
'0100470700ff': 'Momentanstrom L3',
'0100480700ff': 'Momentanspannung L3',
'01004c0700ff': 'Summenwirkleistung L3',
'0100510701ff': 'Phasenabweichung Spannungen L1/L2',
'0100510702ff': 'Phasenabweichung Spannungen L1/L3',
'0100510704ff': 'Phasenabweichung Strom/Spannung L1',
Expand All @@ -101,7 +123,6 @@
'010060320005': 'Gemittelte Chiptemperatur',
'010060320303': 'Spannungsminimum',
'010060320304': 'Spannungsmaximum',
'01000e0700ff': 'Netz Frequenz',
'8181c78203ff': 'Hersteller-Identifikation',
'8181c78205ff': 'Öffentlicher Schlüssel',
}
2 changes: 1 addition & 1 deletion src/smllib/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
class SmlStreamReader:
MAX_SIZE = 50 * 1024

def __init__(self, build_ctx: CTX_HINT = None):
def __init__(self, build_ctx: Optional[CTX_HINT] = None):
self.bytes: bytes = b''
self.build_ctx: CTX_HINT = build_ctx if build_ctx is not None else create_context()

Expand Down
3 changes: 1 addition & 2 deletions src/smllib/sml/message.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from typing import Dict, Type, Union

from smllib.sml import SmlBaseObj, SmlChoice, SmlCloseResponse, SmlGetListResponse, SmlObjFieldInfo, SmlOpenResponse
from smllib.sml._base_obj import T_SML_OBJ as _T_SML_OBJ

MSG_TYPES: Dict[int, Type[_T_SML_OBJ]] = {
MSG_TYPES: Dict[int, Type[SmlBaseObj]] = {
# 0x0100: 'SmlOpenRequest',
0x0101: SmlOpenResponse,
# 0x0200: 'SmlCloseRequest',
Expand Down
8 changes: 4 additions & 4 deletions src/smllib/sml/sml_choice.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from typing import Any, List, Mapping, Tuple, Type, Union
from typing import Final, Generic, List, Mapping, Tuple, Type

from smllib.errors import UnsupportedChoiceValue, WrongArgCount
from smllib.sml import T_SML_OBJ
from smllib.sml_frame_snippet import SmlFrameSnippet


class SmlChoice:
class SmlChoice(Generic[T_SML_OBJ]):
def __init__(self, choices: Mapping[int, Type[T_SML_OBJ]]):
self.choices = choices
self.choices: Final = choices

def get(self, obj: List[SmlFrameSnippet]) -> Union[Tuple[None, Any], Tuple[Type[T_SML_OBJ], Any]]:
def get(self, obj: List[SmlFrameSnippet]) -> Tuple[Type[T_SML_OBJ], SmlFrameSnippet]:
if len(obj) != 2:
raise WrongArgCount()

Expand Down
2 changes: 1 addition & 1 deletion src/smllib/sml_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


class SmlFrame:
def __init__(self, buffer: bytes, build_ctx: CTX_HINT = None, msg_ctx: Optional[bytes] = None):
def __init__(self, buffer: bytes, build_ctx: Optional[CTX_HINT] = None, msg_ctx: Optional[bytes] = None):
self.bytes = buffer
self.buffer = memoryview(buffer)
self.buf_len = len(buffer)
Expand Down
6 changes: 3 additions & 3 deletions tests/builder/test_build.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from smllib.builder import SmlCloseResponseBuilder, SmlGetListResponseBuilder, \
SmlListEntryBuilder, SmlMessageBuilder, SmlObjBuilder
from smllib.sml import EndOfSmlMsg, SmlCloseResponse, SmlGetListResponse, SmlListEntry
from smllib.sml import EndOfSmlMsg, SmlCloseResponse, SmlListEntry
from tests.helper import in_snip


Expand All @@ -21,7 +21,7 @@ def test_build_entry_list():

builder = SmlGetListResponseBuilder()

obj = builder.build(data, {SmlListEntry: SmlListEntryBuilder()}) # type: SmlGetListResponse
obj = builder.build(data, {SmlListEntry: SmlListEntryBuilder()})
assert obj.server_id == 'server'
assert obj.val_list[0].obis == '0100010800ff'
assert obj.val_list[0].value == 'val1'
Expand All @@ -36,7 +36,7 @@ def build(self, obj: list, classes):
ret.obis += '_patched'
return ret

obj = builder.build(data, {SmlListEntry: PatchedBuilder()}) # type: SmlGetListResponse
obj = builder.build(data, {SmlListEntry: PatchedBuilder()})
assert obj.server_id == 'server'
assert obj.val_list[0].obis == '0100010800ff_patched'
assert obj.val_list[0].value == 'val1'
Expand Down
4 changes: 2 additions & 2 deletions tests/sml/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_list_entry():
' scaler : None\n' \
' value : val1\n' \
' value_signature: None\n' \
' -> (Zählerstand Total)\n' \
' -> (Zählerstand Bezug Total)\n' \
' <SmlListEntry>\n' \
' obis : 0100010801ff (1-0:1.8.1*255)\n' \
' status : None\n' \
Expand All @@ -55,6 +55,6 @@ def test_list_entry():
' scaler : None\n' \
' value : val2\n' \
' value_signature: None\n' \
' -> (Zählerstand Tarif 1)\n' \
' -> (Zählerstand Bezug Tarif 1)\n' \
' list_signature : None\n' \
' act_gateway_time: None\n'
23 changes: 22 additions & 1 deletion tests/test_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@
b'019EBD01010163F08A007605011FBC8562006200726500000201710163E38F000000001B1B1B1B1A03509F',
id='Frame Issue #8 (FIXED)'
),
#
# This is a frame where the shortcut fails
#
# pytest.param(
# b'1b1b1b1b010101017605077707006200620072630101760107ffffffffffff05027d02560b0a01454d4800009f3846726201650'
# b'27d082b62016312980076050777070162006200726307017707ffffffffffff0b0a01454d4800009f3846070100620affff7262'
# b'0165027d082b7577070100603201010101010104454d480177070100600100ff010101010b0a01454d4800009f3846017707010'
# b'0010800ff641c010472620165027d082b621e52ff6501ddf5f40177070100020800ff0172620165027d082b621e52ff6501d4dc'
# b'0d0177070100100700ff0101621b520053039f01010163ec0100760507770702620062007263020171016344d5001b1b1b1b1a0'
# b'08aa9',
# id='Frame Issue #15 (FIXED)'
# ),
)
)
def test_frames(frame):
Expand Down Expand Up @@ -112,6 +124,14 @@ def test_frames(frame):
b'020171016357f100',
id='Frame3'
),
pytest.param(
b'76050550750262006200726301017601010501c57c560b0a0149534b0005020de27262016501c57c07620163c497007605055075'
b'03620062007263070177010b0a0149534b0005020de2070100620affff7262016501c57c07757707010060320101010101010449'
b'534b0177070100600100ff010101010b0a0149534b0005020de20177070100010800ff65001c410401621e52ff6501d3c8d80177'
b'070100020800ff0101621e52ff650001fe010177070100100700ff0101621b52005300ad010101639e9c00760505507504620062'
b'0072630201710163b71b00',
id='Frame3'
),
)
)
def test_frame_only(data):
Expand All @@ -128,5 +148,6 @@ def test_frame_only(data):
assert len(obis_values) >= 4, obis_values

for obis in obis_values:
obis.format_msg()
print(obis.format_msg())
obis.get_value()
break
6 changes: 3 additions & 3 deletions tests/test_sml_stream_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ def test_msg_long_list():

r = SmlStreamReader()
r.add(msg2)
f = r.get_frame()
for f in f.parse_frame():
f.format_msg()
frame = r.get_frame()
for msg in frame.parse_frame():
msg.format_msg()

0 comments on commit 90ded5f

Please sign in to comment.