fix: Prevent premature reinitialization when stale HA reconnects (#2717)

- Closes: #2714
This commit is contained in:
Dermot Duffy
2026-08-29 13:47:38 -07:00
committed by GitHub
parent fb53681978
commit 4b101545cc
15 changed files with 333 additions and 131 deletions
@@ -1,41 +1,21 @@
import { STATE_RUNNING } from 'home-assistant-js-websocket';
import type { ConditionState } from '../../../condition-trigger/conditions/types.js';
import { localize } from '../../../localize/localize.js';
import type { HASSReadiness } from '../../hass/types.js';
import type { Issue, IssueDescription } from '../types.js';
// Tracks "is HA fully ready to talk to". Active in two sub-states:
// - 'lost' : the WebSocket is disconnected
// - 'starting' : the WebSocket is connected but HA hasn't finished loading
// integrations yet (hass.config.state !== STATE_RUNNING)
// Both sub-states render as a full-card notification with a spinner. The card
// only attempts re-initialization when the issue clears (i.e. HA is fully
// ready), so integration-specific WS calls (e.g. Frigate event subscriptions)
// don't fail with "Unknown command" against a half-loaded HA.
type ConnectionState = 'ready' | 'lost' | 'starting';
export class ConnectionIssue implements Issue {
public readonly key = 'connection' as const;
private _state: ConnectionState = 'ready';
private _readiness: HASSReadiness = 'ready';
public detectDynamic(state: ConditionState): void {
// Before HASS is ever provided, leave state untouched -- undefined hass is
// not a disconnection, just "not yet initialized".
if (state.hass === undefined) {
return;
}
if (!state.hass.connected) {
this._state = 'lost';
} else if (state.hass.config?.state !== STATE_RUNNING) {
this._state = 'starting';
} else {
this._state = 'ready';
if (state.hassReadiness) {
this._readiness = state.hassReadiness;
}
}
public hasIssue(): boolean {
return this._state !== 'ready';
return this._readiness !== 'ready';
}
public isFullCardIssue(): boolean {
@@ -43,7 +23,7 @@ export class ConnectionIssue implements Issue {
}
public getIssue(): IssueDescription | null {
return this._state === 'lost'
return this._readiness === 'disconnected'
? {
icon: 'mdi:lan-disconnect',
severity: 'high',
@@ -57,7 +37,7 @@ export class ConnectionIssue implements Issue {
in_progress: true,
},
}
: this._state === 'starting'
: this._readiness === 'starting'
? {
icon: 'mdi:home-assistant',
severity: 'medium',
@@ -75,6 +55,6 @@ export class ConnectionIssue implements Issue {
}
public reset(): void {
this._state = 'ready';
this._readiness = 'ready';
}
}