1 """Manage allocation of instance ID's.
3 HomeKit needs to allocate unique numbers to each accessory. These need to
4 be stable between reboots and upgrades.
6 This module generates and stores them in a HA storage.
9 from __future__
import annotations
13 from pyhap.util
import uuid_to_hap_type
18 from .util
import get_iid_storage_filename_for_entry_id
20 IID_MANAGER_STORAGE_VERSION = 2
21 IID_MANAGER_SAVE_DELAY = 2
23 ALLOCATIONS_KEY =
"allocations"
26 IID_MAX = 18446744073709551615
29 ACCESSORY_INFORMATION_SERVICE =
"3E"
33 """Storage class for IIDManager."""
37 old_major_version: int,
38 old_minor_version: int,
41 """Migrate to the new version."""
42 if old_major_version == 1:
46 old_allocations: dict[str, int] = old_data.pop(ALLOCATIONS_KEY, {})
47 new_allocation: dict[str, dict[str, int]] = {}
48 old_data[ALLOCATIONS_KEY] = new_allocation
49 for allocation_key, iid
in old_allocations.items():
50 aid_str, new_allocation_key = allocation_key.split(
"_", 1)
51 service_type, _, char_type, *_ = new_allocation_key.split(
"_")
52 accessory_allocation = new_allocation.setdefault(aid_str, {})
53 if service_type == ACCESSORY_INFORMATION_SERVICE
and not char_type:
54 accessory_allocation[new_allocation_key] = 1
56 accessory_allocation[new_allocation_key] = iid
60 raise NotImplementedError
64 """Provide stable allocation of IIDs for the lifetime of an accessory.
66 Will generate new ID's, ensure they are unique and store them to make sure they
70 def __init__(self, hass: HomeAssistant, entry_id: str) ->
None:
71 """Create a new iid store."""
73 self.
allocationsallocations: dict[str, dict[str, int]] = {}
74 self.allocated_iids: dict[str, list[int]] = {}
76 self.
storestore: IIDStorage |
None =
None
79 """Load the latest IID data."""
80 iid_store = get_iid_storage_filename_for_entry_id(self.
entry_identry_id)
87 assert isinstance(raw_storage, dict)
88 self.
allocationsallocations = raw_storage.get(ALLOCATIONS_KEY, {})
89 for aid_str, allocations
in self.
allocationsallocations.items():
90 self.allocated_iids[aid_str] = sorted(allocations.values())
96 service_unique_id: str |
None,
97 char_uuid: UUID |
None,
98 char_unique_id: str |
None,
100 """Generate a stable iid."""
101 service_hap_type: str = uuid_to_hap_type(service_uuid)
102 char_hap_type: str |
None = uuid_to_hap_type(char_uuid)
if char_uuid
else None
105 f
'{service_hap_type}_{service_unique_id or ""}_'
106 f
'{char_hap_type or ""}_{char_unique_id or ""}'
110 accessory_allocation = self.
allocationsallocations.setdefault(aid_str, {})
111 accessory_allocated_iids = self.allocated_iids.setdefault(aid_str, [1])
112 if service_hap_type == ACCESSORY_INFORMATION_SERVICE
and char_uuid
is None:
114 if allocation_key
in accessory_allocation:
115 return accessory_allocation[allocation_key]
116 if accessory_allocated_iids:
117 allocated_iid = accessory_allocated_iids[-1] + 1
120 accessory_allocation[allocation_key] = allocated_iid
121 accessory_allocated_iids.append(allocated_iid)
127 """Schedule saving the iid allocations."""
128 assert self.
storestore
is not None
132 """Save the iid allocations."""
133 assert self.
storestore
is not None
138 """Return data of entity map to store in a file."""
139 return {ALLOCATIONS_KEY: self.
allocationsallocations}
None _async_schedule_save(self)
None async_initialize(self)
None __init__(self, HomeAssistant hass, str entry_id)
int get_or_allocate_iid(self, int aid, UUID service_uuid, str|None service_unique_id, UUID|None char_uuid, str|None char_unique_id)
dict[str, dict[str, dict[str, int]]] _data_to_save(self)
dict _async_migrate_func(self, int old_major_version, int old_minor_version, dict old_data)
None async_load(HomeAssistant hass)
None async_delay_save(self, Callable[[], _T] data_func, float delay=0)