import { Logger } from '@project-chip/matter-node.js/log'; import { HassEntity, StateChangedEvent } from './HAssTypes'; import hass, { HassApi, HassWsOptions } from 'homeassistant-ws'; const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); export class HAMiddleware { private logger = new Logger('HAMiddleware'); private hassClient: HassApi; private static instance: HAMiddleware; private requestFulfilled: boolean = true; private entities: { [k: string]: HassEntity } = {}; private functionsToCallOnChange: { [k: string]: ((data: StateChangedEvent) => void) | undefined; } = {}; async waitCompletition(): Promise { let waited = 0; const timeOut = 5000; while (!this.requestFulfilled && waited < timeOut) { await sleep(1000); waited += 1000; } } stop(): void { this.hassClient.rawClient.ws.close(); } async callAService(domain: string, service: string, extraArgs?: unknown) { this.requestFulfilled = false; this.hassClient.callService(domain, service, extraArgs); } subscribe() { this.hassClient.on('state_changed', (event) => { this.logger.debug(event); const toDo = this.functionsToCallOnChange[event.data.entity_id]; if (toDo) { toDo(event.data); } }); } subscrieToDevice(deviceId: string, fn: (event: StateChangedEvent) => void) { this.functionsToCallOnChange[deviceId] = fn; this.logger.debug(this.functionsToCallOnChange); } async getStates(): Promise<{ [k: string]: HassEntity }> { this.requestFulfilled = false; const states = await this.hassClient.getStates(); const sorted = states.reduceRight<{ [k: string]: HassEntity }>( (last, current) => { last[current['entity_id']] = current; return last; }, {} ); this.logger.debug({ getStates: sorted }); this.entities = sorted; return this.entities; } async getStatesPartitionedByType(): Promise<{ [k: string]: HassEntity[] }> { const states = await this.getStates(); const toReturn = Object.keys(states).reduceRight<{ [k: string]: HassEntity[]; }>((prev, current) => { const key = current.split('.')[0]; if (!prev[key] && !Array.isArray(prev[key])) { prev[key] = new Array(); } prev[key].push(states[current]); return prev; }, {}); this.logger.debug({ getStatesPartitionedByType: toReturn }); return toReturn; } async getServices() { this.requestFulfilled = false; const states = await this.hassClient.getServices(); return states; } private constructor(client: HassApi) { this.hassClient = client; } public static async getInstance( callerOptions?: Partial | undefined ): Promise { if (!HAMiddleware.instance) { const client = await hass(callerOptions); HAMiddleware.instance = new HAMiddleware(client); } return HAMiddleware.instance; } }