Coverage for src / bluetooth_sig / gatt / characteristics / idd_features.py: 100%

46 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-03 16:41 +0000

1"""IDD Features characteristic (0x2B23). 

2 

3Composite structure: E2E-CRC (uint16) + E2E-Counter (uint8) + 

4Insulin Concentration (SFLOAT) + Flags (24-bit). 

5 

6References: 

7 Bluetooth SIG Insulin Delivery Service v1.0.1, Table 4.11, 4.12 

8""" 

9 

10from __future__ import annotations 

11 

12from enum import IntFlag 

13 

14import msgspec 

15 

16from ..context import CharacteristicContext 

17from .base import BaseCharacteristic 

18from .utils import DataParser, IEEE11073Parser 

19 

20 

21class IDDFeatureFlags(IntFlag): 

22 """IDD Feature flags (24-bit) per IDS v1.0.1 Table 4.12.""" 

23 

24 E2E_PROTECTION_SUPPORTED = 0x000001 # bit 0 

25 BASAL_RATE_SUPPORTED = 0x000002 # bit 1 

26 TBR_TYPE_ABSOLUTE_SUPPORTED = 0x000004 # bit 2 

27 TBR_TYPE_RELATIVE_SUPPORTED = 0x000008 # bit 3 

28 TBR_TEMPLATE_SUPPORTED = 0x000010 # bit 4 

29 FAST_BOLUS_SUPPORTED = 0x000020 # bit 5 

30 EXTENDED_BOLUS_SUPPORTED = 0x000040 # bit 6 

31 MULTIWAVE_BOLUS_SUPPORTED = 0x000080 # bit 7 

32 BOLUS_DELAY_TIME_SUPPORTED = 0x000100 # bit 8 

33 BOLUS_TEMPLATE_SUPPORTED = 0x000200 # bit 9 

34 BOLUS_ACTIVATION_TYPE_SUPPORTED = 0x000400 # bit 10 

35 MULTIPLE_BOND_SUPPORTED = 0x000800 # bit 11 

36 ISF_PROFILE_TEMPLATE_SUPPORTED = 0x001000 # bit 12 

37 I2CHO_RATIO_PROFILE_TEMPLATE_SUPPORTED = 0x002000 # bit 13 

38 TARGET_GLUCOSE_RANGE_PROFILE_TEMPLATE_SUPPORTED = 0x004000 # bit 14 

39 INSULIN_ON_BOARD_SUPPORTED = 0x008000 # bit 15 

40 FEATURE_EXTENSION = 0x800000 # bit 23 

41 

42 

43class IDDFeaturesData(msgspec.Struct, frozen=True, kw_only=True): 

44 """Parsed IDD Features characteristic data. 

45 

46 Attributes: 

47 e2e_crc: CRC-CCITT value (0xFFFF if E2E not supported). 

48 e2e_counter: E2E counter (0x00 if E2E not supported). 

49 insulin_concentration: Insulin concentration as SFLOAT. 

50 flags: Supported feature flags (24-bit). 

51 

52 """ 

53 

54 e2e_crc: int 

55 e2e_counter: int 

56 insulin_concentration: float 

57 flags: IDDFeatureFlags 

58 

59 

60class IDDFeaturesCharacteristic(BaseCharacteristic[IDDFeaturesData]): 

61 """IDD Features characteristic (0x2B23). 

62 

63 org.bluetooth.characteristic.idd_features 

64 

65 Reports supported features of the Insulin Delivery Device. 

66 Structure: E2E-CRC(2) + E2E-Counter(1) + InsulinConcentration(2) + Flags(3) = 8 bytes. 

67 """ 

68 

69 min_length = 8 

70 allow_variable_length = True 

71 

72 def _decode_value( 

73 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True 

74 ) -> IDDFeaturesData: 

75 """Parse IDD Features data per IDS v1.0.1 Table 4.11.""" 

76 e2e_crc = DataParser.parse_int16(data, 0, signed=False) 

77 e2e_counter = DataParser.parse_int8(data, 2, signed=False) 

78 insulin_concentration = IEEE11073Parser.parse_sfloat(data, 3) 

79 flags_raw = DataParser.parse_int24(data, 5, signed=False) 

80 flags = IDDFeatureFlags(flags_raw) 

81 return IDDFeaturesData( 

82 e2e_crc=e2e_crc, 

83 e2e_counter=e2e_counter, 

84 insulin_concentration=insulin_concentration, 

85 flags=flags, 

86 ) 

87 

88 def _encode_value(self, data: IDDFeaturesData) -> bytearray: 

89 """Encode IDD Features data.""" 

90 result = bytearray() 

91 result.extend(DataParser.encode_int16(data.e2e_crc, signed=False)) 

92 result.extend(DataParser.encode_int8(data.e2e_counter, signed=False)) 

93 result.extend(IEEE11073Parser.encode_sfloat(data.insulin_concentration)) 

94 result.extend(DataParser.encode_int24(int(data.flags), signed=False)) 

95 return result