Skip to content
This repository has been archived by the owner on Nov 7, 2024. It is now read-only.

fix: wait for initial entities to be loaded #153

Merged
merged 1 commit into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions src/home-assistant/home-assistant-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,34 @@ export class HomeAssistantClient {
url = url.replace(/\/$/, '');
const auth = createLongLivedTokenAuth(url, accessToken);
const connection = await createConnection({ auth });
const client = new HomeAssistantClient(connection);
await client.init();
return client;
return new HomeAssistantClient(connection);
}

private readonly entityCollection: Collection<HassEntities>;
private readonly registryCollection: Collection<HassRegistryEntities>;
private states: HassEntities = {};
private registry: HassRegistryEntities = {};
private states: HassEntities | undefined = undefined;
private registry: HassRegistryEntities | undefined = undefined;
private entities: Record<string, Entity> = {};
private readonly subscribers = new Set<SubscribeFn>();
private readonly update: () => Promise<void>;

private _isInitialized: boolean = false;
public get isInitialized(): boolean {
return this._isInitialized;
}

private constructor(private readonly connection: Connection) {
this.update = debounce(this.expensiveUpdate.bind(this), 100);
this.entityCollection = entitiesColl(connection);
this.registryCollection = entityRegistryColl(connection);
}

private async init() {
this.entityCollection.subscribe((states) => {
this.entityCollection.subscribe(async (states) => {
this.states = states;
this.update();
await this.update();
});
this.registryCollection.subscribe((registry) => {
this.registryCollection.subscribe(async (registry) => {
this.registry = registry;
this.update();
await this.update();
});
}

Expand All @@ -57,17 +58,21 @@ export class HomeAssistantClient {
}

private async expensiveUpdate() {
if (!this.states || !this.registry) {
return;
}
this.entities = Object.fromEntries(
Object.keys(this.states)
.map<Entity>((entityId) => ({
...this.states[entityId],
hidden: !!this.registry[entityId]?.hidden_by,
...this.states![entityId],
hidden: !!this.registry?.[entityId]?.hidden_by,
}))
.map((entity) => [entity.entity_id, entity]),
);
for (const subscriber of this.subscribers) {
await subscriber(this.entities);
}
this._isInitialized = true;
}

callService(
Expand Down
6 changes: 6 additions & 0 deletions src/home-assistant/home-assistant-matter-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ export class HomeAssistantMatterAdapter {
private readonly ignoreEntities = new Set<string>();
private readonly hiddenEntities = new Set<string>();
private readonly devices = new Map<string, HomeAssistantDevice>();
private _isInitialized: boolean = false;
public readonly close: UnsubscribeFn;

public get isInitialized(): boolean {
return this._isInitialized;
}

constructor(
private readonly client: HomeAssistantClient,
private readonly platform: MatterbridgeDynamicPlatform,
Expand All @@ -58,6 +63,7 @@ export class HomeAssistantMatterAdapter {
for (const removedEntity of removed) {
await this.remove(removedEntity);
}
this._isInitialized = true;
}

async create(entity: Entity) {
Expand Down
15 changes: 13 additions & 2 deletions src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,29 @@ export class HomeAssistantPlatform extends MatterbridgeDynamicPlatform {

override async onStart(reason?: string) {
const config = this.validateConfig();
this.log.info('onStart called with reason:', reason ?? 'none');
this.log.debug('onStart called with reason:', reason ?? 'none');

const client = await HomeAssistantClient.create(config.homeAssistantUrl, config.homeAssistantAccessToken);
this.adapter = new HomeAssistantMatterAdapter(
client,
this,
new PatternMatcher(config.homeAssistantClientConfig ?? {}),
);

await new Promise<void>((resolve) => {
const handle = setInterval(() => {
if (client.isInitialized && this.adapter.isInitialized) {
clearInterval(handle);
resolve();
}
}, 10);
});

this.log.debug('onStart finished');
}

override async onShutdown(reason?: string) {
this.log.info('onShutdown called with reason:', reason ?? 'none');
this.log.debug('onShutdown called with reason:', reason ?? 'none');
this.adapter.close();
if (this.config.unregisterOnShutdown === true) await this.unregisterAllDevices();
}
Expand Down