Coverage for src / bluetooth_sig / gatt / characteristics / physical_activity_current_session.py: 100%
38 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"""Physical Activity Current Session characteristic (0x2B44).
3Contains current session data including activity type and session start indicator.
5References:
6 Bluetooth SIG Physical Activity Monitor Service 1.0
7"""
9from __future__ import annotations
11from enum import IntEnum, IntFlag
13import msgspec
15from ..context import CharacteristicContext
16from .base import BaseCharacteristic
17from .utils import DataParser
20class PAMSessionFlags(IntFlag):
21 """Physical Activity Current Session flags."""
23 SESSION_ACTIVE = 0x01
24 ACTIVITY_TYPE_PRESENT = 0x02
27class PAMActivityType(IntEnum):
28 """Physical Activity Monitor activity types."""
30 NO_ACTIVITY = 0x00
31 WALKING = 0x01
32 RUNNING = 0x02
33 CYCLING = 0x03
34 SWIMMING = 0x04
35 GENERIC = 0xFF
38_ACTIVITY_TYPE_MINIMUM_LENGTH = 4
41class PhysicalActivityCurrentSessionData(msgspec.Struct, frozen=True, kw_only=True):
42 """Parsed data from Physical Activity Current Session characteristic.
44 Attributes:
45 flags: Session presence flags.
46 session_id: Session identifier.
47 activity_type: Type of physical activity. None if not present.
49 """
51 flags: PAMSessionFlags
52 session_id: int
53 activity_type: PAMActivityType | None = None
56class PhysicalActivityCurrentSessionCharacteristic(BaseCharacteristic[PhysicalActivityCurrentSessionData]):
57 """Physical Activity Current Session characteristic (0x2B44).
59 org.bluetooth.characteristic.physical_activity_current_session
61 Reports the current session information for the Physical Activity Monitor.
62 """
64 min_length = 3 # flags(1) + session_id(2)
65 allow_variable_length = True
67 def _decode_value(
68 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
69 ) -> PhysicalActivityCurrentSessionData:
70 """Parse Physical Activity Current Session data.
72 Format: Flags (uint8) + SessionID (uint16 LE) + [ActivityType (uint8)].
73 """
74 flags = PAMSessionFlags(DataParser.parse_int8(data, 0, signed=False))
75 session_id = DataParser.parse_int16(data, 1, signed=False)
77 activity_type: PAMActivityType | None = None
78 if flags & PAMSessionFlags.ACTIVITY_TYPE_PRESENT and len(data) >= _ACTIVITY_TYPE_MINIMUM_LENGTH:
79 activity_type = PAMActivityType(DataParser.parse_int8(data, 3, signed=False))
81 return PhysicalActivityCurrentSessionData(
82 flags=flags,
83 session_id=session_id,
84 activity_type=activity_type,
85 )
87 def _encode_value(self, data: PhysicalActivityCurrentSessionData) -> bytearray:
88 """Encode Physical Activity Current Session data."""
89 result = bytearray()
90 result.extend(DataParser.encode_int8(int(data.flags), signed=False))
91 result.extend(DataParser.encode_int16(data.session_id, signed=False))
92 if data.activity_type is not None:
93 result.extend(DataParser.encode_int8(int(data.activity_type), signed=False))
94 return result