File: dpt_5.py

package info (click to toggle)
python-xknx 3.10.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,044 kB
  • sloc: python: 40,087; javascript: 8,556; makefile: 32; sh: 12
file content (176 lines) | stat: -rw-r--r-- 4,260 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
"""Implementation of Basic KNX DPT_1_Ucount Values."""

from __future__ import annotations

from xknx.exceptions import ConversionError

from .dpt import DPTNumeric
from .payload import DPTArray, DPTBinary


class DPTValue1ByteUnsigned(DPTNumeric):
    """
    Abstraction for KNX 1 Octet.

    DPT 5.***
    """

    dpt_main_number = 5
    dpt_sub_number: int | None = None
    value_type = "1byte_unsigned"
    payload_length = 1

    value_min = 0
    value_max = 255
    resolution = 1

    @classmethod
    def from_knx(cls, payload: DPTArray | DPTBinary) -> int:
        """Parse/deserialize from KNX/IP raw data."""
        value = cls.validate_payload(payload)[0]

        if not cls._test_boundaries(value):
            raise ConversionError(
                f"Could not parse {cls.dpt_name()}", value=value, payload=payload
            )

        return value

    @classmethod
    def to_knx(cls, value: int | float) -> DPTArray:
        """Serialize to KNX/IP raw data."""
        try:
            knx_value = int(value)
            if not cls._test_boundaries(knx_value):
                raise ValueError(f"Value out of range {cls.value_min}..{cls.value_max}")
            return DPTArray(knx_value)
        except ValueError as err:
            raise ConversionError(
                f"Could not serialize {cls.dpt_name()}", value=value
            ) from err

    @classmethod
    def _test_boundaries(cls, value: int) -> bool:
        """Test if value is within defined range for this object."""
        return cls.value_min <= value <= cls.value_max


class DPTScaling(DPTNumeric):
    """
    Abstraction for KNX 1 Octet Percent.

    DPT 5.001
    """

    dpt_main_number = 5
    dpt_sub_number = 1
    value_type = "percent"
    unit = "%"
    payload_length = 1

    value_min = 0
    value_max = 100
    resolution = 1

    @classmethod
    def from_knx(cls, payload: DPTArray | DPTBinary) -> int:
        """Parse/deserialize from KNX/IP raw data."""
        knx_value = cls.validate_payload(payload)[0]
        delta = cls.value_max - cls.value_min
        value = round((knx_value / 255) * delta) + cls.value_min

        if not cls._test_boundaries(value):
            raise ConversionError(
                f"Could not parse {cls.dpt_name()}", value=value, payload=payload
            )
        return value

    @classmethod
    def to_knx(cls, value: float) -> DPTArray:
        """Serialize to KNX/IP raw data."""
        try:
            percent_value = float(value)
            if not cls._test_boundaries(percent_value):
                raise ValueError("Value out of range")
            delta = cls.value_max - cls.value_min
            knx_value = round((percent_value - cls.value_min) / delta * 255)

            return DPTArray(knx_value)
        except ValueError as err:
            raise ConversionError(
                f"Could not serialize {cls.dpt_name()}", value=value
            ) from err

    @classmethod
    def _test_boundaries(cls, value: float) -> bool:
        """Test if value is within defined range for this object."""
        return cls.value_min <= value <= cls.value_max


class DPTAngle(DPTScaling):
    """
    Abstraction for KNX 1 Octet Angle.

    DPT 5.003
    """

    dpt_main_number = 5
    dpt_sub_number = 3
    value_type = "angle"
    unit = "°"

    value_min = 0
    value_max = 360
    resolution = 1


class DPTPercentU8(DPTValue1ByteUnsigned):
    """
    Abstraction for KNX 1 Octet Percent.

    DPT 5.004
    """

    dpt_main_number = 5
    dpt_sub_number = 4
    value_type = "percentU8"
    unit = "%"
    resolution = 1


class DPTDecimalFactor(DPTValue1ByteUnsigned):
    """
    Abstraction for KNX 1 Octet Percent.

    DPT 5.005
    """

    dpt_main_number = 5
    dpt_sub_number = 5
    value_type = "decimal_factor"


class DPTTariff(DPTValue1ByteUnsigned):
    """
    Abstraction for KNX 1 Octet tariff information.

    DPT 5.006
    """

    dpt_main_number = 5
    dpt_sub_number = 6
    value_type = "tariff"
    value_max = 254


class DPTValue1Ucount(DPTValue1ByteUnsigned):
    """
    Abstraction for KNX 1 Octet counter pulses.

    DPT 5.010
    """

    dpt_main_number = 5
    dpt_sub_number = 10
    value_type = "pulse"
    unit = "counter pulses"