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

29 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-03 16:41 +0000

1"""Object Changed characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from enum import IntFlag 

6 

7import msgspec 

8 

9from ...types.gatt_enums import CharacteristicRole 

10from ..context import CharacteristicContext 

11from .base import BaseCharacteristic 

12from .utils import DataParser 

13 

14 

15class ObjectChangedFlags(IntFlag): 

16 """Object Changed flags per OTS specification.""" 

17 

18 SOURCE_OF_CHANGE = 0x01 

19 CHANGE_OCCURRED = 0x02 

20 OBJECT_CONTENTS_CHANGED = 0x04 

21 OBJECT_METADATA_CHANGED = 0x08 

22 OBJECT_CREATION = 0x10 

23 OBJECT_DELETION = 0x20 

24 

25 

26class ObjectChangedData(msgspec.Struct, frozen=True, kw_only=True): 

27 """Parsed data from Object Changed characteristic. 

28 

29 Attributes: 

30 flags: Change flags indicating what changed. 

31 object_id: 48-bit object identifier. 

32 

33 """ 

34 

35 flags: ObjectChangedFlags 

36 object_id: int 

37 

38 

39class ObjectChangedCharacteristic(BaseCharacteristic[ObjectChangedData]): 

40 """Object Changed characteristic (0x2AC8). 

41 

42 org.bluetooth.characteristic.object_changed 

43 

44 Notification-only characteristic indicating changes to objects in 

45 the Object Transfer Service (OTS). Contains flags describing the 

46 change and the 48-bit object ID of the affected object. 

47 """ 

48 

49 _manual_role = CharacteristicRole.STATUS 

50 expected_length: int = 7 # flags(1) + object_id(6) 

51 min_length: int = 7 

52 

53 def _decode_value( 

54 self, 

55 data: bytearray, 

56 ctx: CharacteristicContext | None = None, 

57 *, 

58 validate: bool = True, 

59 ) -> ObjectChangedData: 

60 """Parse object changed data. 

61 

62 Args: 

63 data: Raw bytes (7 bytes). 

64 ctx: Optional CharacteristicContext. 

65 validate: Whether to validate ranges (default True). 

66 

67 Returns: 

68 ObjectChangedData with flags and object_id. 

69 

70 """ 

71 flags = ObjectChangedFlags(DataParser.parse_int8(data, 0, signed=False)) 

72 object_id = DataParser.parse_int48(data, 1, signed=False) 

73 return ObjectChangedData(flags=flags, object_id=object_id) 

74 

75 def _encode_value(self, data: ObjectChangedData) -> bytearray: 

76 """Encode object changed data to bytes. 

77 

78 Args: 

79 data: ObjectChangedData to encode. 

80 

81 Returns: 

82 Encoded bytes (7 bytes). 

83 

84 """ 

85 result = DataParser.encode_int8(int(data.flags), signed=False) 

86 result.extend(DataParser.encode_int48(data.object_id, signed=False)) 

87 return result