Coverage for src / bluetooth_sig / gatt / characteristics / object_changed.py: 100%
29 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
1"""Object Changed characteristic implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ...types.gatt_enums import CharacteristicRole
10from ..context import CharacteristicContext
11from .base import BaseCharacteristic
12from .utils import DataParser
15class ObjectChangedFlags(IntFlag):
16 """Object Changed flags per OTS specification."""
18 SOURCE_OF_CHANGE = 0x01
19 CHANGE_OCCURRED = 0x02
20 OBJECT_CONTENTS_CHANGED = 0x04
21 OBJECT_METADATA_CHANGED = 0x08
22 OBJECT_CREATION = 0x10
23 OBJECT_DELETION = 0x20
26class ObjectChangedData(msgspec.Struct, frozen=True, kw_only=True):
27 """Parsed data from Object Changed characteristic.
29 Attributes:
30 flags: Change flags indicating what changed.
31 object_id: 48-bit object identifier.
33 """
35 flags: ObjectChangedFlags
36 object_id: int
39class ObjectChangedCharacteristic(BaseCharacteristic[ObjectChangedData]):
40 """Object Changed characteristic (0x2AC8).
42 org.bluetooth.characteristic.object_changed
44 Notification-only characteristic indicating changes to objects in
45 the Object Transfer Service (OTS). Contains flags describing the
46 change and the 48-bit object ID of the affected object.
47 """
49 _manual_role = CharacteristicRole.STATUS
50 expected_length: int = 7 # flags(1) + object_id(6)
51 min_length: int = 7
53 def _decode_value(
54 self,
55 data: bytearray,
56 ctx: CharacteristicContext | None = None,
57 *,
58 validate: bool = True,
59 ) -> ObjectChangedData:
60 """Parse object changed data.
62 Args:
63 data: Raw bytes (7 bytes).
64 ctx: Optional CharacteristicContext.
65 validate: Whether to validate ranges (default True).
67 Returns:
68 ObjectChangedData with flags and object_id.
70 """
71 flags = ObjectChangedFlags(DataParser.parse_int8(data, 0, signed=False))
72 object_id = DataParser.parse_int48(data, 1, signed=False)
73 return ObjectChangedData(flags=flags, object_id=object_id)
75 def _encode_value(self, data: ObjectChangedData) -> bytearray:
76 """Encode object changed data to bytes.
78 Args:
79 data: ObjectChangedData to encode.
81 Returns:
82 Encoded bytes (7 bytes).
84 """
85 result = DataParser.encode_int8(int(data.flags), signed=False)
86 result.extend(DataParser.encode_int48(data.object_id, signed=False))
87 return result