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

37 statements  

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

1"""ESL Image Information characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from enum import IntEnum 

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 ESLImageType(IntEnum): 

16 """ESL image type identifiers per ESL Service spec.""" 

17 

18 BLACK_WHITE = 0x00 

19 THREE_GRAY_SCALE = 0x01 

20 FOUR_GRAY_SCALE = 0x02 

21 EIGHT_GRAY_SCALE = 0x03 

22 SIXTEEN_GRAY_SCALE = 0x04 

23 RED_BLACK_WHITE = 0x05 

24 YELLOW_BLACK_WHITE = 0x06 

25 FULL_COLOR = 0x07 

26 

27 

28class ESLImageInformationData(msgspec.Struct, frozen=True, kw_only=True): 

29 """Parsed data from ESL Image Information characteristic. 

30 

31 Attributes: 

32 image_index: Index of the image slot (0-based). 

33 max_width: Maximum image width in pixels. 

34 max_height: Maximum image height in pixels. 

35 image_type: Image type identifier (codec/format). 

36 

37 """ 

38 

39 image_index: int 

40 max_width: int 

41 max_height: int 

42 image_type: ESLImageType 

43 

44 

45class ESLImageInformationCharacteristic(BaseCharacteristic[ESLImageInformationData]): 

46 """ESL Image Information characteristic (0x2BFB). 

47 

48 org.bluetooth.characteristic.esl_image_information 

49 

50 Describes an ESL image slot: index, maximum width, maximum height, 

51 and image type. 

52 """ 

53 

54 _manual_role = CharacteristicRole.INFO 

55 expected_length: int = 6 # image_index(1) + max_width(2) + max_height(2) + image_type(1) 

56 min_length: int = 6 

57 

58 def _decode_value( 

59 self, 

60 data: bytearray, 

61 ctx: CharacteristicContext | None = None, 

62 *, 

63 validate: bool = True, 

64 ) -> ESLImageInformationData: 

65 """Parse ESL image information. 

66 

67 Args: 

68 data: Raw bytes (6 bytes). 

69 ctx: Optional CharacteristicContext. 

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

71 

72 Returns: 

73 ESLImageInformationData with image slot details. 

74 

75 """ 

76 image_index = DataParser.parse_int8(data, 0, signed=False) 

77 max_width = DataParser.parse_int16(data, 1, signed=False) 

78 max_height = DataParser.parse_int16(data, 3, signed=False) 

79 image_type = DataParser.parse_int8(data, 5, signed=False) 

80 return ESLImageInformationData( 

81 image_index=image_index, 

82 max_width=max_width, 

83 max_height=max_height, 

84 image_type=ESLImageType(image_type), 

85 ) 

86 

87 def _encode_value(self, data: ESLImageInformationData) -> bytearray: 

88 """Encode ESL image information to bytes. 

89 

90 Args: 

91 data: ESLImageInformationData to encode. 

92 

93 Returns: 

94 Encoded bytes (6 bytes). 

95 

96 """ 

97 result = DataParser.encode_int8(data.image_index, signed=False) 

98 result.extend(DataParser.encode_int16(data.max_width, signed=False)) 

99 result.extend(DataParser.encode_int16(data.max_height, signed=False)) 

100 result.extend(DataParser.encode_int8(int(data.image_type), signed=False)) 

101 return result