Coverage for src / bluetooth_sig / gatt / characteristics / cardiorespiratory_activity_summary_data.py: 100%
51 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 Summary Data characteristic (0x2B3F)."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ..context import CharacteristicContext
10from .base import BaseCharacteristic
11from .utils import DataParser
14class CardioRespiratorySummaryFlags(IntFlag):
15 """Flags for CardioRespiratory Activity Summary Data (Table 3.13)."""
17 TIME_IN_HR_ZONE1_PRESENT = 0x00000001
18 TIME_IN_HR_ZONE2_PRESENT = 0x00000002
19 TIME_IN_HR_ZONE3_PRESENT = 0x00000004
20 TIME_IN_HR_ZONE4_PRESENT = 0x00000008
21 TIME_IN_HR_ZONE5_PRESENT = 0x00000010
22 MIN_VO2_MAX_PRESENT = 0x00000020
23 MAX_VO2_MAX_PRESENT = 0x00000040
24 AVG_VO2_MAX_PRESENT = 0x00000080
25 MIN_HEART_RATE_PRESENT = 0x00000100
26 MAX_HEART_RATE_PRESENT = 0x00000200
27 AVG_HEART_RATE_PRESENT = 0x00000400
28 MIN_PULSE_IBI_PRESENT = 0x00000800
29 MAX_PULSE_IBI_PRESENT = 0x00001000
30 AVG_PULSE_IBI_PRESENT = 0x00002000
31 MIN_RESTING_HR_PRESENT = 0x00004000
32 MAX_RESTING_HR_PRESENT = 0x00008000
33 AVG_RESTING_HR_PRESENT = 0x00010000
34 MIN_HRV_PRESENT = 0x00020000
35 MAX_HRV_PRESENT = 0x00040000
36 AVG_HRV_PRESENT = 0x00080000
37 MIN_RESPIRATION_RATE_PRESENT = 0x00100000
38 MAX_RESPIRATION_RATE_PRESENT = 0x00200000
39 AVG_RESPIRATION_RATE_PRESENT = 0x00400000
40 MIN_RESTING_RESP_PRESENT = 0x00800000
41 MAX_RESTING_RESP_PRESENT = 0x01000000
42 AVG_RESTING_RESP_PRESENT = 0x02000000
43 WORN_DURATION_PRESENT = 0x04000000
46class CardioRespiratoryActivitySummaryData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
47 """Parsed data from CardioRespiratory Activity Summary Data.
49 Contains flags and any additional summary field data as raw bytes.
50 The flags field indicates which optional fields are present.
51 """
53 flags: CardioRespiratorySummaryFlags
54 additional_data: bytes = b""
57_FLAGS_SIZE = 4 # flags field (uint32)
60class CardioRespiratoryActivitySummaryDataCharacteristic(
61 BaseCharacteristic[CardioRespiratoryActivitySummaryData],
62):
63 """CardioRespiratory Activity Summary Data characteristic (0x2B3F).
65 org.bluetooth.characteristic.cardiorespiratory_activity_summary_data
67 Summary cardiorespiratory activity data from the Physical
68 Activity Monitor service. Flags indicate which optional summary
69 fields are present.
70 """
72 _characteristic_name = "CardioRespiratory Activity Summary Data"
73 min_length = 4 # flags (uint32)
74 allow_variable_length = True
76 def _decode_value(
77 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
78 ) -> CardioRespiratoryActivitySummaryData:
79 """Parse CardioRespiratory Activity Summary Data.
81 Format: flags (uint32) + variable optional fields.
82 """
83 flags = CardioRespiratorySummaryFlags(DataParser.parse_int32(data, 0, signed=False))
84 additional_data = bytes(data[_FLAGS_SIZE:]) if len(data) > _FLAGS_SIZE else b""
86 return CardioRespiratoryActivitySummaryData(
87 flags=flags,
88 additional_data=additional_data,
89 )
91 def _encode_value(self, data: CardioRespiratoryActivitySummaryData) -> bytearray:
92 """Encode CardioRespiratory Activity Summary Data to bytes."""
93 result = bytearray()
94 result += DataParser.encode_int32(int(data.flags), signed=False)
95 result += bytearray(data.additional_data)
96 return result