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

39 statements  

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

1"""Step Counter Activity Summary Data characteristic (0x2B40). 

2 

3Summary of step counter activity data with segmented header. 

4 

5References: 

6 Bluetooth SIG Physical Activity Monitor Service 1.0 

7""" 

8 

9from __future__ import annotations 

10 

11from enum import IntFlag 

12 

13import msgspec 

14 

15from ..context import CharacteristicContext 

16from .base import BaseCharacteristic 

17from .utils import DataParser 

18 

19 

20class StepCounterActivitySummaryFlags(IntFlag): 

21 """Step Counter Activity Summary Data flags (8-bit, 1 octet).""" 

22 

23 NORMAL_WALKING_STEPS_PRESENT = 0x01 

24 INTENSITY_STEPS_PRESENT = 0x02 

25 FLOOR_STEPS_PRESENT = 0x04 

26 DISTANCE_PRESENT = 0x08 

27 WORN_DURATION_PRESENT = 0x10 

28 

29 

30class StepCounterActivitySummaryData(msgspec.Struct, frozen=True, kw_only=True): 

31 """Parsed data from Step Counter Activity Summary Data. 

32 

33 Attributes: 

34 header: Segmentation header byte. 

35 flags: Presence flags for optional fields (8-bit). 

36 session_id: Session identifier (uint16). 

37 sub_session_id: Sub-session identifier (uint16). 

38 relative_timestamp: Relative timestamp in seconds (uint32). 

39 sequence_number: Sequence number (uint32). 

40 

41 """ 

42 

43 header: int 

44 flags: StepCounterActivitySummaryFlags 

45 session_id: int 

46 sub_session_id: int 

47 relative_timestamp: int 

48 sequence_number: int 

49 

50 

51class StepCounterActivitySummaryDataCharacteristic( 

52 BaseCharacteristic[StepCounterActivitySummaryData], 

53): 

54 """Step Counter Activity Summary Data characteristic (0x2B40). 

55 

56 org.bluetooth.characteristic.step_counter_activity_summary_data 

57 

58 Summary of step counter activity with optional fields indicated 

59 by a flags field. 

60 """ 

61 

62 min_length = 14 # header(1) + flags(1) + session(2) + subsession(2) + timestamp(4) + sequence(4) 

63 allow_variable_length = True 

64 

65 def _decode_value( 

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

67 ) -> StepCounterActivitySummaryData: 

68 """Parse Step Counter Activity Summary Data. 

69 

70 Format: Header (uint8) + Flags (uint8) + SessionID (uint16) 

71 + SubSessionID (uint16) + RelativeTimestamp (uint32) 

72 + SequenceNumber (uint32) + [optional fields]. 

73 """ 

74 header = DataParser.parse_int8(data, 0, signed=False) 

75 flags = StepCounterActivitySummaryFlags(DataParser.parse_int8(data, 1, signed=False)) 

76 session_id = DataParser.parse_int16(data, 2, signed=False) 

77 sub_session_id = DataParser.parse_int16(data, 4, signed=False) 

78 relative_timestamp = DataParser.parse_int32(data, 6, signed=False) 

79 sequence_number = DataParser.parse_int32(data, 10, signed=False) 

80 

81 return StepCounterActivitySummaryData( 

82 header=header, 

83 flags=flags, 

84 session_id=session_id, 

85 sub_session_id=sub_session_id, 

86 relative_timestamp=relative_timestamp, 

87 sequence_number=sequence_number, 

88 ) 

89 

90 def _encode_value(self, data: StepCounterActivitySummaryData) -> bytearray: 

91 """Encode Step Counter Activity Summary Data.""" 

92 result = bytearray() 

93 result.extend(DataParser.encode_int8(data.header, signed=False)) 

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

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

96 result.extend(DataParser.encode_int16(data.sub_session_id, signed=False)) 

97 result.extend(DataParser.encode_int32(data.relative_timestamp, signed=False)) 

98 result.extend(DataParser.encode_int32(data.sequence_number, signed=False)) 

99 return result