Skip to content

Commit 7a9a62f

Browse files
committed
Add support for pretty-printing of dates
The KMP protocol implements a few different date/time formats. Instead of showing raw numbers, let's show a nice, properly formatted date. I do not feel like changing the RegisterOutput to support many native Python types, IMHO it's perfectly OK to stick with numbers (which will be typically fed to a time series DB or something similar) and "everything else", but let's print that "everything else" properly. I'm not 100% sure how to handle the `yy-mm-dd` format. I *think* that it's rather uncommon to see meters with 26+ years old data record today, which is why I decided to hardcode the year-2000 prefix. A non-public document mentions '99:12:31' as an example, though. Also, a proper y/m/d separator is definitely `-`, not `:`, so I'm using that for clarity.
1 parent b4b92fa commit 7a9a62f

2 files changed

Lines changed: 50 additions & 6 deletions

File tree

src/pykmp/registers.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class RegisterOutput:
2525
unit_int: int
2626
unit_hex: str = attrs.field(init=False)
2727
unit_str: str = attrs.field(init=False)
28-
value_float: float = attrs.field(init=False)
29-
value_str: str = attrs.field(init=False) # best: uses decimal.Decimal without loss
30-
value_dec: decimal.Decimal
28+
value_float: float = attrs.field(init=False, default=None)
29+
value_str: str = attrs.field() # best: uses decimal.Decimal without loss
30+
value_dec: decimal.Decimal = attrs.field()
3131

3232
def __attrs_post_init__(self) -> None:
3333
self.id_hex = f"0x{self.id_int:04X}"
@@ -36,16 +36,36 @@ def __attrs_post_init__(self) -> None:
3636
self.unit_str = constants.UNITS_NAMES.get(
3737
self.unit_int, f"<unknown unit {self.unit_int}>"
3838
)
39-
self.value_float = float(self.value_dec)
40-
self.value_str = str(self.value_dec)
39+
if self.value_dec is not None:
40+
self.value_float = float(self.value_dec)
41+
self.value_str = str(self.value_dec)
4142

4243
@classmethod
4344
def from_register_data(cls, reg: messages.RegisterData) -> Self:
44-
value_dec = codec.FloatCodec.decode(reg.value)
45+
value_dec = None
46+
value_str = None
47+
match reg.unit:
48+
case 0x2f:
49+
# hh:mm:ss
50+
d = int.from_bytes(reg.value[2:], 'big')
51+
value_str = f'{(d//10000):02}:{(d // 100 % 100):02}:{(d % 100):02}'
52+
pass
53+
case 0x30:
54+
# yy-mm-dd
55+
d = int.from_bytes(reg.value[2:], 'big')
56+
value_str = f'{(2000 + d//10000):02}-{(d // 100 % 100):02}-{(d % 100):02}'
57+
pass
58+
case 0x32:
59+
# mm-dd
60+
d = int.from_bytes(reg.value[2:], 'big')
61+
value_str = f'{(d // 100 % 100):02}-{(d % 100):02}'
62+
case _:
63+
value_dec = codec.FloatCodec.decode(reg.value)
4564
return cls(
4665
id_int=reg.id_,
4766
unit_int=reg.unit,
4867
value_dec=value_dec,
68+
value_str=value_str,
4969
)
5070

5171
def to_pretty_line(self) -> str:

tests/test_registers.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,30 @@
2828
decimal.Decimal('378.022'),
2929
'GJ',
3030
),
31+
pytest.param(
32+
1002,
33+
47,
34+
'04 00 00 00 00 04',
35+
'00:00:04',
36+
None,
37+
'hh:mm:ss',
38+
),
39+
pytest.param(
40+
1003,
41+
48,
42+
'04 00 00 03 ae 4f',
43+
'2024-12-31',
44+
None,
45+
'yy:mm:dd',
46+
),
47+
pytest.param(
48+
0,
49+
50,
50+
'04 00 00 03 38',
51+
'08-24',
52+
None,
53+
'mm:dd',
54+
),
3155
]
3256
)
3357
def test_register_parsing(id_, unit, blob_with_size, value_str, value_dec, unit_str):

0 commit comments

Comments
 (0)