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
|
"""
Implementation of Basic KNX 2-Byte Signed Values.
They correspond the following KNX DPTs:
8.*** 2-byte/octet signed (2's complement), i.e. percentV16, delta time
"""
from __future__ import annotations
import struct
from xknx.exceptions import ConversionError
from .dpt import DPTNumeric
from .payload import DPTArray, DPTBinary
class DPT2ByteSigned(DPTNumeric):
"""
Abstraction for KNX 2 Byte signed values.
DPT 8.***
"""
dpt_main_number = 8
dpt_sub_number: int | None = None
value_type = "2byte_signed"
payload_length = 2
value_min = -32768
value_max = 32767
resolution: int | float = 1
# not using DPTStructIntMixin because return type of from_knx can be float when resolution is < 1
_struct_format = ">h"
@classmethod
def from_knx(cls, payload: DPTArray | DPTBinary) -> int | float:
"""Parse/deserialize from KNX/IP raw data."""
raw = cls.validate_payload(payload)
try:
return struct.unpack(cls._struct_format, bytes(raw))[0] * cls.resolution # type: ignore[no-any-return]
except struct.error as err:
raise ConversionError(f"Could not parse {cls.dpt_name()}", raw=raw) from err
@classmethod
def to_knx(cls, value: int | float) -> DPTArray:
"""Serialize to KNX/IP raw data."""
try:
knx_value = int(float(value) / cls.resolution)
if not (cls.value_min <= knx_value <= cls.value_max):
raise ValueError("Value out of range")
return DPTArray(struct.pack(cls._struct_format, knx_value))
except (ValueError, struct.error) as err:
raise ConversionError(
f"Could not serialize {cls.dpt_name()}", value=value
) from err
class DPTValue2Count(DPT2ByteSigned):
"""DPT 8.001 DPT_Value_2_Count (pulses)."""
dpt_main_number = 8
dpt_sub_number = 1
value_type = "pulse_2byte_signed"
unit = "pulses"
class DPTDeltaTimeMsec(DPT2ByteSigned):
"""DPT 8.002 DPT_DeltaTimeMsec (ms)."""
dpt_main_number = 8
dpt_sub_number = 2
value_type = "delta_time_ms"
unit = "ms"
class DPTDeltaTime10Msec(DPT2ByteSigned):
"""DPT 8.003 DPT_DeltaTime10Msec (ms)."""
dpt_main_number = 8
dpt_sub_number = 3
value_type = "delta_time_10ms"
resolution = 10
unit = "ms"
class DPTDeltaTime100Msec(DPT2ByteSigned):
"""DPT 8.004 DPT_DeltaTime100Msec (ms)."""
dpt_main_number = 8
dpt_sub_number = 4
value_type = "delta_time_100ms"
resolution = 100
unit = "ms"
class DPTDeltaTimeSec(DPT2ByteSigned):
"""DPT 8.005 DPT_DeltaTimeSec (s)."""
dpt_main_number = 8
dpt_sub_number = 5
value_type = "delta_time_sec"
unit = "s"
class DPTDeltaTimeMin(DPT2ByteSigned):
"""DPT 8.006 DPT_DeltaTimeMin (min)."""
dpt_main_number = 8
dpt_sub_number = 6
value_type = "delta_time_min"
unit = "min"
class DPTDeltaTimeHrs(DPT2ByteSigned):
"""DPT 8.007 DPT_DeltaTimeHrs (h)."""
dpt_main_number = 8
dpt_sub_number = 7
value_type = "delta_time_hrs"
unit = "h"
class DPTPercentV16(DPT2ByteSigned):
"""DPT 8.010 DPT_Percent_V16 (%)."""
dpt_main_number = 8
dpt_sub_number = 10
value_type = "percentV16"
resolution = 0.01
unit = "%"
class DPTRotationAngle(DPT2ByteSigned):
"""DPT 8.011 DPT_Rotation_Angle (°)."""
dpt_main_number = 8
dpt_sub_number = 11
value_type = "rotation_angle"
unit = "°"
class DPTLengthM(DPT2ByteSigned):
"""DPT 8.012 DPT_Length_m."""
dpt_main_number = 8
dpt_sub_number = 12
value_type = "length_m"
unit = "m"
ha_device_class = "distance"
|