UNPKG

node-red-contrib-home-assistant-websocket

Version:
101 lines (100 loc) 4.41 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createSocket; exports.atLeastHaVersion = atLeastHaVersion; const debug_1 = __importDefault(require("debug")); const home_assistant_js_websocket_1 = require("home-assistant-js-websocket"); const ws_1 = __importDefault(require("ws")); const Websocket_1 = require("./Websocket"); const debug = (0, debug_1.default)('home-assistant:socket'); /* * Pretty much a copy from https://github.com/home-assistant/home-assistant-js-websocket */ function createSocket({ auth, connectionDelay, eventBus, rejectUnauthorizedCerts, url, }) { debug('[Auth Phase] Initializing', url); function connect(promResolve, promReject) { debug('[Auth Phase] New connection', url); eventBus.emit(Websocket_1.ClientEvent.Connecting); const socket = new ws_1.default(url, { rejectUnauthorized: rejectUnauthorizedCerts, }); // If invalid auth, we will not try to reconnect. let invalidAuth = false; const onOpen = async () => { try { socket.send(JSON.stringify(auth)); } catch (err) { invalidAuth = err === home_assistant_js_websocket_1.ERR_INVALID_AUTH; socket.close(); } }; const onMessage = (data, isBinary) => { if (isBinary) return; const message = JSON.parse(data.toString()); debug('[Auth Phase] Received', message); switch (message.type) { case home_assistant_js_websocket_1.MSG_TYPE_AUTH_INVALID: invalidAuth = true; socket.close(); break; case home_assistant_js_websocket_1.MSG_TYPE_AUTH_OK: socket.off('open', onOpen); socket.off('message', onMessage); socket.off('close', onClose); socket.off('error', onClose); socket.haVersion = message.ha_version; // enable coalesce messages if supported if (atLeastHaVersion(socket.haVersion, 2022, 9)) { socket.send(JSON.stringify({ type: 'supported_features', id: 1, features: { coalesce_messages: 1 }, })); } promResolve(socket); break; default: if (message.type !== home_assistant_js_websocket_1.MSG_TYPE_AUTH_REQUIRED) { debug('[Auth Phase] Unhandled message', message); } } }; const onClose = () => { // If we are in error handler make sure close handler doesn't also fire. socket.off('close', onClose); if (invalidAuth) { promReject(home_assistant_js_websocket_1.ERR_INVALID_AUTH); return; } // Try again in a second setTimeout(() => connect(promResolve, promReject), 5000); }; socket.on('open', onOpen); socket.on('message', onMessage); socket.on('close', onClose); socket.on('error', onClose); } return new Promise((resolve, reject) => { // if hass.io, do a 5 second delay so it doesn't spam the hass.io proxy // https://github.com/zachowj/node-red-contrib-home-assistant-websocket/issues/76 setTimeout(() => connect(resolve, reject), connectionDelay !== false ? 5000 : 0); }); } // https://github.com/home-assistant/home-assistant-js-websocket/blob/95f166b29a09fc1841bd0c1f312391ceb2812520/lib/util.ts#L45 function atLeastHaVersion(version, major, minor, patch) { const [haMajor, haMinor, haPatch] = version.split('.', 3); return (Number(haMajor) > major || (Number(haMajor) === major && (patch === undefined ? Number(haMinor) >= minor : Number(haMinor) > minor)) || (patch !== undefined && Number(haMajor) === major && Number(haMinor) === minor && Number(haPatch) >= patch)); }