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

19 statements  

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

1"""Volume Offset State characteristic (0x2B80).""" 

2 

3from __future__ import annotations 

4 

5import msgspec 

6 

7from ..context import CharacteristicContext 

8from .base import BaseCharacteristic 

9from .utils import DataParser 

10 

11 

12class VolumeOffsetStateData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods 

13 """Parsed data from Volume Offset State characteristic. 

14 

15 Contains the volume offset and change counter. 

16 """ 

17 

18 volume_offset: int 

19 change_counter: int 

20 

21 

22class VolumeOffsetStateCharacteristic(BaseCharacteristic[VolumeOffsetStateData]): 

23 """Volume Offset State characteristic (0x2B80). 

24 

25 org.bluetooth.characteristic.volume_offset_state 

26 

27 Reports the current volume offset and change counter 

28 for the Volume Offset Control Service. 

29 """ 

30 

31 expected_length = 3 

32 

33 def _decode_value( 

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

35 ) -> VolumeOffsetStateData: 

36 """Parse Volume Offset State data. 

37 

38 Format: volume_offset (sint16 LE) + change_counter (uint8). 

39 """ 

40 volume_offset = DataParser.parse_int16(data, 0, signed=True) 

41 change_counter = DataParser.parse_int8(data, 2, signed=False) 

42 return VolumeOffsetStateData( 

43 volume_offset=volume_offset, 

44 change_counter=change_counter, 

45 ) 

46 

47 def _encode_value(self, data: VolumeOffsetStateData) -> bytearray: 

48 """Encode Volume Offset State data to bytes.""" 

49 result = bytearray() 

50 result += DataParser.encode_int16(data.volume_offset, signed=True) 

51 result += DataParser.encode_int8(data.change_counter) 

52 return result