Coverage for src / bluetooth_sig / gatt / characteristics / alert_status.py: 57%

30 statements  

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

1"""Alert Status characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5import msgspec 

6 

7from ..context import CharacteristicContext 

8from .base import BaseCharacteristic 

9from .utils import DataParser 

10 

11 

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

13 """Parsed data from Alert Status characteristic.""" 

14 

15 ringer_state: bool 

16 vibrate_state: bool 

17 display_alert_status: bool 

18 

19 

20class AlertStatusCharacteristic(BaseCharacteristic[AlertStatusData]): 

21 """Alert Status characteristic (0x2A3F). 

22 

23 org.bluetooth.characteristic.alert_status 

24 

25 The Alert Status characteristic defines the Status of alert. 

26 Bit 0: Ringer State (0=not active, 1=active) 

27 Bit 1: Vibrate State (0=not active, 1=active) 

28 Bit 2: Display Alert Status (0=not active, 1=active) 

29 Bits 3-7: Reserved for future use 

30 """ 

31 

32 expected_length: int = 1 

33 min_length: int = 1 

34 

35 # Bit masks for alert status flags 

36 RINGER_STATE_MASK = 0x01 # Bit 0 

37 VIBRATE_STATE_MASK = 0x02 # Bit 1 

38 DISPLAY_ALERT_STATUS_MASK = 0x04 # Bit 2 

39 

40 def _decode_value( 

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

42 ) -> AlertStatusData: 

43 """Parse alert status data according to Bluetooth specification. 

44 

45 Args: 

46 data: Raw bytearray from BLE characteristic. 

47 ctx: Optional CharacteristicContext (unused) 

48 validate: Whether to validate ranges (default True) 

49 

50 Returns: 

51 AlertStatusData containing parsed alert status flags. 

52 

53 Raises: 

54 ValueError: If data format is invalid. 

55 

56 """ 

57 status_byte = DataParser.parse_int8(data, 0, signed=False) 

58 

59 # Extract bit fields according to specification 

60 ringer_state = bool(status_byte & self.RINGER_STATE_MASK) 

61 vibrate_state = bool(status_byte & self.VIBRATE_STATE_MASK) 

62 display_alert_status = bool(status_byte & self.DISPLAY_ALERT_STATUS_MASK) 

63 

64 return AlertStatusData( 

65 ringer_state=ringer_state, 

66 vibrate_state=vibrate_state, 

67 display_alert_status=display_alert_status, 

68 ) 

69 

70 def _encode_value(self, data: AlertStatusData) -> bytearray: 

71 """Encode AlertStatusData back to bytes. 

72 

73 Args: 

74 data: AlertStatusData instance to encode 

75 

76 Returns: 

77 Encoded bytes representing the alert status 

78 

79 """ 

80 status_byte = 0 

81 if data.ringer_state: 

82 status_byte |= self.RINGER_STATE_MASK 

83 if data.vibrate_state: 

84 status_byte |= self.VIBRATE_STATE_MASK 

85 if data.display_alert_status: 

86 status_byte |= self.DISPLAY_ALERT_STATUS_MASK 

87 

88 return bytearray([status_byte])