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

22 statements  

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

1"""Unread Alert Status characteristic (0x2A45) implementation. 

2 

3Represents the number of unread alerts in a specific category. 

4Used by Alert Notification Service (0x1811). 

5 

6Based on Bluetooth SIG GATT Specification: 

7- Unread Alert Status: 2 bytes (Category ID + Unread Count) 

8""" 

9 

10from __future__ import annotations 

11 

12import msgspec 

13 

14from ...types import AlertCategoryID 

15from ..context import CharacteristicContext 

16from .base import BaseCharacteristic 

17from .utils import DataParser 

18 

19 

20class UnreadAlertStatusData(msgspec.Struct): 

21 """Unread Alert Status characteristic data structure.""" 

22 

23 category_id: AlertCategoryID 

24 unread_count: int # 0-254, 255 means >254 

25 

26 

27class UnreadAlertStatusCharacteristic(BaseCharacteristic[UnreadAlertStatusData]): 

28 """Unread Alert Status characteristic (0x2A45). 

29 

30 Represents the number of unread alerts in a specific category. 

31 

32 Structure (2 bytes): 

33 - Category ID: uint8 (0=Simple Alert, 1=Email, etc.) 

34 - Unread Count: uint8 (0-254, 255 means more than 254 unread alerts) 

35 

36 Used by Alert Notification Service (0x1811). 

37 """ 

38 

39 expected_length: int | None = 2 

40 

41 def _decode_value( 

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

43 ) -> UnreadAlertStatusData: 

44 """Decode Unread Alert Status data from bytes. 

45 

46 Args: 

47 data: Raw characteristic data (2 bytes) 

48 ctx: Optional characteristic context 

49 validate: Whether to validate ranges (default True) 

50 

51 Returns: 

52 UnreadAlertStatusData with all fields 

53 

54 Raises: 

55 ValueError: If data contains invalid values 

56 

57 """ 

58 # Parse Category ID (1 byte) 

59 category_id_raw = DataParser.parse_int8(data, 0, signed=False) 

60 category_id = AlertCategoryID(category_id_raw) 

61 

62 # Parse Unread Count (1 byte) 

63 unread_count = DataParser.parse_int8(data, 1, signed=False) 

64 

65 return UnreadAlertStatusData( 

66 category_id=category_id, 

67 unread_count=unread_count, 

68 ) 

69 

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

71 """Encode Unread Alert Status data to bytes. 

72 

73 Args: 

74 data: UnreadAlertStatusData to encode 

75 

76 Returns: 

77 Encoded unread alert status (2 bytes) 

78 

79 Raises: 

80 ValueError: If data contains invalid values 

81 

82 """ 

83 result = bytearray() 

84 

85 # Encode Category ID (1 byte) 

86 category_id_value = int(data.category_id) 

87 result.append(category_id_value) 

88 

89 # Encode Unread Count (1 byte) 

90 result.append(data.unread_count) 

91 

92 return result