@@ -119,6 +119,51 @@ def _check_common_slots(
119119 }
120120
121121
122+ async def _async_check_existing_usercodes (
123+ hass : HomeAssistant ,
124+ dev_reg : dr .DeviceRegistry ,
125+ ent_reg : er .EntityRegistry ,
126+ lock_entity_id : str ,
127+ ) -> tuple [Any , dict [int , str | SlotCode ]]:
128+ """Query a single lock for all existing usercodes.
129+
130+ Returns (lock_instance, usercodes) where usercodes is the full dict from
131+ the provider (managed and unmanaged, including empty slots). Callers are
132+ responsible for filtering.
133+
134+ Raises LockCodeManagerError for expected skip conditions (missing entity,
135+ unsupported platform, missing config entry). Unexpected exceptions from
136+ the provider propagate directly.
137+ """
138+ lock_entry = ent_reg .async_get (lock_entity_id )
139+ if not lock_entry :
140+ _LOGGER .warning (
141+ "Entity %s not found in registry; skipping usercode check" ,
142+ lock_entity_id ,
143+ )
144+ raise LockCodeManagerError (lock_entity_id )
145+ if lock_entry .platform not in INTEGRATIONS_CLASS_MAP :
146+ _LOGGER .debug (
147+ "Lock %s uses unsupported platform %s; skipping usercode check" ,
148+ lock_entity_id ,
149+ lock_entry .platform ,
150+ )
151+ raise LockCodeManagerError (lock_entity_id )
152+ lock_config_entry = hass .config_entries .async_get_entry (lock_entry .config_entry_id )
153+ if lock_config_entry is None :
154+ _LOGGER .warning (
155+ "Config entry for lock %s not found; skipping usercode check" ,
156+ lock_entity_id ,
157+ )
158+ raise LockCodeManagerError (lock_entity_id )
159+
160+ lock_instance = INTEGRATIONS_CLASS_MAP [lock_entry .platform ](
161+ hass , dev_reg , ent_reg , lock_config_entry , lock_entry
162+ )
163+ usercodes = await lock_instance .async_internal_get_usercodes ()
164+ return lock_instance , usercodes
165+
166+
122167async def _async_get_unmanaged_codes (
123168 hass : HomeAssistant ,
124169 dev_reg : dr .DeviceRegistry ,
@@ -134,75 +179,37 @@ async def _async_get_unmanaged_codes(
134179 - Dict keyed by lock entity ID to temporary lock provider instances, for
135180 reuse in clear/adopt steps.
136181 """
137-
138- async def _query_lock (
139- lock_entity_id : str ,
140- ) -> tuple [Any , dict [int , str | SlotCode ]]:
141- """Query a single lock for unmanaged codes.
142-
143- Returns (lock_instance, unmanaged_codes) or raises on any skip condition.
144- Logs the reason before raising so the outer loop can use a bare except.
145- """
146- lock_entry = ent_reg .async_get (lock_entity_id )
147- if not lock_entry :
148- _LOGGER .warning (
149- "Entity %s not found in registry; skipping usercode check" ,
150- lock_entity_id ,
151- )
152- raise LockCodeManagerError (lock_entity_id )
153- if lock_entry .platform not in INTEGRATIONS_CLASS_MAP :
154- _LOGGER .debug (
155- "Lock %s uses unsupported platform %s; skipping usercode check" ,
156- lock_entity_id ,
157- lock_entry .platform ,
158- )
159- raise LockCodeManagerError (lock_entity_id )
160- lock_config_entry = hass .config_entries .async_get_entry (
161- lock_entry .config_entry_id
162- )
163- if lock_config_entry is None :
164- _LOGGER .warning (
165- "Config entry for lock %s not found; skipping usercode check" ,
166- lock_entity_id ,
167- )
168- raise LockCodeManagerError (lock_entity_id )
169-
170- lock_instance = INTEGRATIONS_CLASS_MAP [lock_entry .platform ](
171- hass , dev_reg , ent_reg , lock_config_entry , lock_entry
172- )
173- usercodes = await lock_instance .async_internal_get_usercodes ()
174-
175- managed_slots = {
176- int (s )
177- for entry in hass .config_entries .async_entries (DOMAIN )
178- if lock_entity_id in get_entry_data (entry , CONF_LOCKS , [])
179- for s in get_entry_data (entry , CONF_SLOTS , {})
180- }
181- unmanaged = {
182- slot : code
183- for slot , code in usercodes .items ()
184- if code is not SlotCode .EMPTY and slot not in managed_slots
185- }
186- return lock_instance , unmanaged
187-
188182 result : dict [str , dict [int , str | SlotCode ]] = {}
189183 lock_instances : dict [str , Any ] = {}
190184 for lock_entity_id in lock_entity_ids :
191185 try :
192- lock_instance , unmanaged = await _query_lock (lock_entity_id )
186+ lock_instance , usercodes = await _async_check_existing_usercodes (
187+ hass , dev_reg , ent_reg , lock_entity_id
188+ )
193189 except LockCodeManagerError :
194- continue
190+ pass
195191 except Exception : # noqa: BLE001
196192 _LOGGER .warning (
197193 "Failed to get usercodes from %s during lock reset check; "
198194 "this lock's codes will not be shown" ,
199195 lock_entity_id ,
200196 exc_info = True ,
201197 )
202- continue
203- if unmanaged :
204- result [lock_entity_id ] = unmanaged
205- lock_instances [lock_entity_id ] = lock_instance
198+ else :
199+ managed_slots = {
200+ int (s )
201+ for entry in hass .config_entries .async_entries (DOMAIN )
202+ if lock_entity_id in get_entry_data (entry , CONF_LOCKS , [])
203+ for s in get_entry_data (entry , CONF_SLOTS , {})
204+ }
205+ unmanaged = {
206+ slot : code
207+ for slot , code in usercodes .items ()
208+ if code is not SlotCode .EMPTY and slot not in managed_slots
209+ }
210+ if unmanaged :
211+ result [lock_entity_id ] = unmanaged
212+ lock_instances [lock_entity_id ] = lock_instance
206213 return result , lock_instances
207214
208215
0 commit comments