fix(gateway): restore multiplex secondary adapters

Partial cherry-pick of a7ffbbff7 from PR #63256: secondary-profile
adapter creation errors no longer abort the whole secondary startup
(try/except around _create_adapter + loud warning on None return), and
Home Assistant's check_ha_requirements() becomes dep-only with the
credential moved to a new validate_ha_config() so secondary profiles
whose HASS_TOKEN lives in the profile secret scope are not silently
dropped by the registry gate.

Telegram diagnostic hunks and profile-label stamping dropped: the
regression they targeted does not exist on current main and they
conflict with the connect() teardown fence.
This commit is contained in:
Jay Stothard 2026-07-16 05:08:59 -07:00 committed by Teknium
parent ea2c9bc10f
commit bd44ef8645
3 changed files with 42 additions and 13 deletions

View file

@ -8828,9 +8828,24 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
f"'{profile_name}'s config.yaml (configure it only on the "
f"default profile)."
)
with _profile_runtime_scope(profile_home):
adapter = self._create_adapter(platform, platform_config)
try:
with _profile_runtime_scope(profile_home):
adapter = self._create_adapter(platform, platform_config)
except Exception as e:
logger.error(
"[MULTIPLEX] Profile '%s': _create_adapter('%s') raised %s",
profile_name,
platform.value,
e,
exc_info=True,
)
continue
if not adapter:
logger.warning(
"[MULTIPLEX] Profile '%s': skipping platform '%s' - adapter creation returned None",
profile_name,
platform.value,
)
continue
# Same-token conflict detection — refuse a duplicate poll.

View file

@ -40,12 +40,14 @@ logger = logging.getLogger(__name__)
def check_ha_requirements() -> bool:
"""Check if Home Assistant dependencies are available and configured."""
if not AIOHTTP_AVAILABLE:
return False
if not os.getenv("HASS_TOKEN"):
return False
return True
"""Check if Home Assistant runtime dependencies are available."""
return bool(AIOHTTP_AVAILABLE)
def validate_ha_config(config: PlatformConfig) -> bool:
"""Accept either a scoped config token or an env-provided HASS_TOKEN."""
token = getattr(config, "token", None) or os.getenv("HASS_TOKEN", "")
return bool(str(token or "").strip())
class HomeAssistantAdapter(BasePlatformAdapter):
@ -560,6 +562,7 @@ def register(ctx) -> None:
label="Home Assistant",
adapter_factory=_build_adapter,
check_fn=check_ha_requirements,
validate_config=validate_ha_config,
is_connected=_is_connected,
required_env=["HASS_TOKEN"],
install_hint="pip install aiohttp",

View file

@ -17,6 +17,7 @@ from gateway.config import (
from plugins.platforms.homeassistant.adapter import (
HomeAssistantAdapter,
check_ha_requirements,
validate_ha_config,
)
@ -26,12 +27,8 @@ from plugins.platforms.homeassistant.adapter import (
class TestCheckRequirements:
def test_returns_false_without_token(self, monkeypatch):
def test_returns_true_when_aiohttp_present(self, monkeypatch):
monkeypatch.delenv("HASS_TOKEN", raising=False)
assert check_ha_requirements() is False
def test_returns_true_with_token(self, monkeypatch):
monkeypatch.setenv("HASS_TOKEN", "test-token")
assert check_ha_requirements() is True
@patch("plugins.platforms.homeassistant.adapter.AIOHTTP_AVAILABLE", False)
@ -40,6 +37,20 @@ class TestCheckRequirements:
assert check_ha_requirements() is False
class TestValidateConfig:
def test_returns_false_without_token_in_config_or_env(self, monkeypatch):
monkeypatch.delenv("HASS_TOKEN", raising=False)
assert validate_ha_config(PlatformConfig(enabled=True)) is False
def test_returns_true_with_token_in_env(self, monkeypatch):
monkeypatch.setenv("HASS_TOKEN", "test-token")
assert validate_ha_config(PlatformConfig(enabled=True)) is True
def test_returns_true_with_token_in_config(self, monkeypatch):
monkeypatch.delenv("HASS_TOKEN", raising=False)
assert validate_ha_config(PlatformConfig(enabled=True, token="cfg-token")) is True
# ---------------------------------------------------------------------------
# _format_state_change - pure function, all domain branches
# ---------------------------------------------------------------------------