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

48 statements  

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

1"""Physical Activity Session Descriptor characteristic (0x2B45). 

2 

3Describes properties of a completed or ongoing activity session. 

4 

5References: 

6 Bluetooth SIG Physical Activity Monitor Service 1.0 

7""" 

8 

9from __future__ import annotations 

10 

11from enum import IntEnum 

12 

13import msgspec 

14 

15from ..context import CharacteristicContext 

16from .base import BaseCharacteristic 

17from .utils import DataParser 

18 

19 

20class PAMSessionStatus(IntEnum): 

21 """Physical Activity session status.""" 

22 

23 COMPLETE = 0x00 

24 IN_PROGRESS = 0x01 

25 PAUSED = 0x02 

26 

27 

28class ActivityType(IntEnum): 

29 """Physical Activity session activity type (PAMS v1.0 Table 3.7).""" 

30 

31 UNSPECIFIED = 0x00 

32 OTHER = 0x01 

33 SIT = 0x02 

34 LIE = 0x03 

35 STAND = 0x04 

36 WALK = 0x05 

37 SHUFFLE = 0x06 

38 RUN = 0x07 

39 CYCLE_INDOOR = 0x08 

40 CYCLE_OUTDOOR = 0x09 

41 CYCLE = 0x0A 

42 AEROBIC_WORKOUT = 0x0B 

43 ELLIPTICAL = 0x0C 

44 SPORTS = 0x0D 

45 SWIM = 0x0E 

46 UNKNOWN = 0xFF 

47 

48 

49class PhysicalActivitySessionDescriptorData(msgspec.Struct, frozen=True, kw_only=True): 

50 """Parsed data from Physical Activity Session Descriptor characteristic. 

51 

52 Attributes: 

53 session_id: Session identifier. 

54 session_status: Status of the session. 

55 activity_type: Type of activity for this session (raw uint8). 

56 additional_data: Any additional descriptor bytes. 

57 

58 """ 

59 

60 session_id: int 

61 session_status: PAMSessionStatus 

62 activity_type: ActivityType 

63 additional_data: bytes = b"" 

64 

65 

66class PhysicalActivitySessionDescriptorCharacteristic(BaseCharacteristic[PhysicalActivitySessionDescriptorData]): 

67 """Physical Activity Session Descriptor characteristic (0x2B45). 

68 

69 org.bluetooth.characteristic.physical_activity_session_descriptor 

70 

71 Describes properties of an activity session. 

72 """ 

73 

74 min_length = 4 # session_id(2) + status(1) + activity_type(1) 

75 allow_variable_length = True 

76 

77 def _decode_value( 

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

79 ) -> PhysicalActivitySessionDescriptorData: 

80 """Parse Physical Activity Session Descriptor data. 

81 

82 Format: SessionID (uint16 LE) + SessionStatus (uint8) + ActivityType (uint8) 

83 + AdditionalData (variable). 

84 """ 

85 session_id = DataParser.parse_int16(data, 0, signed=False) 

86 session_status = PAMSessionStatus(DataParser.parse_int8(data, 2, signed=False)) 

87 activity_type = ActivityType(DataParser.parse_int8(data, 3, signed=False)) 

88 additional_data = bytes(data[4:]) 

89 

90 return PhysicalActivitySessionDescriptorData( 

91 session_id=session_id, 

92 session_status=session_status, 

93 activity_type=activity_type, 

94 additional_data=additional_data, 

95 ) 

96 

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

98 """Encode Physical Activity Session Descriptor data.""" 

99 result = bytearray() 

100 result.extend(DataParser.encode_int16(data.session_id, signed=False)) 

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

102 result.extend(DataParser.encode_int8(int(data.activity_type), signed=False)) 

103 result.extend(data.additional_data) 

104 return result