1 """Manage allocation of accessory ID's.
3 HomeKit needs to allocate unique numbers to each accessory. These need to
4 be stable between reboots and upgrades.
6 Using a hash function to generate them means collisions. It also means you
7 can't change the hash without causing breakages for HA users.
9 This module generates and stores them in a HA storage.
12 from __future__
import annotations
14 from collections.abc
import Generator
17 from fnv_hash_fast
import fnv1a_32
23 from .util
import get_aid_storage_filename_for_entry_id
25 AID_MANAGER_STORAGE_VERSION = 1
26 AID_MANAGER_SAVE_DELAY = 2
28 ALLOCATIONS_KEY =
"allocations"
29 UNIQUE_IDS_KEY =
"unique_ids"
34 AID_MAX = 18446744073709551615
38 """Determine the system wide unique_id for an entity."""
39 return f
"{entity.platform}.{entity.domain}.{entity_unique_id}"
43 """Generate accessory aid."""
49 yield fnv1a_32(unique_id.encode(
"utf-8"))
53 yield fnv1a_32(entity_id.encode(
"utf-8"))
59 yield random.randrange(AID_MIN, AID_MAX)
63 """Holds a map of entity ID to HomeKit ID.
65 Will generate new ID's, ensure they are unique and store them to make sure they
69 def __init__(self, hass: HomeAssistant, entry_id: str) ->
None:
70 """Create a new entity map store."""
75 self.
storestore: Store |
None =
None
79 """Load the latest AID data."""
80 aidstore = get_aid_storage_filename_for_entry_id(self.
_entry_id_entry_id)
81 self.
storestore =
Store(self.
hasshass, AID_MANAGER_STORAGE_VERSION, aidstore)
86 assert isinstance(raw_storage, dict)
87 self.
allocationsallocations = raw_storage.get(ALLOCATIONS_KEY, {})
91 """Generate a stable aid for an entity id."""
100 self, sys_unique_id: str, entry: er.RegistryEntry
102 """Migrate the unique id aid assignment if its changed."""
103 if sys_unique_id
in self.
allocationsallocations
or not (
104 previous_unique_id := entry.previous_unique_id
108 if aid := self.
allocationsallocations.pop(old_sys_unique_id,
None):
113 """Allocate (and return) a new aid for an accessory."""
114 if unique_id
and unique_id
in self.
allocationsallocations:
120 if aid
in INVALID_AIDS:
124 storage_key = unique_id
or entity_id
131 f
"Unable to generate unique aid allocation for {entity_id} [{unique_id}]"
135 """Delete an aid allocation."""
145 """Schedule saving the entity map cache."""
146 assert self.
storestore
is not None
150 """Save the entity map cache."""
151 assert self.
storestore
is not None
156 """Return data of entity map to store in a file."""
157 return {ALLOCATIONS_KEY: self.
allocationsallocations}
int get_or_allocate_aid_for_entity_id(self, str entity_id)
None async_schedule_save(self)
int get_or_allocate_aid(self, str|None unique_id, str entity_id)
None delete_aid(self, str storage_key)
dict[str, dict[str, int]] _data_to_save(self)
None async_initialize(self)
None __init__(self, HomeAssistant hass, str entry_id)
None _migrate_unique_id_aid_assignment_if_needed(self, str sys_unique_id, er.RegistryEntry entry)
bool add(self, _T matcher)
Generator[int] _generate_aids(str|None unique_id, str entity_id)
str get_system_unique_id(er.RegistryEntry entity, str entity_unique_id)
None async_load(HomeAssistant hass)
AreaRegistry async_get(HomeAssistant hass)
None async_delay_save(self, Callable[[], _T] data_func, float delay=0)