Coverage for src/bluetooth_sig/gatt/descriptors/environmental_sensing_measurement.py: 71%
34 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"""Environmental Sensing Measurement Descriptor implementation."""
3from __future__ import annotations
5import msgspec
7from ..characteristics.utils import DataParser
8from .base import BaseDescriptor
11class EnvironmentalSensingMeasurementData(msgspec.Struct, frozen=True, kw_only=True):
12 """Environmental Sensing Measurement descriptor data."""
14 sampling_function: int
15 measurement_period: int
16 update_interval: int
17 application: int
18 measurement_uncertainty: int
21class EnvironmentalSensingMeasurementDescriptor(BaseDescriptor):
22 """Environmental Sensing Measurement Descriptor (0x290C).
24 Contains measurement parameters for environmental sensors.
25 Includes sampling function, measurement period, and other parameters.
26 """
28 def _has_structured_data(self) -> bool:
29 return True
31 def _get_data_format(self) -> str:
32 return "struct"
34 def _parse_descriptor_value(self, data: bytes) -> EnvironmentalSensingMeasurementData:
35 """Parse Environmental Sensing Measurement value.
37 Format: 12 bytes
38 - Sampling Function (3 bytes, uint24) - using uint32 for simplicity
39 - Measurement Period (3 bytes, uint24) - using uint32 for simplicity
40 - Update Interval (3 bytes, uint24) - using uint32 for simplicity
41 - Application (1 byte)
42 - Measurement Uncertainty (2 bytes, uint16)
44 Args:
45 data: Raw bytes (should be 12 bytes)
47 Returns:
48 EnvironmentalSensingMeasurementData with measurement parameters
50 Raises:
51 ValueError: If data is not exactly 12 bytes
52 """
53 if len(data) != 12:
54 raise ValueError(f"Environmental Sensing Measurement data must be exactly 12 bytes, got {len(data)}")
56 # For simplicity, treat uint24 values as uint32 (they'll fit)
57 return EnvironmentalSensingMeasurementData(
58 sampling_function=DataParser.parse_int32(data, offset=0, endian="little") & 0xFFFFFF,
59 measurement_period=DataParser.parse_int32(data, offset=3, endian="little") & 0xFFFFFF,
60 update_interval=DataParser.parse_int32(data, offset=6, endian="little") & 0xFFFFFF,
61 application=DataParser.parse_int8(data, offset=9),
62 measurement_uncertainty=DataParser.parse_int16(data, offset=10, endian="little"),
63 )
65 def get_sampling_function(self, data: bytes) -> int:
66 """Get the sampling function."""
67 parsed = self._parse_descriptor_value(data)
68 return parsed.sampling_function
70 def get_measurement_period(self, data: bytes) -> int:
71 """Get the measurement period."""
72 parsed = self._parse_descriptor_value(data)
73 return parsed.measurement_period
75 def get_update_interval(self, data: bytes) -> int:
76 """Get the update interval."""
77 parsed = self._parse_descriptor_value(data)
78 return parsed.update_interval
80 def get_application(self, data: bytes) -> int:
81 """Get the application identifier."""
82 parsed = self._parse_descriptor_value(data)
83 return parsed.application
85 def get_measurement_uncertainty(self, data: bytes) -> int:
86 """Get the measurement uncertainty."""
87 parsed = self._parse_descriptor_value(data)
88 return parsed.measurement_uncertainty