diff --git a/src/discovery/hap_node_js_client.ts b/src/discovery/hap_node_js_client.ts index 969fc34..36ab875 100644 --- a/src/discovery/hap_node_js_client.ts +++ b/src/discovery/hap_node_js_client.ts @@ -1,45 +1,73 @@ -import type { HapDiscover } from './api' -import { HAPNodeJSClient } from 'hap-node-client' +import type {HapDiscover} from './api' +import {HAPNodeJSClient} from 'hap-node-client' -import { Device, DeviceBoundary } from '../boundaries' -import { Array, Unknown } from 'runtypes' +import {Device, DeviceBoundary} from '../boundaries' +import {Array, Unknown} from 'runtypes' +import {Logger} from "homebridge"; const MaybeDevices = Array(Unknown) -export const discover: HapDiscover = ({ pin, refreshInterval, discoveryTimeout, requestTimeout, logger, debug }) => { +type HapConfig = { + debug: boolean + refresh: number + timeout: number + reqTimeout: number + pin: string +} +type HapClient = typeof HAPNodeJSClient +type ResolveFunc = (devices: Device[]) => void +type RejectFunc = (error: unknown) => void + +const clientMap: Record = {} +const promiseMap: Record = {} + +function startDiscovery(logger: Logger, config: HapConfig, resolve: ResolveFunc, reject: RejectFunc) { + const key = JSON.stringify(config) + + if (!clientMap[key]) { + logger.debug('Creating new HAP client') + const client = new HAPNodeJSClient(config) + client.on('Ready', (deviceData: unknown) => { + try { + const devices: Device[] = [] + + for (const device of MaybeDevices.check(deviceData)) { + try { + devices.push(DeviceBoundary.check(device)) + } catch (e) { + logger.error( + 'Boundary check for device data failed %o %s', + e, + JSON.stringify(device, null, 4), + ) + } + } + + if (promiseMap[key]) promiseMap[key][0](devices) + } catch (e) { + if (promiseMap[key]) promiseMap[key][1](e) + } + }) + clientMap[key] = client + } else { + logger.debug('Reusing existing HAP client') + } + promiseMap[key] = [resolve, reject] +} + +export const discover: HapDiscover = ({pin, refreshInterval, discoveryTimeout, requestTimeout, logger, debug}) => { return new Promise((resolve, reject) => { - try { - const client = new HAPNodeJSClient({ + startDiscovery( + logger, + { debug: debug, refresh: refreshInterval, timeout: discoveryTimeout, reqTimeout: requestTimeout, pin, - }) - - client.on('Ready', (deviceData: unknown) => { - try { - const devices: Device[] = [] - - for (const device of MaybeDevices.check(deviceData)) { - try { - devices.push(DeviceBoundary.check(device)) - } catch (e) { - logger.error( - 'Boundary check for device data failed %o %s', - e, - JSON.stringify(device, null, 4), - ) - } - } - - resolve(devices) - } catch (e) { - reject(e) - } - }) - } catch (e) { - reject(e) - } + }, + resolve, + reject + ) }) } diff --git a/src/platform.ts b/src/platform.ts index 5903190..bcd2e79 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -112,6 +112,7 @@ export class PrometheusExporterPlatform implements IndependentPlatformPlugin { this.metrics = aggregate(devices) this.metricsDiscovered = true this.log.debug('HAP discovery completed, %d metrics discovered', this.metrics.length) + this.startHapDiscovery() }) .catch((e) => { this.log.error('HAP discovery error', e)