UNPKG

homebridge-hilo

Version:

Plugin Homebridge (non officiel) pour la passerelle et les appareils Hilo de Hydro-Québec | Unofficial Homebridge plugin for Hydro-Québec Hilo bridge and devices

184 lines 8.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const config_1 = require("./config"); const logger_1 = require("./logger"); const api_1 = require("./api"); const hiloApi_1 = require("./hiloApi"); const devices_1 = require("./devices"); const subscription_1 = require("./subscription"); const location_1 = require("./location"); const deviceHub_1 = require("./deviceHub"); const types_1 = require("./devices/types"); const PLUGIN_NAME = "homebridge-hilo"; const PLATFORM_NAME = "Hilo"; function default_1(api) { api.registerPlatform(PLATFORM_NAME, Hilo); } class Hilo { constructor(log, config, api, accessories = {}) { this.log = log; this.config = config; this.api = api; this.accessories = accessories; this.pluginAccessories = {}; this.locations = []; this.subscriptions = {}; this.staleAccessories = []; (0, config_1.setConfig)(config); this.config = (0, config_1.getConfig)(); if (!this.config.refreshToken) { this.log.error("Please login with hilo in the plugin configuration page"); return; } (0, logger_1.setLogger)(log); (0, api_1.setApi)(api); log.info("Initializing Hilo platform"); api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, async () => { this.locations = await fetchLocations(); if (this.locations.length === 0) { log.error("No locations found"); return; } else { log.info(`Found ${this.locations.length} locations`); } const allSignalRDevices = []; const allGraphqlDevices = []; let signalRConnected = true; for (const location of this.locations) { const [hubResult, graphqlDevices] = await Promise.all([ (0, deviceHub_1.connectToDeviceHub)(location.id), (0, location_1.fetchDevicesForLocation)(location.locationHiloId), ]); if (!hubResult.connected) { signalRConnected = false; log.warn(`DeviceHub connection failed for location ${location.id}, will use cached devices`); } hubResult.devices.forEach((d) => (d.locationId = location.id)); allSignalRDevices.push(...hubResult.devices); allGraphqlDevices.push(...graphqlDevices); } // When SignalR failed, recover cached SignalR device data from accessories if (!signalRConnected && allSignalRDevices.length === 0) { const cachedDevices = Object.values(this.accessories) .map((a) => a.context.device) .filter((d) => !!(d === null || d === void 0 ? void 0 : d.hiloId)); if (cachedDevices.length > 0) { log.info(`Recovering ${cachedDevices.length} cached SignalR devices`); allSignalRDevices.push(...cachedDevices); } } const supportedDevices = allGraphqlDevices.filter((device) => types_1.SUPPORTED_DEVICES.includes(device.__typename)); if (supportedDevices.length === 0) { log.error("No supported devices found"); return; } else { log.info(`Found ${supportedDevices.length} supported devices`); } const signalRByHiloId = new Map(allSignalRDevices.map((d) => [d.hiloId, d])); supportedDevices.forEach((device) => { this.log.debug("Initializing device", device); const signalRDevice = signalRByHiloId.get(device.hiloId); if (!signalRDevice) { if (signalRConnected) { this.log.error(`No SignalR device found for hiloId ${device.hiloId}`); } else { this.log.warn(`No SignalR device found for hiloId ${device.hiloId} (SignalR disconnected, device may appear after reconnection)`); } return; } let accessory = this.accessories[device.hiloId]; if (!accessory) { this.log.debug(`Setting up new accessory for device ${device.hiloId}`); accessory = this.setupNewAccessory(device, signalRDevice); } else { accessory.context = { device: signalRDevice, graphqlDevice: device, }; } const pluginAccessory = devices_1.initializeHiloDevice[device.__typename](accessory, this.api); this.pluginAccessories[device.hiloId] = pluginAccessory; }); // Only remove stale accessories when SignalR is connected and authoritative if (signalRConnected) { const currentHiloIds = new Set(signalRByHiloId.keys()); this.staleAccessories = this.staleAccessories.concat(Object.values(this.accessories).filter((accessory) => { return !currentHiloIds.has(accessory.context.device.hiloId); })); this.log.debug(`Found ${this.staleAccessories.length} stale accessories removing...`); if (this.staleAccessories.length > 0) { this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, this.staleAccessories); } } else { log.warn("Skipping stale accessory removal because SignalR connection failed"); } this.setupSubscriptions(); log.info("Hilo platform is ready"); }); } async setupSubscriptions() { for (const location of this.locations) { try { const subscription = await (0, subscription_1.setupSubscription)(location.locationHiloId, (device) => { this.log.debug(`Device update received:`, device); const pluginAccessory = this.pluginAccessories[device.hiloId]; if (!pluginAccessory) { this.log.debug(`No accessory for device ${device.hiloId}`); return; } pluginAccessory.updateDevice(device); }); this.subscriptions[location.locationHiloId] = subscription; this.log.info(`Subscribed to updates for location ${location.locationHiloId}`); } catch (error) { this.log.error(`Failed to subscribe to location ${location.locationHiloId}:`, error instanceof Error ? error.message : String(error)); } } } configureAccessory(accessory) { var _a; this.log.debug(`Configuring accessory from cache ${accessory.displayName}`); if ((_a = accessory.context.device) === null || _a === void 0 ? void 0 : _a.hiloId) { this.accessories[accessory.context.device.hiloId] = accessory; } else { this.log.warn(`Stale cached accessory ${accessory.displayName}, will remove`); this.staleAccessories.push(accessory); } } setupNewAccessory(device, signalRDevice) { const uuid = this.api.hap.uuid.generate(signalRDevice.hiloId); const accessory = new this.api.platformAccessory(signalRDevice.name.trim(), uuid); accessory.context = { device: signalRDevice, graphqlDevice: device, }; this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [ accessory, ]); this.accessories[device.hiloId] = accessory; return accessory; } } async function fetchLocations() { (0, logger_1.getLogger)().debug("Fetching locations"); try { const response = await hiloApi_1.hiloApi.get("/Automation/v1/api/Locations", { params: { force: true }, }); return response.data; } catch (error) { (0, logger_1.getLogger)().error("Error while fetching locations", error instanceof Error ? error.message : String(error)); return []; } } //# sourceMappingURL=hilo.js.map