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

42 statements  

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

1"""IDD Status characteristic (0x2B21). 

2 

3Reports the current status of the Insulin Delivery Device including 

4therapy control state, operational state, and reservoir remaining. 

5 

6References: 

7 Bluetooth SIG Insulin Delivery Service 1.0.1, Table 4.3 

8""" 

9 

10from __future__ import annotations 

11 

12from enum import IntEnum, IntFlag 

13 

14import msgspec 

15 

16from ..context import CharacteristicContext 

17from .base import BaseCharacteristic 

18from .utils import DataParser, IEEE11073Parser 

19 

20 

21class TherapyControlState(IntEnum): 

22 """IDD therapy control state (Hamming-coded).""" 

23 

24 UNDETERMINED = 0x0F 

25 STOP = 0x33 

26 PAUSE = 0x3C 

27 RUN = 0x55 

28 

29 

30class IDDOperationalState(IntEnum): 

31 """IDD operational state (Hamming-coded).""" 

32 

33 UNDETERMINED = 0x0F 

34 OFF = 0x33 

35 STANDBY = 0x3C 

36 PREPARING = 0x55 

37 PRIMING = 0x5A 

38 WAITING = 0x66 

39 READY = 0x96 

40 

41 

42class IDDStatusFlags(IntFlag): 

43 """IDD Status flags (8-bit).""" 

44 

45 RESERVOIR_ATTACHED = 0x01 

46 

47 

48class IDDStatusData(msgspec.Struct, frozen=True, kw_only=True): 

49 """Parsed data from IDD Status characteristic. 

50 

51 Attributes: 

52 therapy_control_state: Current therapy control state. 

53 operational_state: Current operational state. 

54 reservoir_remaining: Reservoir remaining amount (SFLOAT). 

55 flags: Status flags. 

56 

57 """ 

58 

59 therapy_control_state: TherapyControlState 

60 operational_state: IDDOperationalState 

61 reservoir_remaining: float 

62 flags: IDDStatusFlags 

63 

64 

65class IDDStatusCharacteristic(BaseCharacteristic[IDDStatusData]): 

66 """IDD Status characteristic (0x2B21). 

67 

68 org.bluetooth.characteristic.idd_status 

69 

70 Reports therapy control state, operational state, and 

71 reservoir remaining for an Insulin Delivery Device. 

72 """ 

73 

74 min_length = 5 # therapy(1) + operational(1) + reservoir_sfloat(2) + flags(1) 

75 allow_variable_length = True 

76 

77 def _decode_value( 

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

79 ) -> IDDStatusData: 

80 """Parse IDD Status data. 

81 

82 Format: TherapyControlState (uint8) + OperationalState (uint8) + 

83 ReservoirRemainingAmount (SFLOAT, 2 bytes) + Flags (uint8). 

84 """ 

85 therapy_control_state = TherapyControlState(DataParser.parse_int8(data, 0, signed=False)) 

86 operational_state = IDDOperationalState(DataParser.parse_int8(data, 1, signed=False)) 

87 reservoir_remaining = IEEE11073Parser.parse_sfloat(data, 2) 

88 flags = IDDStatusFlags(DataParser.parse_int8(data, 4, signed=False)) 

89 

90 return IDDStatusData( 

91 therapy_control_state=therapy_control_state, 

92 operational_state=operational_state, 

93 reservoir_remaining=reservoir_remaining, 

94 flags=flags, 

95 ) 

96 

97 def _encode_value(self, data: IDDStatusData) -> bytearray: 

98 """Encode IDD Status data.""" 

99 result = bytearray() 

100 result.extend(DataParser.encode_int8(int(data.therapy_control_state), signed=False)) 

101 result.extend(DataParser.encode_int8(int(data.operational_state), signed=False)) 

102 result.extend(IEEE11073Parser.encode_sfloat(data.reservoir_remaining)) 

103 result.extend(DataParser.encode_int8(int(data.flags), signed=False)) 

104 return result