Repository: dermotduffy/frigate-hass-card (ts)

Issue:
Card no longer loads in some Android devices after #1390
<!-- READ THIS FIRST:
- If you need additional help with this template please refer to https://www.home-assistant.io/help/reporting_issues/
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/home-assistant/releases
- Provide as many details as possible. Do not delete any text from this template!
-->

**Checklist:**

- [x] I updated to the latest version available
- [x] I cleared the cache of my browser

**Release with the issue:** #1390 onwards (tested up to #1399)

**Last working release (if known):** #1390 downwards (last working is #1366)

**Browser and Operating System:** Android 10, Webview 122. Also happened in my brother's wife with Android 14, Webview 122. Problem reproduces within or outside the companion app.

<!--
Provide details about what browser (and version) you are seeing the issue in. And also which operating system this is on. If possible try to replicate the issue in other browsers and include your findings here.
-->

**Description of problem:**

The card does not load on a few devices. **Note it is working normally in some other devices.**

![image](https://github.com/dermotduffy/frigate-hass-card/assets/29582865/29ade534-1370-44e7-b424-6f3f0af717a3)
![image](https://github.com/dermotduffy/frigate-hass-card/assets/29582865/cd7fa31e-edbe-4dec-bbd9-766600cb2169)



<!--
Explain what the issue is, and how things should look/behave. If possible provide a screenshot with a description.
-->

**Frigate card diagnostic information**

<!--
On the card, hold down the Frigate menu button for a few seconds then paste the diagnostics below:
-->

Can't access this button.

**Javascript errors shown in the web inspector (if applicable):**

None, unfortunately.

**Additional information:**

After some investigation with the help of @dermotduffy, this is where the initialization logic seems to stop:

![image](https://github.com/dermotduffy/frigate-hass-card/assets/29582865/b3fb661a-a438-4eae-b875-9c42b6074d23)


Pull request description:
Don't run automations prior to initialization .
* May or may not be sufficient to close #1407

Patch:
diff --git a/src/card-controller/automations-manager.ts b/src/card-controller/automations-manager.ts
index dbc38abb..367a7f5c 100644
--- a/src/card-controller/automations-manager.ts
+++ b/src/card-controller/automations-manager.ts
@@ -27,11 +27,16 @@ export class AutomationsManager {
   }
 
   public execute(): void {
-    const hass = this._api.getHASSManager().getHASS();
-
-    // Never execute automations if there's an error (as our automation loop
-    // avoidance -- which shows as an error -- would not work!).
-    if (!hass || this._api.getMessageManager().hasErrorMessage()) {
+    if (
+      !this._api.getHASSManager().hasHASS() ||
+      // Never execute automations if the card hasn't finished initializing, as
+      // it could cause a view change when camera loads are not finished.
+      // See: https://github.com/dermotduffy/frigate-hass-card/issues/1407
+      !this._api.getInitializationManager().isInitializedMandatory() ||
+      // Never execute automations if there's an error (as our automation loop
+      // avoidance -- which shows as an error -- would not work!).
+      this._api.getMessageManager().hasErrorMessage()
+    ) {
       return;
     }
 
diff --git a/src/card-controller/hass/hass-manager.ts b/src/card-controller/hass/hass-manager.ts
index a0ea929f..86ce88eb 100644
--- a/src/card-controller/hass/hass-manager.ts
+++ b/src/card-controller/hass/hass-manager.ts
@@ -17,6 +17,10 @@ export class HASSManager {
     return this._hass;
   }
 
+  public hasHASS(): boolean {
+    return !!this._hass;
+  }
+
   public getStateWatcher(): StateWatcherSubscriptionInterface {
     return this._stateWatcher;
   }
diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts
index 5dd754d6..834d7f8a 100644
--- a/src/card-controller/types.ts
+++ b/src/card-controller/types.ts
@@ -59,6 +59,7 @@ export interface CardAutomationsAPI {
   getCardElementManager(): CardElementManager;
   getConditionsManager(): ConditionsManager;
   getHASSManager(): HASSManager;
+  getInitializationManager(): InitializationManager;
   getMessageManager(): MessageManager;
 }
 


Test patch:
diff --git a/tests/card-controller/automations-manager.test.ts b/tests/card-controller/automations-manager.test.ts
index a60fa696..2f9d6d41 100644
--- a/tests/card-controller/automations-manager.test.ts
+++ b/tests/card-controller/automations-manager.test.ts
@@ -1,6 +1,6 @@
 import { afterEach, describe, expect, it, vi } from 'vitest';
 import { AutomationsManager } from '../../src/card-controller/automations-manager.js';
-import { createCardAPI, createHASS } from '../test-utils.js';
+import { createCardAPI } from '../test-utils.js';
 import { ActionType } from '../../src/config/types.js';
 import { AuxillaryActionConfig } from '../../src/card-controller/actions/types.js';
 
@@ -34,9 +34,25 @@ describe('AutomationsManager', () => {
     expect(api.getActionsManager().executeActions).not.toBeCalled();
   });
 
+  it('should do nothing without being initialized', () => {
+    const api = createCardAPI();
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      false,
+    );
+
+    const automationsManager = new AutomationsManager(api);
+    automationsManager.execute();
+
+    expect(api.getActionsManager().executeActions).not.toBeCalled();
+  });
+
   it('should do nothing without automations', () => {
     const api = createCardAPI();
-    vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      true,
+    );
 
     const automationsManager = new AutomationsManager(api);
     automationsManager.execute();
@@ -46,7 +62,10 @@ describe('AutomationsManager', () => {
 
   it('should execute actions', () => {
     const api = createCardAPI();
-    vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      true,
+    );
 
     const automationsManager = new AutomationsManager(api);
     automationsManager.addAutomations([automation]);
@@ -77,7 +96,11 @@ describe('AutomationsManager', () => {
 
   it('should execute actions_not', () => {
     const api = createCardAPI();
-    vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      true,
+    );
+
     vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false);
 
     const automationsManager = new AutomationsManager(api);
@@ -90,7 +113,10 @@ describe('AutomationsManager', () => {
 
   it('should prevent automation loops', () => {
     const api = createCardAPI();
-    vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      true,
+    );
 
     const automationsManager = new AutomationsManager(api);
     automationsManager.addAutomations([automation, not_automation]);
@@ -130,7 +156,10 @@ describe('AutomationsManager', () => {
 
   it('should delete automations', () => {
     const api = createCardAPI();
-    vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
+    vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true);
+    vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
+      true,
+    );
 
     const automationsManager = new AutomationsManager(api);
     automationsManager.addAutomations([automation]);
diff --git a/tests/card-controller/hass/hass-manager.test.ts b/tests/card-controller/hass/hass-manager.test.ts
index f4051d31..181a2799 100644
--- a/tests/card-controller/hass/hass-manager.test.ts
+++ b/tests/card-controller/hass/hass-manager.test.ts
@@ -21,6 +21,7 @@ describe('HASSManager', () => {
   it('should have null hass on construction', () => {
     const manager = new HASSManager(createCardAPI());
     expect(manager.getHASS()).toBeNull();
+    expect(manager.hasHASS()).toBeFalsy();
   });
 
   it('should get state watcher', () => {
@@ -28,6 +29,15 @@ describe('HASSManager', () => {
     expect(manager.getStateWatcher()).toEqual(expect.any(StateWatcher));
   });
 
+  it('should get hass after set', () => {
+    const manager = new HASSManager(createCardAPI());
+    const hass = createHASS();
+    manager.setHASS(hass);
+
+    expect(manager.getHASS()).toBe(hass);
+    expect(manager.hasHASS()).toBeTruthy();
+  });
+
   it('should set light or dark mode upon setting hass', () => {
     const api = createCardAPI();
     const manager = new HASSManager(api);