Skip to content

Fix multi-instance entity/device cross-wiring (#491)#499

Open
garycollins2002 wants to merge 1 commit into
JoDehli:masterfrom
garycollins2002:fix/multi-instance-support
Open

Fix multi-instance entity/device cross-wiring (#491)#499
garycollins2002 wants to merge 1 commit into
JoDehli:masterfrom
garycollins2002:fix/multi-instance-support

Conversation

@garycollins2002

Copy link
Copy Markdown

Summary

Follows up on #491. The 0.9.16 fix for that issue namespaced the
keep-alive/software-version sensor unique IDs by serial, which helps
those two specific entities, but the actual root cause was untouched
and still affects every other platform.

Root cause: get_miniserver_from_hass(hass) in miniserver.py
always returns the first-registered config entry's MiniServer:

def get_miniserver_from_hass(hass):
    return hass.data[DOMAIN][list(hass.data[DOMAIN].keys())[0]].miniserver

Every platform's async_setup_entry(hass, config_entry, async_add_entities)
calls this instead of using the config_entry it was actually invoked
for. With two or more Miniservers configured, the second (and any
subsequent) instance's platforms build entities from the first
instance's structure file, producing duplicate uuidAction/unique_id
entities that collide with the first instance's already-registered
entities ("Platform loxone does not generate unique IDs" errors) and
causing previously-working entities to go unavailable.

Separately, alarm_control_panel.py has its own bug: it subscribes to
the event bus directly in async_setup_entry, before async_add_entities
has decided whether the entity is actually accepted:

new_alarm = LoxoneAlarm(**loxone_alarm)
hass.bus.async_listen(EVENT, new_alarm.event_handler)   # fires unconditionally
entities.append(new_alarm)
async_add_entities(entities, True)                      # may reject duplicates

If HA rejects the entity for a duplicate unique_id (which happens today
because of the bug above), the listener is never unsubscribed and keeps
calling self.async_schedule_update_ha_state() on an entity whose
.hass was never set, producing a repeating
RuntimeError: Attribute hass is None on every subsequent websocket
event.

Changes

  • miniserver.py: scope get_miniserver_from_hass() by
    config_entry.entry_id instead of always returning the
    first-registered instance; drop the dead, single-instance-only
    get_miniserver_from_config().
  • Thread config_entry through to the lookup in all 12 platform files
    (climate, switch, cover, sensor, binary_sensor, light,
    alarm_control_panel, button, fan, media_player, number,
    text) and __init__.py's loxone_discovered().
  • alarm_control_panel.py: remove the premature hass.bus.async_listen
    call; LoxoneAlarm already inherits LoxoneEntity's standard
    async_added_to_hass/async_will_remove_from_hass lifecycle, which
    now handles subscription correctly like every other platform.

Test plan

  • Verified against two real Miniservers (different physical
    buildings) running concurrently for several days.
  • No more "Platform loxone does not generate unique IDs" errors on
    startup with both instances configured.
  • No more repeating RuntimeError: Attribute hass is None from
    the alarm platform.
  • Both instances' entities (climate, switch, cover, light, sensor,
    alarm, etc.) stay available after both integrations finish
    loading, regardless of setup order.
  • Confirmed via Home Assistant's device registry that devices are
    no longer cross-associated with the wrong config entry after
    the fix (previously, two lighting-controller devices had leaked
    an extra config_entries association from before the fix was
    applied; this is a one-time artifact of the old bug, not
    something the fix needs to clean up itself).

get_miniserver_from_hass() always returned the first-registered config
entry's MiniServer, ignoring which config_entry a platform's
async_setup_entry was actually invoked for. With two or more
Miniservers configured, the second (and subsequent) instance's
platforms built entities from the first instance's structure file,
producing duplicate unique_ids, "Platform loxone does not generate
unique IDs" errors, and previously-working entities going unavailable.

The 0.9.16 fix for JoDehli#491 namespaced the keep-alive/software-version
sensor unique_ids by serial, but that only patches those two specific
entities - every other platform (climate, switch, cover, light,
binary_sensor, alarm_control_panel, etc.) was still affected.

- miniserver.py: scope get_miniserver_from_hass() by config_entry.entry_id
  instead of always returning the first-registered instance; drop the
  dead, single-instance-only get_miniserver_from_config().
- Thread config_entry through to the lookup in all 12 platform files
  and __init__.py's loxone_discovered().
- alarm_control_panel.py: remove the async_setup_entry-time
  hass.bus.async_listen(EVENT, ...) call that fired before HA decided
  whether to accept the entity, leaving orphaned listeners bound to
  hass=None objects (RuntimeError: Attribute hass is None crash on
  every subsequent websocket event). LoxoneEntity's standard
  async_added_to_hass/async_will_remove_from_hass lifecycle now
  handles this like every other platform.

Verified against two real Miniservers running concurrently for
several days, including confirming device-registry entries no longer
cross-associate between instances.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant