Coverage for src / bluetooth_sig / gatt / characteristics / general_activity_instantaneous_data.py: 100%
47 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"""General Activity Instantaneous Data characteristic (0x2B3C).
3Reports instantaneous general 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 GeneralActivityInstFlags(IntFlag):
21 """General Activity Instantaneous Data flags (24-bit, 3 octets)."""
23 NORMAL_WALKING_EE_PER_HOUR_PRESENT = 0x000001
24 INTENSITY_EE_PER_HOUR_PRESENT = 0x000002
25 TOTAL_EE_PER_HOUR_PRESENT = 0x000004
26 FAT_BURNED_PER_HOUR_PRESENT = 0x000008
27 METABOLIC_EQUIVALENT_PRESENT = 0x000010
28 SPEED_PRESENT = 0x000020
29 MOTION_CADENCE_PRESENT = 0x000040
30 ELEVATION_PRESENT = 0x000080
31 ACTIVITY_COUNT_PER_MINUTE_PRESENT = 0x000100
32 ACTIVITY_LEVEL_PRESENT = 0x000200
33 ACTIVITY_TYPE_PRESENT = 0x000400
34 DEVICE_WORN = 0x800000
37class GeneralActivityInstantaneousData(msgspec.Struct, frozen=True, kw_only=True):
38 """Parsed data from General Activity Instantaneous Data characteristic.
40 Attributes:
41 header: Segmentation header byte.
42 flags: Presence flags for optional fields (24-bit).
43 session_id: Session identifier (uint16).
44 sub_session_id: Sub-session identifier (uint16).
45 relative_timestamp: Relative timestamp in seconds (uint32).
46 sequence_number: Sequence number (uint32).
48 """
50 header: int
51 flags: GeneralActivityInstFlags
52 session_id: int
53 sub_session_id: int
54 relative_timestamp: int
55 sequence_number: int
58class GeneralActivityInstantaneousDataCharacteristic(BaseCharacteristic[GeneralActivityInstantaneousData]):
59 """General Activity Instantaneous Data characteristic (0x2B3C).
61 org.bluetooth.characteristic.general_activity_instantaneous_data
63 Reports instantaneous general activity data.
64 """
66 min_length = 16 # header(1) + flags(3) + session(2) + subsession(2) + timestamp(4) + sequence(4)
67 allow_variable_length = True
69 def _decode_value(
70 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
71 ) -> GeneralActivityInstantaneousData:
72 """Parse General Activity Instantaneous Data.
74 Format: Header (uint8) + Flags (uint24) + SessionID (uint16)
75 + SubSessionID (uint16) + RelativeTimestamp (uint32)
76 + SequenceNumber (uint32) + [optional fields].
77 """
78 header = DataParser.parse_int8(data, 0, signed=False)
79 flags_raw = DataParser.parse_int24(data, 1, signed=False)
80 flags = GeneralActivityInstFlags(flags_raw)
81 session_id = DataParser.parse_int16(data, 4, signed=False)
82 sub_session_id = DataParser.parse_int16(data, 6, signed=False)
83 relative_timestamp = DataParser.parse_int32(data, 8, signed=False)
84 sequence_number = DataParser.parse_int32(data, 12, signed=False)
86 return GeneralActivityInstantaneousData(
87 header=header,
88 flags=flags,
89 session_id=session_id,
90 sub_session_id=sub_session_id,
91 relative_timestamp=relative_timestamp,
92 sequence_number=sequence_number,
93 )
95 def _encode_value(self, data: GeneralActivityInstantaneousData) -> bytearray:
96 """Encode General Activity Instantaneous data."""
97 result = bytearray()
98 result.extend(DataParser.encode_int8(data.header, signed=False))
99 result.extend(DataParser.encode_int24(int(data.flags), signed=False))
100 result.extend(DataParser.encode_int16(data.session_id, signed=False))
101 result.extend(DataParser.encode_int16(data.sub_session_id, signed=False))
102 result.extend(DataParser.encode_int32(data.relative_timestamp, signed=False))
103 result.extend(DataParser.encode_int32(data.sequence_number, signed=False))
104 return result