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

29 statements  

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

1"""Descriptor Value Changed characteristic (0x2A7D).""" 

2 

3from __future__ import annotations 

4 

5from enum import IntFlag 

6 

7import msgspec 

8 

9from ...types.uuid import BluetoothUUID 

10from ..context import CharacteristicContext 

11from .base import BaseCharacteristic 

12from .utils import DataParser 

13 

14 

15class DescriptorValueChangedFlags(IntFlag): 

16 """Descriptor Value Changed flags.""" 

17 

18 SOURCE_OF_CHANGE_DEVICE = 0x0001 

19 SOURCE_OF_CHANGE_EXTERNAL = 0x0002 

20 

21 

22class DescriptorValueChangedData(msgspec.Struct, frozen=True, kw_only=True): 

23 """Parsed data from Descriptor Value Changed characteristic.""" 

24 

25 flags: DescriptorValueChangedFlags 

26 characteristic_uuid: BluetoothUUID 

27 value: bytes 

28 

29 

30_ADDITIONAL_DATA_START_OFFSET = 4 

31 

32 

33class DescriptorValueChangedCharacteristic(BaseCharacteristic[DescriptorValueChangedData]): 

34 """Descriptor Value Changed characteristic (0x2A7D). 

35 

36 org.bluetooth.characteristic.descriptor_value_changed 

37 

38 Indicates that a descriptor value has changed. Contains flags, 

39 the UUID of the changed characteristic, and the new value. 

40 """ 

41 

42 min_length = 4 

43 allow_variable_length = True 

44 

45 def _decode_value( 

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

47 ) -> DescriptorValueChangedData: 

48 flags = DescriptorValueChangedFlags(DataParser.parse_int16(data, 0, signed=False)) 

49 characteristic_uuid = BluetoothUUID(DataParser.parse_int16(data, 2, signed=False)) 

50 value = bytes(data[_ADDITIONAL_DATA_START_OFFSET:]) if len(data) > _ADDITIONAL_DATA_START_OFFSET else b"" 

51 

52 return DescriptorValueChangedData( 

53 flags=flags, 

54 characteristic_uuid=characteristic_uuid, 

55 value=value, 

56 ) 

57 

58 def _encode_value(self, data: DescriptorValueChangedData) -> bytearray: 

59 result = bytearray() 

60 result.extend(DataParser.encode_int16(int(data.flags), signed=False)) 

61 result.extend(DataParser.encode_int16(int(data.characteristic_uuid.short_form, 16), signed=False)) 

62 result.extend(data.value) 

63 return result