Skip to content

Commit

Permalink
Initial Release
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemanspiff2007 committed Jan 8, 2021
0 parents commit 69f22b3
Show file tree
Hide file tree
Showing 22 changed files with 1,791 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[flake8]
ignore =
# E201 whitespace after '('
E201,
# E221 multiple spaces before operator
E203,
# E203 whitespace before ':'
E221,
# E241 multiple spaces after ','
E241,
# E251 unexpected spaces around keyword / parameter equals
E251,
# E303 too many blank lines
E303,

max-line-length = 120
exclude =
.git,
.tox,
__pycache__,
build,
dist,
conf,
venv

33 changes: 33 additions & 0 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Publish Python distributions to PyPI
on:
release:
types: [published]

jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
runs-on: ubuntu-latest

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

- name: Install setuptools
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade setuptools wheel twine
- name: Build a binary wheel and a source tarball
run: |
python setup.py sdist bdist_wheel
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_api_key }}
24 changes: 24 additions & 0 deletions .github/workflows/run_tox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
python-version: [3.8, 3.9]

steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.mypy_cache
.idea
__pycache__
/conf
/venv
/build
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include LICENSE
134 changes: 134 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# SmlLib
[![Tests Status](https://github.com/spacemanspiff2007/SmlLib/workflows/Tests/badge.svg)](https://github.com/spacemanspiff2007/SmlLib/actions?query=workflow%3ATests)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/SmlLib)](https://pypi.org/project/smllib/)
[![PyPI](https://img.shields.io/pypi/v/SmlLib)](https://pypi.org/project/smllib/)
[![Downloads](https://pepy.tech/badge/SmlLib/month)](https://pepy.tech/project/SmlLib/month)


_A SML (Smart Message Language) library_

## About
This library can be used to parse SML byte streams.
It does not read from external devices.

## Usage
The [Sml2Mqtt](https://pypi.org/project/Sml2Mqtt/) program makes use of this library.


Example:
```python
from smllib import SmlStreamReader

stream = SmlStreamReader()
stream.add(b'BytesFromSerialPort')
sml_msgs = stream.get_msg()
if sml_msgs is None:
print('Bytes missing')

# Shortcut to extract all values without parsing the whole frame
obis_values = sml_msgs.get_obis()

# return all values but slower
parsed_msgs = sml_msgs.parse_frame()
for msg in parsed_msgs:
# prints a nice overview over the received values
print(msg.format_msg())
```

```text
SmlMessage
transaction_id: 17c77d6b
group_no : 0
abort_on_error: 0
message_body <SmlOpenResponse>
codepage : None
client_id : None
req_file_id: 07ed29cd
server_id : 11111111111111111111
ref_time : None
sml_version: None
crc16 : 25375
SmlMessage
transaction_id: 17c77d6c
group_no : 0
abort_on_error: 0
message_body <SmlGetListResponse>
client_id : None
sever_id : 11111111111111111111
list_name : 0100620affff
act_sensor_time : 226361515
val_list: list
<SmlListEntry>
obis : 8181c78203ff
status : None
val_time : None
unit : None
scaler : None
value : ISK
value_signature: None
-> (Hersteller-Identifikation)
<SmlListEntry>
obis : 0100000009ff
status : None
val_time : None
unit : None
scaler : None
value : 11111111111111111111
value_signature: None
-> (Geräteeinzelidentifikation)
<SmlListEntry>
obis : 0100010800ff
status : 386
val_time : None
unit : 30
scaler : -1
value : 123456789
value_signature: None
-> 12345678.9Wh (Zählerstand Total)
<SmlListEntry>
obis : 0100010801ff
status : None
val_time : None
unit : 30
scaler : -1
value : 123456789
value_signature: None
-> 12345678.9Wh (Zählerstand Tarif 1)
<SmlListEntry>
obis : 0100010802ff
status : None
val_time : None
unit : 30
scaler : -1
value : 0
value_signature: None
-> 0.0Wh (Zählerstand Tarif 2)
<SmlListEntry>
obis : 0100100700ff
status : None
val_time : None
unit : 27
scaler : 0
value : 555
value_signature: None
-> 555W (aktuelle Wirkleistung)
<SmlListEntry>
obis : 8181c78205ff
status : None
val_time : None
unit : None
scaler : None
value : XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
value_signature: None
-> (Öffentlicher Schlüssel)
list_signature : None
act_gateway_time: None
crc16 : 22117
SmlMessage
transaction_id: 17c77d6d
group_no : 0
abort_on_error: 0
message_body <SmlCloseResponse>
global_signature: None
crc16 : 56696
```
55 changes: 55 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import typing
from pathlib import Path

import setuptools # type: ignore


def load_version() -> str:
version: typing.Dict[str, str] = {}
with open("smllib/__version__.py") as fp:
exec(fp.read(), version)
assert version['__version__'], version
return version['__version__']


__version__ = load_version()

print(f'Version: {__version__}')
print('')

# When we run tox tests we don't have these files available so we skip them
readme = Path(__file__).with_name('readme.md')
long_description = ''
if readme.is_file():
with readme.open("r", encoding='utf-8') as fh:
long_description = fh.read()

setuptools.setup(
name="smllib",
version=__version__,
author="spaceman_spiff",
# author_email="",
description="A library for the SML (Smart Message Language) protocol",
keywords=[
'sml',
'obis',
'smart message language',
'energy meter',
],
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/spacemanspiff2007/SmlLib",
project_urls={
'GitHub': "https://github.com/spacemanspiff2007/SmlLib",
},
packages=setuptools.find_packages(include=['smllib'], exclude=['tests*']),
classifiers=[
"Development Status :: 4 - Beta",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Home Automation"
],
)
4 changes: 4 additions & 0 deletions smllib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from smllib.__version__ import __version__ # noqa: F401

from smllib.sml_frame import SmlFrame # noqa: F401
from smllib.reader import SmlStreamReader, CrcError # noqa: F401
1 change: 1 addition & 0 deletions smllib/__version__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.1'
105 changes: 105 additions & 0 deletions smllib/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
UNITS = {
1: 'a',
2: 'mo',
3: 'wk',
4: 'd',
5: 'h',
6: 'min',
7: 's',
8: '°',
9: '°C',
10: 'currency',
11: 'm',
12: 'm/s',
13: 'm³',
14: 'm³',
15: 'm³/h',
16: 'm³/h',
17: 'm³/d',
18: 'm³/d',
19: 'l',
20: 'kg',
21: 'N',
22: 'Nm',
23: 'Pa',
24: 'bar',
25: 'J',
26: 'J/h',
27: 'W',
28: 'VA',
29: 'var',
30: 'Wh',
31: 'VAh',
32: 'varh',
33: 'A',
34: 'C',
35: 'V',
36: 'V/m',
37: 'F',
38: 'Ω',
39: 'Ωm²/m',
40: 'Wb',
41: 'T',
42: 'A/m',
43: 'H',
44: 'Hz',
45: '1/(Wh)',
46: '1/(varh)',
47: '1/(VAh)',
48: 'V²h',
49: 'A²h',
50: 'kg/s',
51: 'S',
52: 'K',
53: '1/(V²h)',
54: '1/(A²h)',
55: '1/m³',
56: '%',
57: 'Ah',
60: 'Wh/m³',
61: 'J/m³',
62: 'Mol%',
63: 'g/m³',
64: 'Pas',
65: 'J/kg',
66: 'g/cm²',
67: 'arm',
70: 'dBm',
71: 'dBµV',
72: 'dB',
}

# 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',
'0100011100ff': 'Total-Zählerstand',
'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',
'0100510701ff': 'Phasenabweichung Spannungen L1/L2',
'0100510702ff': 'Phasenabweichung Spannungen L1/L3',
'0100510704ff': 'Phasenabweichung Strom/Spannung L1',
'010051070fff': 'Phasenabweichung Strom/Spannung L2',
'010051071aff': 'Phasenabweichung Strom/Spannung L3',
'010060320002': 'Aktuelle Chiptemperatur',
'010060320003': 'Minimale Chiptemperatur',
'010060320004': 'Maximale Chiptemperatur',
'010060320005': 'Gemittelte Chiptemperatur',
'010060320303': 'Spannungsminimum',
'010060320304': 'Spannungsmaximum',
'8181c78203ff': 'Hersteller-Identifikation',
'8181c78205ff': 'Öffentlicher Schlüssel',
}
Loading

0 comments on commit 69f22b3

Please sign in to comment.