Coverage for src/bluetooth_sig/gatt/descriptors/valid_range_and_accuracy.py: 91%

23 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-30 00:10 +0000

1"""Valid Range and Accuracy Descriptor implementation.""" 

2 

3from __future__ import annotations 

4 

5import msgspec 

6 

7from ..characteristics.utils import DataParser 

8from .base import BaseDescriptor, RangeDescriptorMixin 

9 

10 

11class ValidRangeAndAccuracyData(msgspec.Struct, frozen=True, kw_only=True): 

12 """Valid Range and Accuracy descriptor data.""" 

13 

14 min_value: int | float 

15 max_value: int | float 

16 accuracy: int | float 

17 

18 

19class ValidRangeAndAccuracyDescriptor(BaseDescriptor, RangeDescriptorMixin): 

20 """Valid Range and Accuracy Descriptor (0x2911). 

21 

22 Defines the valid range and accuracy for characteristic values. 

23 Contains minimum value, maximum value, and accuracy information. 

24 """ 

25 

26 def _has_structured_data(self) -> bool: 

27 return True 

28 

29 def _get_data_format(self) -> str: 

30 return "struct" 

31 

32 def _parse_descriptor_value(self, data: bytes) -> ValidRangeAndAccuracyData: 

33 """Parse Valid Range and Accuracy descriptor value. 

34 

35 The format depends on the characteristic's value type. 

36 For simplicity, this implementation assumes uint16 values. 

37 

38 Args: 

39 data: Raw bytes containing min, max, and accuracy values 

40 

41 Returns: 

42 ValidRangeAndAccuracyData with range and accuracy info 

43 

44 Raises: 

45 ValueError: If data length is incorrect 

46 """ 

47 # Valid Range and Accuracy format: min_value + max_value + accuracy 

48 # For now, assume 6 bytes total (2 bytes each for uint16) 

49 if len(data) != 6: 

50 raise ValueError(f"Valid Range and Accuracy data expected 6 bytes, got {len(data)}") 

51 

52 min_value = DataParser.parse_int16(data, offset=0, endian="little") 

53 max_value = DataParser.parse_int16(data, offset=2, endian="little") 

54 accuracy = DataParser.parse_int16(data, offset=4, endian="little") 

55 

56 return ValidRangeAndAccuracyData( 

57 min_value=min_value, 

58 max_value=max_value, 

59 accuracy=accuracy, 

60 ) 

61 

62 def get_accuracy(self, data: bytes) -> int | float: 

63 """Get the accuracy value. 

64 

65 Args: 

66 data: Raw descriptor data 

67 

68 Returns: 

69 Accuracy value for the characteristic 

70 """ 

71 parsed = self._parse_descriptor_value(data) 

72 return parsed.accuracy