Coverage for src/bluetooth_sig/gatt/characteristics/blood_pressure_feature.py: 100%
37 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""Blood Pressure Feature characteristic implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ...types.gatt_enums import ValueType
10from ..context import CharacteristicContext
11from .base import BaseCharacteristic
12from .utils import DataParser
15class BloodPressureFeatures(IntFlag):
16 """Blood Pressure Feature flags as per Bluetooth SIG specification."""
18 BODY_MOVEMENT_DETECTION = 0x01
19 CUFF_FIT_DETECTION = 0x02
20 IRREGULAR_PULSE_DETECTION = 0x04
21 PULSE_RATE_RANGE_DETECTION = 0x08
22 MEASUREMENT_POSITION_DETECTION = 0x10
23 MULTIPLE_BOND_SUPPORT = 0x20
26class BloodPressureFeatureData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
27 """Parsed data from Blood Pressure Feature characteristic."""
29 features_bitmap: int
30 body_movement_detection_support: bool
31 cuff_fit_detection_support: bool
32 irregular_pulse_detection_support: bool
33 pulse_rate_range_detection_support: bool
34 measurement_position_detection_support: bool
35 multiple_bond_support: bool
38class BloodPressureFeatureCharacteristic(BaseCharacteristic):
39 """Blood Pressure Feature characteristic (0x2A49).
41 Used to expose the supported features of a blood pressure monitoring
42 device. Indicates which optional measurements and capabilities are
43 available.
44 """
46 _manual_value_type: ValueType | str | None = ValueType.DICT # Override since decode_value returns dataclass
48 def decode_value(self, data: bytearray, ctx: CharacteristicContext | None = None) -> BloodPressureFeatureData:
49 """Parse blood pressure feature data according to Bluetooth specification.
51 Format: Features(2) - 16-bit bitmap indicating supported features.
53 Args:
54 data: Raw bytearray from BLE characteristic.
55 ctx: Optional CharacteristicContext providing surrounding context (may be None).
57 Returns:
58 BloodPressureFeatureData containing parsed feature bitmap and capabilities.
60 """
61 if len(data) < 2:
62 raise ValueError("Blood Pressure Feature data must be at least 2 bytes")
64 features_bitmap = DataParser.parse_int16(data, 0, signed=False)
66 body_movement_detection = bool(features_bitmap & BloodPressureFeatures.BODY_MOVEMENT_DETECTION)
67 cuff_fit_detection = bool(features_bitmap & BloodPressureFeatures.CUFF_FIT_DETECTION)
68 irregular_pulse_detection = bool(features_bitmap & BloodPressureFeatures.IRREGULAR_PULSE_DETECTION)
69 pulse_rate_range_detection = bool(features_bitmap & BloodPressureFeatures.PULSE_RATE_RANGE_DETECTION)
70 measurement_position_detection = bool(features_bitmap & BloodPressureFeatures.MEASUREMENT_POSITION_DETECTION)
71 multiple_bond_support = bool(features_bitmap & BloodPressureFeatures.MULTIPLE_BOND_SUPPORT)
73 return BloodPressureFeatureData(
74 features_bitmap=features_bitmap,
75 body_movement_detection_support=body_movement_detection,
76 cuff_fit_detection_support=cuff_fit_detection,
77 irregular_pulse_detection_support=irregular_pulse_detection,
78 pulse_rate_range_detection_support=pulse_rate_range_detection,
79 measurement_position_detection_support=measurement_position_detection,
80 multiple_bond_support=multiple_bond_support,
81 )
83 def encode_value(self, data: BloodPressureFeatureData) -> bytearray:
84 """Encode BloodPressureFeatureData back to bytes.
86 Args:
87 data: BloodPressureFeatureData instance to encode
89 Returns:
90 Encoded bytes representing the blood pressure features
92 """
93 return DataParser.encode_int16(data.features_bitmap, signed=False)