Coverage for src / bluetooth_sig / gatt / characteristics / blood_pressure_feature.py: 100%
40 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 20:14 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 20:14 +0000
1"""Blood Pressure Feature characteristic implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ...types.gatt_enums import ValueType
10from ..constants import UINT16_MAX
11from ..context import CharacteristicContext
12from .base import BaseCharacteristic
13from .utils import DataParser
16class BloodPressureFeatures(IntFlag):
17 """Blood Pressure Feature flags as per Bluetooth SIG specification."""
19 BODY_MOVEMENT_DETECTION = 0x01
20 CUFF_FIT_DETECTION = 0x02
21 IRREGULAR_PULSE_DETECTION = 0x04
22 PULSE_RATE_RANGE_DETECTION = 0x08
23 MEASUREMENT_POSITION_DETECTION = 0x10
24 MULTIPLE_BOND_SUPPORT = 0x20
27class BloodPressureFeatureData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
28 """Parsed data from Blood Pressure Feature characteristic."""
30 features_bitmap: int
31 body_movement_detection_support: bool
32 cuff_fit_detection_support: bool
33 irregular_pulse_detection_support: bool
34 pulse_rate_range_detection_support: bool
35 measurement_position_detection_support: bool
36 multiple_bond_support: bool
39class BloodPressureFeatureCharacteristic(BaseCharacteristic[BloodPressureFeatureData]):
40 """Blood Pressure Feature characteristic (0x2A49).
42 Used to expose the supported features of a blood pressure monitoring
43 device. Indicates which optional measurements and capabilities are
44 available.
45 """
47 _manual_value_type: ValueType | str | None = ValueType.DICT # Override since decode_value returns dataclass
49 # YAML has no range constraint; enforce full uint16 bitmap range.
50 min_value: int = 0
51 max_value: int = UINT16_MAX
53 def _decode_value(self, data: bytearray, ctx: CharacteristicContext | None = None) -> BloodPressureFeatureData:
54 """Parse blood pressure feature data according to Bluetooth specification.
56 Format: Features(2) - 16-bit bitmap indicating supported features.
58 Args:
59 data: Raw bytearray from BLE characteristic.
60 ctx: Optional CharacteristicContext providing surrounding context (may be None).
62 Returns:
63 BloodPressureFeatureData containing parsed feature bitmap and capabilities.
65 """
66 if len(data) < 2:
67 raise ValueError("Blood Pressure Feature data must be at least 2 bytes")
69 features_bitmap = DataParser.parse_int16(data, 0, signed=False)
71 body_movement_detection = bool(features_bitmap & BloodPressureFeatures.BODY_MOVEMENT_DETECTION)
72 cuff_fit_detection = bool(features_bitmap & BloodPressureFeatures.CUFF_FIT_DETECTION)
73 irregular_pulse_detection = bool(features_bitmap & BloodPressureFeatures.IRREGULAR_PULSE_DETECTION)
74 pulse_rate_range_detection = bool(features_bitmap & BloodPressureFeatures.PULSE_RATE_RANGE_DETECTION)
75 measurement_position_detection = bool(features_bitmap & BloodPressureFeatures.MEASUREMENT_POSITION_DETECTION)
76 multiple_bond_support = bool(features_bitmap & BloodPressureFeatures.MULTIPLE_BOND_SUPPORT)
78 return BloodPressureFeatureData(
79 features_bitmap=features_bitmap,
80 body_movement_detection_support=body_movement_detection,
81 cuff_fit_detection_support=cuff_fit_detection,
82 irregular_pulse_detection_support=irregular_pulse_detection,
83 pulse_rate_range_detection_support=pulse_rate_range_detection,
84 measurement_position_detection_support=measurement_position_detection,
85 multiple_bond_support=multiple_bond_support,
86 )
88 def _encode_value(self, data: BloodPressureFeatureData) -> bytearray:
89 """Encode BloodPressureFeatureData back to bytes.
91 Args:
92 data: BloodPressureFeatureData instance to encode
94 Returns:
95 Encoded bytes representing the blood pressure features
97 """
98 return DataParser.encode_int16(data.features_bitmap, signed=False)