diff --git a/pyplumio/helpers/uid.py b/pyplumio/helpers/uid.py index 1c333d85..6fafa5b6 100644 --- a/pyplumio/helpers/uid.py +++ b/pyplumio/helpers/uid.py @@ -1,6 +1,9 @@ """Contains an UID helpers.""" from __future__ import annotations +from functools import reduce +from typing import Final + def unpack_uid(message: bytearray, offset: int = 0) -> str: """Decode and return a complete UID string.""" @@ -8,10 +11,10 @@ def unpack_uid(message: bytearray, offset: int = 0) -> str: offset += 1 uid = message[offset : length + offset] - return _encode_base5(uid + _uid_crc(uid)) + return _base5(uid + _crc16(uid)) -def _encode_base5(data: bytes) -> str: +def _base5(data: bytes) -> str: """Encode bytes to a base5 encoded string.""" key_string = "0123456789ABCDEFGHIJKLMNZPQRSTUV" number = int.from_bytes(data, "little") @@ -23,18 +26,20 @@ def _encode_base5(data: bytes) -> str: return output -def _uid_crc(message: bytes) -> bytes: - """Return an UID CRC.""" - crc_value = 0xA3A3 - for byte in message: - crc_value = _uid_byte(crc_value ^ byte) +CRC: Final = 0xA3A3 +POLYNOMIAL: Final = 0xA001 - return crc_value.to_bytes(byteorder="little", length=2) + +def _crc16(message: bytes) -> bytes: + """Return an UID CRC.""" + crc16 = reduce(_crc16_byte, message, CRC) + return crc16.to_bytes(byteorder="little", length=2) -def _uid_byte(byte: int) -> int: +def _crc16_byte(crc: int, byte: int) -> int: """Return a byte CRC.""" + crc ^= byte for _ in range(8): - byte = (byte >> 1) ^ 0xA001 if byte & 1 else byte >> 1 + crc = (crc >> 1) ^ POLYNOMIAL if crc & 1 else crc >> 1 - return byte + return crc