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
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
1"""Step Counter Activity Summary Data characteristic (0x2B40).
3Summary of step counter activity data with segmented header.
5References:
6 Bluetooth SIG Physical Activity Monitor Service 1.0
7"""
9from __future__ import annotations
11from enum import IntFlag
13import msgspec
15from ..context import CharacteristicContext
16from .base import BaseCharacteristic
17from .utils import DataParser
20class StepCounterActivitySummaryFlags(IntFlag):
21 """Step Counter Activity Summary Data flags (8-bit, 1 octet)."""
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
30class StepCounterActivitySummaryData(msgspec.Struct, frozen=True, kw_only=True):
31 """Parsed data from Step Counter Activity Summary Data.
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).
41 """
43 header: int
44 flags: StepCounterActivitySummaryFlags
45 session_id: int
46 sub_session_id: int
47 relative_timestamp: int
48 sequence_number: int
51class StepCounterActivitySummaryDataCharacteristic(
52 BaseCharacteristic[StepCounterActivitySummaryData],
53):
54 """Step Counter Activity Summary Data characteristic (0x2B40).
56 org.bluetooth.characteristic.step_counter_activity_summary_data
58 Summary of step counter activity with optional fields indicated
59 by a flags field.
60 """
62 min_length = 14 # header(1) + flags(1) + session(2) + subsession(2) + timestamp(4) + sequence(4)
63 allow_variable_length = True
65 def _decode_value(
66 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
67 ) -> StepCounterActivitySummaryData:
68 """Parse Step Counter Activity Summary Data.
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)
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 )
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