UNPKG

homebridge-loxone-proxy

Version:

Homebridge Dynamic Platform Plugin which exposes a Loxone System to Homekit.

217 lines 9.24 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const uuid_1 = require("uuid"); const LxCommunicator = __importStar(require("lxcommunicator")); const WebSocketConfig = LxCommunicator.WebSocketConfig; class LoxoneHandler { constructor(platform) { this.socket = undefined; this.loxdata = undefined; this.log = platform.log; this.host = platform.config.host; this.port = platform.config.port; this.tls = platform.config.TLS; this.username = platform.config.username; this.password = platform.config.password; this.uuidCallbacks = {}; this.uuidCache = {}; this.startListener(); } startListener() { if (typeof this.socket === 'undefined') { const uuid = (0, uuid_1.v4)(); const proto = this.tls ? WebSocketConfig.protocol.WSS : WebSocketConfig.protocol.WS; const webSocketConfig = new WebSocketConfig(proto, uuid, 'homebridge', WebSocketConfig.permission.APP, false); const handleAnyEvent = (uuid, message) => { if (Object.prototype.hasOwnProperty.call(this.uuidCallbacks, uuid)) { if (typeof message === 'string') { if (message.includes('->')) { const parts = message.split('->'); if (parts.length === 2) { message = parts[1].trim(); } } message = { uuid: uuid, value: message }; } this.uuidCallbacks[uuid].forEach(callback => callback(message)); } this.uuidCache[uuid] = message; }; webSocketConfig.delegate = { socketOnDataProgress: (socket, progress) => { this.log.debug('data progress ' + progress); }, socketOnTokenConfirmed: (socket, response) => { this.log.debug('token confirmed'); }, socketOnTokenReceived: (socket, result) => { this.log.debug('token received'); }, socketOnConnectionClosed: (socket, code) => { this.log.info('Socket closed ' + code); if (code !== LxCommunicator.SupportCode.WEBSOCKET_MANUAL_CLOSE) { this.reconnect(); } }, socketOnEventReceived: (socket, events, type) => { for (const evt of events) { switch (type) { case LxCommunicator.BinaryEvent.Type.EVENT: handleAnyEvent(evt.uuid, evt.value); handleAnyEvent(evt.uuid, evt); break; case LxCommunicator.BinaryEvent.Type.EVENTTEXT: handleAnyEvent(evt.uuid, evt.text); break; case LxCommunicator.BinaryEvent.Type.WEATHER: handleAnyEvent(evt.uuid, evt); break; default: break; } } }, }; this.socket = new LxCommunicator.WebSocket(webSocketConfig); this.connect() .catch(error => { this.log.error('Couldn\'t open socket: ' + error); this.reconnect(); }); } } async connect() { this.log.info(`Trying to connect to Miniserver at ${this.host}:${this.port} (TLS=${this.tls})`); let url; if (this.tls) { url = `https://${this.host}`; if (this.port && this.port !== 443) { url += `:${this.port}`; } } else { url = `http://${this.host}:${this.port}`; } try { await this.socket.open(url, this.username, this.password); const file = await this.socket.send('data/LoxAPP3.json'); this.loxdata = JSON.parse(file); this.startBinaryStatusUpdates(); this.log.info('Connected to Miniserver'); return true; } catch (error) { this.log.error('Connection failed: ' + error); try { this.socket.close(); } catch (_a) { } return false; } } startBinaryStatusUpdates() { this.log.debug('[LoxoneHandler] Enabling binary status updates...'); this.socket.send('jdev/sps/enablebinstatusupdate'); } reconnect(attempt = 0) { const delay = Math.min(10000 * (attempt + 1), 60000); this.log.info(`Reconnecting in ${delay / 1000}s...`); setTimeout(async () => { const success = await this.connect(); if (!success && attempt < 10) { this.reconnect(attempt + 1); } else if (!success) { this.log.error('Max reconnect attempts reached'); } }, delay); } registerListenerForUUID(uuid, callback) { if (Object.prototype.hasOwnProperty.call(this.uuidCallbacks, uuid)) { this.uuidCallbacks[uuid].push(callback); } else { this.uuidCallbacks[uuid] = [callback]; } if (uuid in this.uuidCache) { this.uuidCallbacks[uuid].forEach(cb => cb(this.uuidCache[uuid])); } } sendCommand(uuid, action) { return this.socket.send(`jdev/sps/io/${uuid}/${action}`, 2) .catch(err => this.log.error(`sendCommand failed: ${err}`)); } getsecuredDetails(uuid) { return this.socket.send(`jdev/sps/io/${uuid}/securedDetails`); } getActiveCommunicationToken() { var _a, _b, _c; try { const tokenHandler = (_a = this.socket) === null || _a === void 0 ? void 0 : _a._tokenHandler; if (!(tokenHandler === null || tokenHandler === void 0 ? void 0 : tokenHandler.getToken)) { return undefined; } const appToken = (_b = tokenHandler.getToken(WebSocketConfig.permission.APP, this.username)) !== null && _b !== void 0 ? _b : tokenHandler.getToken(WebSocketConfig.permission.APP); if (appToken === null || appToken === void 0 ? void 0 : appToken.token) { return appToken.token; } const webToken = (_c = tokenHandler.getToken(WebSocketConfig.permission.WEB, this.username)) !== null && _c !== void 0 ? _c : tokenHandler.getToken(WebSocketConfig.permission.WEB); if (webToken === null || webToken === void 0 ? void 0 : webToken.token) { return webToken.token; } return undefined; } catch (_d) { return undefined; } } getLastCachedValue(uuid) { return this.uuidCache[uuid]; } pushCachedState(accessory, uuid) { var _a, _b, _c; const value = this.getLastCachedValue(uuid); if (value === undefined) { this.log.debug(`[pushCachedState] No cached value found for UUID: ${uuid}`); return; } const itemState = (_a = accessory.ItemStates) === null || _a === void 0 ? void 0 : _a[uuid]; if (!itemState) { this.log.warn(`[pushCachedState] UUID not registered in ItemStates for device ${(_b = accessory.device) === null || _b === void 0 ? void 0 : _b.name}`); return; } const message = { uuid, state: itemState.state, service: itemState.service, value, }; this.log.debug(`[pushCachedState] Pushing Cached state for ${(_c = accessory.device) === null || _c === void 0 ? void 0 : _c.name} [${itemState.state}] = ${value}`); accessory.callBackHandler(message); } } exports.default = LoxoneHandler; //# sourceMappingURL=LoxoneHandler.js.map