Coverage for src / bluetooth_sig / gatt / characteristics / acceleration_3d.py: 100%

23 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-18 11:17 +0000

1"""Acceleration - 3D characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from ..context import CharacteristicContext 

6from .base import BaseCharacteristic 

7from .templates import VectorData 

8from .utils import DataParser 

9 

10 

11class Acceleration3DCharacteristic(BaseCharacteristic[VectorData]): 

12 """Acceleration - 3D characteristic (0x2C1D). 

13 

14 org.bluetooth.characteristic.acceleration_3d 

15 

16 The Acceleration - 3D characteristic represents a measure of acceleration with a limited range. 

17 """ 

18 

19 _characteristic_name: str | None = "Acceleration 3D" 

20 resolution: float = 0.01 

21 

22 # BaseCharacteristic handles validation 

23 expected_length = 3 

24 

25 def _decode_value( 

26 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True 

27 ) -> VectorData: 

28 """Parse 3D acceleration (3 x sint8). 

29 

30 Args: 

31 data: Raw bytearray from BLE characteristic (3 bytes, validated by base class). 

32 ctx: Optional CharacteristicContext. 

33 validate: Whether to validate ranges (default True) 

34 

35 Returns: 

36 VectorData with x, y, z axis values in gₙ (standard acceleration due to gravity). 

37 """ 

38 x_raw = DataParser.parse_int8(data, 0, signed=True) 

39 y_raw = DataParser.parse_int8(data, 1, signed=True) 

40 z_raw = DataParser.parse_int8(data, 2, signed=True) 

41 

42 return VectorData( 

43 x_axis=x_raw * self.resolution, 

44 y_axis=y_raw * self.resolution, 

45 z_axis=z_raw * self.resolution, 

46 ) 

47 

48 def _encode_value(self, data: VectorData) -> bytearray: 

49 """Encode 3D acceleration. 

50 

51 Args: 

52 data: VectorData with x, y, z axis values in gₙ. 

53 

54 Returns: 

55 Encoded bytes (3 bytes) 

56 """ 

57 x_raw = int(data.x_axis / self.resolution) 

58 y_raw = int(data.y_axis / self.resolution) 

59 z_raw = int(data.z_axis / self.resolution) 

60 

61 result = bytearray() 

62 result.extend(DataParser.encode_int8(x_raw, signed=True)) 

63 result.extend(DataParser.encode_int8(y_raw, signed=True)) 

64 result.extend(DataParser.encode_int8(z_raw, signed=True)) 

65 return result