node-red-contrib-xmihome
Version:
Node-RED nodes for controlling Xiaomi Mi Home devices using the xmihome library.
2 lines (1 loc) • 2.75 kB
JavaScript
import O from"xmihome";import{CACHE_TTL as Q}from"xmihome/constants.js";var J=new Map;class K{#F;#k;#B;#z;devices=new Map;subscriptions=new Map;disconnectTimers=new Map;endpoint;deviceCache={devices:[],timestamp:0,error:null};constructor(z,B,k){this.#k=z,this.#B=B,this.#F=k,this.endpoint=`/xmihome/${this.#k.id}/devices`,this.#F.httpAdmin.get(this.endpoint,k.auth.needsPermission("xmihome-config.read"),this.#G.bind(this)),this.#k.on("close",this.#J.bind(this))}get client(){if(!this.#z)this.#z=new O({credentials:this.#k.credentials,connectionType:this.#B.connectionType==="auto"?null:this.#B.connectionType,logLevel:this.#B.debug?"debug":"none"});return this.#z}async getDevices(z=!1,B=void 0){if(J.has(this.#k.id))return this.#k.debug("Device refresh already in progress, returning existing promise."),J.get(this.#k.id);let k=Date.now();if(!z&&this.deviceCache.devices.length>0&&k-this.deviceCache.timestamp<Q)return this.#k.debug("Using cached device list (TTL not expired)."),Promise.resolve(this.deviceCache.devices);this.#k.debug(`Initiating device cache refresh (force=${z})...`),this.deviceCache.error=null;let F=(async()=>{try{let G=await this.client.getDevices({...B&&{timeout:B}});return this.deviceCache.devices=G||[],this.deviceCache.timestamp=Date.now(),this.#k.log(`Device cache refreshed. Found ${this.deviceCache.devices.length} devices.`),this.deviceCache.devices}catch(G){throw this.#k.error(`Failed to refresh device cache: ${G.message}`,G),this.deviceCache.error=G.message||"Unknown error",G}finally{J.delete(this.#k.id),this.#k.debug("Refresh promise removed.")}})();return J.set(this.#k.id,F),this.#k.debug("Refresh promise created and stored."),F}async#G(z,B){try{await this.getDevices(z.query.force==="true"),B.json({devices:this.deviceCache.devices,loading:J.has(this.#k.id),error:this.deviceCache.error,timestamp:this.deviceCache.timestamp})}catch(k){B.status(500).json({devices:this.deviceCache.devices,loading:!1,error:k.message||"Failed to refresh device list",timestamp:this.deviceCache.timestamp})}}async#J(z,B){this.#k.debug(`Closing config node ${this.#k.id} (removed: ${!!z})`),J.delete(this.#k.id);let k=this.#F.httpAdmin._router.stack;for(let F=k.length-1;F>=0;F--)if(k[F].route?.path===this.endpoint){k.splice(F,1),this.#k.debug(`Removed HTTP admin route: ${this.endpoint}`);break}if(this.#z)try{await this.#z.destroy(),this.#k.log("XiaomiMiHome client destroyed.")}catch(F){this.#k.error(`Error destroying client: ${F.message}`)}finally{this.#z=null}B()}}function S(z){z.nodes.registerType("xmihome-config",function(B){z.nodes.createNode(this,B);let k=this;k.instance=new K(k,B,z)},{credentials:{username:{type:"text"},password:{type:"password"},country:{type:"text"}}})}export{S as default,K as ConfigNode};