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

24 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-18 11:17 +0000

1"""CGM Session Run Time characteristic implementation. 

2 

3Implements the CGM Session Run Time characteristic (0x2AAB). 

4 

5Structure (from GSS YAML): 

6 CGM Session Run Time (uint16) -- expected run time in hours 

7 E2E-CRC (uint16, optional) -- present if E2E-CRC Supported 

8 

9References: 

10 Bluetooth SIG Continuous Glucose Monitoring Service 

11 org.bluetooth.characteristic.cgm_session_run_time (GSS YAML) 

12""" 

13 

14from __future__ import annotations 

15 

16import msgspec 

17 

18from ..context import CharacteristicContext 

19from .base import BaseCharacteristic 

20from .utils import DataParser 

21 

22 

23class CGMSessionRunTimeData(msgspec.Struct, frozen=True, kw_only=True): 

24 """Parsed data from CGM Session Run Time characteristic. 

25 

26 Attributes: 

27 run_time_hours: Expected run time of the CGM session in hours. 

28 e2e_crc: E2E-CRC value. None if absent. 

29 

30 """ 

31 

32 run_time_hours: int 

33 e2e_crc: int | None = None 

34 

35 

36class CGMSessionRunTimeCharacteristic(BaseCharacteristic[CGMSessionRunTimeData]): 

37 """CGM Session Run Time characteristic (0x2AAB). 

38 

39 Reports the expected run time of the CGM session in hours. 

40 """ 

41 

42 expected_type = CGMSessionRunTimeData 

43 min_length: int = 2 # run_time(2) 

44 allow_variable_length: bool = True # optional E2E-CRC 

45 

46 def _decode_value( 

47 self, 

48 data: bytearray, 

49 ctx: CharacteristicContext | None = None, 

50 *, 

51 validate: bool = True, 

52 ) -> CGMSessionRunTimeData: 

53 """Parse CGM Session Run Time from raw BLE bytes. 

54 

55 Args: 

56 data: Raw bytearray from BLE characteristic (2 or 4 bytes). 

57 ctx: Optional context (unused). 

58 validate: Whether to validate ranges. 

59 

60 Returns: 

61 CGMSessionRunTimeData with parsed run time. 

62 

63 """ 

64 run_time_hours = DataParser.parse_int16(data, 0, signed=False) 

65 

66 _min_length_with_crc = 4 

67 e2e_crc: int | None = None 

68 if len(data) >= _min_length_with_crc: 

69 e2e_crc = DataParser.parse_int16(data, 2, signed=False) 

70 

71 return CGMSessionRunTimeData( 

72 run_time_hours=run_time_hours, 

73 e2e_crc=e2e_crc, 

74 ) 

75 

76 def _encode_value(self, data: CGMSessionRunTimeData) -> bytearray: 

77 """Encode CGMSessionRunTimeData back to BLE bytes. 

78 

79 Args: 

80 data: CGMSessionRunTimeData instance. 

81 

82 Returns: 

83 Encoded bytearray (2 or 4 bytes). 

84 

85 """ 

86 result = DataParser.encode_int16(data.run_time_hours, signed=False) 

87 if data.e2e_crc is not None: 

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

89 return result