Coverage for src / bluetooth_sig / gatt / characteristics / cardiorespiratory_activity_instantaneous_data.py: 100%
32 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"""CardioRespiratory Activity Instantaneous Data characteristic (0x2B3E)."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ..context import CharacteristicContext
10from .base import BaseCharacteristic
11from .utils import DataParser
14class CardioRespiratoryInstantaneousFlags(IntFlag):
15 """Flags for CardioRespiratory Activity Instantaneous Data (Table 3.11)."""
17 VO2_MAX_PRESENT = 0x0001
18 HEART_RATE_PRESENT = 0x0002
19 PULSE_INTER_BEAT_INTERVAL_PRESENT = 0x0004
20 RESTING_HEART_RATE_PRESENT = 0x0008
21 HEART_RATE_VARIABILITY_PRESENT = 0x0010
22 RESPIRATION_RATE_PRESENT = 0x0020
23 RESTING_RESPIRATION_RATE_PRESENT = 0x0040
24 DEVICE_WORN = 0x8000
27class CardioRespiratoryActivityInstantaneousData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
28 """Parsed data from CardioRespiratory Activity Instantaneous Data.
30 Contains flags and any additional field data as raw bytes.
31 The flags field indicates which optional fields are present.
32 """
34 flags: CardioRespiratoryInstantaneousFlags
35 additional_data: bytes = b""
38_FLAGS_SIZE = 2 # flags field (uint16)
41class CardioRespiratoryActivityInstantaneousDataCharacteristic(
42 BaseCharacteristic[CardioRespiratoryActivityInstantaneousData],
43):
44 """CardioRespiratory Activity Instantaneous Data characteristic (0x2B3E).
46 org.bluetooth.characteristic.cardiorespiratory_activity_instantaneous_data
48 Instantaneous cardiorespiratory activity data from the Physical
49 Activity Monitor service. Flags indicate which optional fields
50 (heart rate, resting heart rate, cadence, distance, etc.) are present.
51 """
53 _characteristic_name = "CardioRespiratory Activity Instantaneous Data"
54 min_length = 2 # flags (uint16)
55 allow_variable_length = True
57 def _decode_value(
58 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
59 ) -> CardioRespiratoryActivityInstantaneousData:
60 """Parse CardioRespiratory Activity Instantaneous Data.
62 Format: flags (uint16) + variable optional fields.
63 """
64 flags = CardioRespiratoryInstantaneousFlags(DataParser.parse_int16(data, 0, signed=False))
65 additional_data = bytes(data[_FLAGS_SIZE:]) if len(data) > _FLAGS_SIZE else b""
67 return CardioRespiratoryActivityInstantaneousData(
68 flags=flags,
69 additional_data=additional_data,
70 )
72 def _encode_value(self, data: CardioRespiratoryActivityInstantaneousData) -> bytearray:
73 """Encode CardioRespiratory Activity Instantaneous Data to bytes."""
74 result = bytearray()
75 result += DataParser.encode_int16(int(data.flags), signed=False)
76 result += bytearray(data.additional_data)
77 return result