Coverage for src / bluetooth_sig / gatt / characteristics / idd_history_data.py: 100%
61 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"""IDD History Data characteristic (0x2B28).
3Contains historical event data from the Insulin Delivery Device.
5References:
6 Bluetooth SIG Insulin Delivery Service 1.0
7"""
9from __future__ import annotations
11from enum import IntEnum
13import msgspec
15from ..context import CharacteristicContext
16from .base import BaseCharacteristic
17from .utils import DataParser
20class IDDHistoryEventType(IntEnum):
21 """IDD history event types (Table 4.95, Hamming codes)."""
23 REFERENCE_TIME = 0x000F
24 REFERENCE_TIME_BASE_OFFSET = 0x0033
25 BOLUS_CALCULATED_PART_1 = 0x003C
26 BOLUS_CALCULATED_PART_2 = 0x0055
27 BOLUS_PROGRAMMED_PART_1 = 0x005A
28 BOLUS_PROGRAMMED_PART_2 = 0x0066
29 BOLUS_DELIVERED_PART_1 = 0x0069
30 BOLUS_DELIVERED_PART_2 = 0x0096
31 DELIVERED_BASAL_RATE_CHANGED = 0x0099
32 TBR_ADJUSTMENT_STARTED = 0x00A5
33 TBR_ADJUSTMENT_ENDED = 0x00AA
34 TBR_ADJUSTMENT_CHANGED = 0x00C3
35 PROFILE_TEMPLATE_ACTIVATED = 0x00CC
36 BASAL_RATE_PROFILE_TEMPLATE_TIME_BLOCK_CHANGED = 0x00F0
37 TOTAL_DAILY_INSULIN_DELIVERY = 0x00FF
38 THERAPY_CONTROL_STATE_CHANGED = 0x0303
39 OPERATIONAL_STATE_CHANGED = 0x030C
40 RESERVOIR_REMAINING_AMOUNT_CHANGED = 0x0330
41 ANNUNCIATION_STATUS_CHANGED_PART_1 = 0x033F
42 ANNUNCIATION_STATUS_CHANGED_PART_2 = 0x0356
43 ISF_PROFILE_TEMPLATE_TIME_BLOCK_CHANGED = 0x0359
44 I2CHO_RATIO_PROFILE_TEMPLATE_TIME_BLOCK_CHANGED = 0x0365
45 TARGET_GLUCOSE_RANGE_PROFILE_TEMPLATE_TIME_BLOCK_CHANGED = 0x036A
46 PRIMING_STARTED = 0x0395
47 PRIMING_DONE = 0x039A
48 DATA_CORRUPTION = 0x03A6
49 POINTER_EVENT = 0x03A9
50 BOLUS_TEMPLATE_CHANGED_PART_1 = 0x03C0
51 BOLUS_TEMPLATE_CHANGED_PART_2 = 0x03CF
52 TBR_TEMPLATE_CHANGED = 0x03F3
53 MAX_BOLUS_AMOUNT_CHANGED = 0x03FC
54 MANUFACTURER_RESERVED_START = 0xF000
55 MANUFACTURER_RESERVED_END = 0xFFF0
58class IDDHistoryDataPayload(msgspec.Struct, frozen=True, kw_only=True):
59 """Parsed data from IDD History Data characteristic.
61 Attributes:
62 event_type: Type of the history event (uint16).
63 sequence_number: Sequence number of this history event (uint32).
64 relative_offset: Relative time offset in seconds (uint16).
65 event_data: Raw event-specific data bytes.
67 """
69 event_type: IDDHistoryEventType
70 sequence_number: int
71 relative_offset: int
72 event_data: bytes = b""
75class IDDHistoryDataCharacteristic(BaseCharacteristic[IDDHistoryDataPayload]):
76 """IDD History Data characteristic (0x2B28).
78 org.bluetooth.characteristic.idd_history_data
80 Contains historical event data from the Insulin Delivery Device.
81 """
83 min_length = 8 # event_type(2) + sequence_number(4) + relative_offset(2)
84 allow_variable_length = True
86 def _decode_value(
87 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
88 ) -> IDDHistoryDataPayload:
89 """Parse IDD History Data.
91 Format: EventType (uint16 LE) + SequenceNumber (uint32 LE) + RelativeOffset (uint16 LE) + EventData (variable).
92 """
93 event_type = IDDHistoryEventType(DataParser.parse_int16(data, 0, signed=False))
94 sequence_number = DataParser.parse_int32(data, 2, signed=False)
95 relative_offset = DataParser.parse_int16(data, 6, signed=False)
96 event_data = bytes(data[8:])
98 return IDDHistoryDataPayload(
99 event_type=event_type,
100 sequence_number=sequence_number,
101 relative_offset=relative_offset,
102 event_data=event_data,
103 )
105 def _encode_value(self, data: IDDHistoryDataPayload) -> bytearray:
106 """Encode IDD History Data."""
107 result = bytearray()
108 result.extend(DataParser.encode_int16(int(data.event_type), signed=False))
109 result.extend(DataParser.encode_int32(data.sequence_number, signed=False))
110 result.extend(DataParser.encode_int16(data.relative_offset, signed=False))
111 result.extend(data.event_data)
112 return result