UNPKG

node-red-contrib-home-assistant-websocket

Version:
110 lines (109 loc) 3.8 kB
"use strict"; const { merge } = require('lodash'); const BaseError = require('../common/errors/BaseError').default; const BaseNode = require('./BaseNode'); const { INTEGRATION_EVENT, INTEGRATION_LOADED, INTEGRATION_UNLOADED, INTEGRATION_NOT_LOADED, } = require('../const'); const DEFAULT_NODE_OPTIONS = { debug: false, config: { exposeToHomeAssistant: (nodeDef) => nodeDef.exposeToHomeAssistant === undefined ? false : nodeDef.exposeToHomeAssistant, }, }; class EventsNode extends BaseNode { constructor({ node, config, RED, status, nodeOptions = {} }) { nodeOptions = merge({}, DEFAULT_NODE_OPTIONS, nodeOptions); super({ node, config, RED, status, nodeOptions }); this.listeners = {}; this.registered = false; this.integrationErrorMessage = 'Node-RED custom integration needs to be installed in Home Assistant for this node to function correctly.'; this.status = status; this.status.init({ nodeState: this.isEnabled, homeAssistant: this.homeAssistant, }); // Setup event listeners const events = { 'ha_client:close': this.onHaEventsClose, 'ha_client:error': this.onHaEventsError, [INTEGRATION_EVENT]: this.onHaIntegration, }; Object.entries(events).forEach(([event, callback]) => this.addEventClientListener(event, callback.bind(this))); } errorHanlderForEvents(callback) { return (...args) => { try { // eslint-disable-next-line n/no-callback-literal callback(...args); } catch (err) { if (err instanceof BaseError) { this.status.setFailed(err.statusMessage); this.node.error(err); } else { this.status.setFailed(this.RED._('home-assistant.status.error')); this.node.error(err.message); } } }; } addEventClientListener(event, handler) { if (this.homeAssistant) { const callback = this.errorHanlderForEvents(handler); this.listeners[event] = callback; this.homeAssistant.addListener(event, callback); } } removeEventClientListeners() { if (this.homeAssistant) { Object.entries(this.listeners).forEach(([event, handler]) => { this.homeAssistant.removeListener(event, handler); }); } } async onClose(removed) { super.onClose(removed); this.removeEventClientListeners(); if (typeof this.status.destroy === 'function') { this.status.destroy(); } } onHaEventsClose() { this.registered = false; } onHaEventsError(err) { if (err && err.message) this.node.error(err.message); } onHaIntegration(type) { switch (type) { case INTEGRATION_LOADED: this.registerEntity(); break; case INTEGRATION_UNLOADED: case INTEGRATION_NOT_LOADED: this.registered = false; break; } } registerEntity() { if (this.nodeConfig.exposeToHomeAssistant === false) { return false; } if (!this.isIntegrationLoaded) { if (this.node.type === 'ha-webhook' || this.node.type === 'ha-entity') { this.node.error(this.integrationErrorMessage); this.status.setFailed('Error'); } return false; } if (this.registered) { return false; } } } module.exports = EventsNode;