node-red-contrib-home-assistant-websocket
Version:
Node-RED integration with Home Assistant through websocket and REST API
2 lines (1 loc) • 4.19 kB
JavaScript
"use strict";const c=require("selectn"),{merge:v}=require("lodash"),m=require("../common/services/ComparatorService").default,C=require("../common/State").default,y=require("../common/TransformState").default,{createControllerDependencies:S}=require("../common/controllers/helpers"),{debugToClient:b}=require("../helpers/node"),{getHomeAssistant:I}=require("../homeAssistant"),A={config:{debugenabled:{},name:{},server:{isNode:!0},version:o=>o.version||0},input:{topic:{messageProp:"topic"},payload:{messageProp:"payload"}}};class R{constructor({node:e,config:t,RED:n,status:s,nodeOptions:r={}}){this.node=e,this.RED=n,this.options=v({},A,r),this._eventHandlers=E,this._internals=f,this.status=s,this.state=new C(this.node),this.nodeConfig=Object.entries(this.options.config).reduce((l,[u,h])=>(h.isNode?l[u]=this.RED.nodes.getNode(t[u]):typeof h=="function"?l[u]=h.call(this,t):l[u]=t[u],l),{}),e.on("input",this._eventHandlers.preOnInput.bind(this)),e.on("close",this._eventHandlers.preOnClose.bind(this));const{jsonataService:i,nodeRedContextService:a,typedInputService:d}=S(this.node,this.homeAssistant),p=new y(this.server?.config?.ha_boolean);this.comparatorService=new m({jsonataService:i,nodeRedContextService:a,homeAssistant:this.homeAssistant,transformState:p}),this.nodeRedContextService=a,this.jsonataService=i,this.typedInputService=d,this.transformState=p;const g=c("nodeConfig.name",this);this.node.debug(`instantiated node, name: ${g||"undefined"}`)}get server(){return this?.nodeConfig?.server}get homeAssistant(){return I(this.server)}get isConnected(){return this.homeAssistant&&this.homeAssistant.isConnected}get isHomeAssistantRunning(){return this.isConnected&&this.homeAssistant.isHomeAssistantRunning}get isIntegrationLoaded(){return this.isConnected&&this.homeAssistant.isIntegrationLoaded}get isEnabled(){return this.state.isEnabled()}set isEnabled(e){this.state.setEnabled(e),this.status.setNodeState(e)}onClose(e){}onInput(){}send(){this.node.send(...arguments)}sendSplit(e,t,n){n||(n=this.send),delete e._msgid,e.parts={id:this.RED.util.generateId(),type:"array",count:t.length,len:1};let s=0;for(let r=0;r<t.length;r++)e.payload=t.slice(s,s+1)[0],e.parts.index=r,s+=1,n(this.RED.util.cloneMessage(e))}debugToClient(e,t="sent data"){b(this.node,e,t)}getCastValue(e,t){return this.transformState.transform(e,t)}castState(e,t){e&&(e.original_state=e.state,e.state=this.getCastValue(t,e.state))}setContextValue(e,t,n,s){this.nodeRedContextService.set(e,t,n,s)}async getComparatorResult(e,t,n,s,{message:r,entity:i,prevEntity:a}){return this.comparatorService.getComparatorResult(e,t,n,s,{message:r,entity:i,prevEntity:a})}async evaluateJSONata(e,t={}){return this.jsonataService.evaluate(e,t)}async getTypedInputValue(e,t,n={}){return this.typedInputService.getValue(e,t,n)}async setCustomOutputs(e=[],t,n){for(const s of e){const r=await this.getTypedInputValue(s.value,s.valueType,{message:t,...n});try{this.nodeRedContextService.set(r,s.propertyType,s.property,t)}catch(i){this.node.warn(`Custom Ouput Error (${s.propertyType}:${s.property}): ${i.message}`)}}}}const f={parseInputMessage(o,e){if(!o)return;const t={};for(const[n,s]of Object.entries(o)){const r=Array.isArray(s.messageProp)?s.messageProp.reduce((a,d)=>a||c(d,e),void 0):c(s.messageProp,e),i={key:n,value:r,source:"message",validation:null};if(i.value===void 0&&s.configProp&&(i.value=c(s.configProp,this.nodeConfig),i.source="config"),i.value===void 0&&s.default!==void 0&&(i.value=typeof s.default=="function"?s.default.call(this):s.default,i.source="default"),i.value===void 0&&(i.source="missing"),s.validation){const{error:a,value:d}=s.validation.schema.validate(i.value,{convert:!0});if(a&&s.validation.haltOnFail)throw a;i.validation={error:a,value:d}}t[n]=i}return t}},E={preOnInput(o,e,t){try{const n=f.parseInputMessage.call(this,this.options.input,o);this.onInput({parsedMessage:n,message:o,send:e,done:t})}catch(n){if(n&&n.isJoi){this.status.setFailed("Error"),t(n.message);return}throw n}},async preOnClose(o,e){this.node.debug(`closing node. Reason: ${o?"node deleted":"node re-deployed"}`);try{await this.onClose(o),e()}catch(t){this.node.error(t.message)}}};module.exports=R;