Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
476 changes: 240 additions & 236 deletions luxtronik/calculations.py

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions luxtronik/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@

# Content of response that is contained in responses to discovery broadcast
LUXTRONIK_DISCOVERY_RESPONSE_PREFIX = "2500;111;"

LUXTRONIK_NAME_CHECK_NONE = "none"
LUXTRONIK_NAME_CHECK_PREFERRED = "preferred"
LUXTRONIK_NAME_CHECK_OBSOLETE = "obsolete"
15 changes: 14 additions & 1 deletion luxtronik/data_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import logging

from luxtronik.constants import (
LUXTRONIK_NAME_CHECK_PREFERRED,
LUXTRONIK_NAME_CHECK_OBSOLETE,
)

from luxtronik.datatypes import Unknown


Expand All @@ -11,6 +16,8 @@ class DataVector:
logger = logging.getLogger("Luxtronik.DataVector")
name = "DataVector"

_obsolete = {}

def __init__(self):
"""Initialize DataVector class."""
self._data = {}
Expand Down Expand Up @@ -46,9 +53,15 @@ def _lookup(self, target, with_index=False):
except ValueError:
# Get entry by name
target_index = None
obsolete_entry = self._obsolete.get(target, None)
if obsolete_entry:
raise KeyError(f"The name '{target}' is obsolete! Use '{obsolete_entry}' instead.")
for index, entry in self._data.items():
if entry.name == target:
check_result = entry.check_name(target)
if check_result == LUXTRONIK_NAME_CHECK_PREFERRED:
target_index = index
elif check_result == LUXTRONIK_NAME_CHECK_OBSOLETE:
raise KeyError(f"The name '{target}' is obsolete! Use '{entry.name}' instead.")
elif isinstance(target, int):
# Get entry by id
target_index = target
Expand Down
32 changes: 30 additions & 2 deletions luxtronik/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import socket
import struct

from luxtronik.constants import (
LUXTRONIK_NAME_CHECK_NONE,
LUXTRONIK_NAME_CHECK_PREFERRED,
LUXTRONIK_NAME_CHECK_OBSOLETE,
)

from functools import total_ordering


Expand All @@ -14,12 +20,17 @@ class Base:
datatype_class = None
datatype_unit = None

def __init__(self, name, writeable=False):
def __init__(self, names, writeable=False):
"""Initialize the base data field class. Set the initial raw value to None"""
# save the raw value only since the user value
# could be build at any time
self._raw = None
self.name = name
if isinstance(names, list):
self._names = names
else:
self._names = [names]
assert len(self._names) > 0, "At least one name is required"
assert all(isinstance(name, str) for name in self._names), "Names must be strings"
self.writeable = writeable

@classmethod
Expand All @@ -32,6 +43,23 @@ def from_heatpump(cls, value):
"""Converts value from heatpump units."""
return value

@property
def name(self):
"""Return the (most common) name of the entry."""
return self._names[0]

def check_name(self, name):
"""
Check whether a name matches one of the supported entry names.
The result string can be used to trigger a exception for obsolete names.
"""
if name == self.name:
return LUXTRONIK_NAME_CHECK_PREFERRED
elif name in self._names:
return LUXTRONIK_NAME_CHECK_OBSOLETE
else:
return LUXTRONIK_NAME_CHECK_NONE

@property
def value(self):
"""Return the stored value converted from heatpump units."""
Expand Down
2,216 changes: 1,108 additions & 1,108 deletions luxtronik/parameters.py

Large diffs are not rendered by default.

700 changes: 350 additions & 350 deletions luxtronik/visibilities.py

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions tests/test_data_vector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Test suite for data_vector module"""

# pylint: disable=too-few-public-methods,invalid-name,too-many-lines

import pytest
from luxtronik.data_vector import DataVector

from luxtronik.datatypes import (
Base,
)


class ObsoleteDataVector(DataVector):

name = "Obsolete"

_obsolete = {
"baz": "foo"
}

def __init__(self):
super().__init__()
self._data = {
0: Base(["foo", "bar"]),
}


class TestDataVector:
"""Test suite for DataVector"""

@pytest.mark.parametrize("name, exception_expected", [
("foo", False),
("bar", True),
("baz", True),
("qux", False),
])
def test_obsolete(self, name, exception_expected):
"""Test cases for initialization"""
obsolete = ObsoleteDataVector()
try:
obsolete.get(name)
assert not exception_expected
except KeyError:
assert exception_expected
33 changes: 33 additions & 0 deletions tests/test_datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

import datetime

from luxtronik.constants import (
LUXTRONIK_NAME_CHECK_NONE,
LUXTRONIK_NAME_CHECK_PREFERRED,
LUXTRONIK_NAME_CHECK_OBSOLETE,
)

from luxtronik.datatypes import (
Base,
SelectionBase,
Expand Down Expand Up @@ -93,6 +99,33 @@ def test_to_heatpump(self):

assert Base.to_heatpump(42) == 42

def test_name(self):
"""Test cases for name property"""
base = Base(["foo", "bar"])

assert base.name == "foo"

def test_empty_name(self):
"""Test cases for name property"""
try:
Base([])
assert False
except Exception:
pass
try:
Base(None)
assert False
except Exception:
pass

def test_check_name(self):
"""Test cases for check_name() function"""
base = Base(["foo", "bar"])

assert base.check_name("foo") == LUXTRONIK_NAME_CHECK_PREFERRED
assert base.check_name("bar") == LUXTRONIK_NAME_CHECK_OBSOLETE
assert base.check_name("baz") == LUXTRONIK_NAME_CHECK_NONE

def test_value_property(self):
"""Test case for value property"""

Expand Down