UNPKG

node-red-contrib-google-smarthome

Version:

Lets you control Node-Red via Google Assistant or the Google Home App

184 lines (159 loc) 7.37 kB
/** * node-red-contrib-google-smarthome * Copyright (C) 2024 Michael Jacobsen and others. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ module.exports = function (RED) { "use strict"; /****************************************************************************************************************** * * */ class MgmtNode { constructor(config) { RED.nodes.createNode(this, config); this.client = config.client; /** @type {GoogleSmartHomeNode} */ this.clientConn = RED.nodes.getNode(this.client); if (!this.clientConn) { this.error(RED._("googlemanagement.errors.missing-config")); this.status({ fill: "red", shape: "dot", text: "Missing config" }); return; } else if (typeof this.clientConn.register !== 'function') { this.error(RED._("googlemanagement.errors.missing-bridge")); this.status({ fill: "red", shape: "dot", text: "Missing SmartHome" }); return; } this.set_state_type = config.set_state_type || 'filtered_by_id'; this.clientConn.register(this, 'mgmt', config.name); this.status({ fill: "yellow", shape: "dot", text: "Ready" }); this.on('input', this.onInput); this.on('close', this.onClose); } _debug(msg) { if (this.clientConn.enabledebug) { console.log(msg) } else { RED.log.debug(msg); } } /****************************************************************************************************************** * called when state is updated from Google Assistant * */ updated(data) { // this must be defined before the call to clientConn.register() const me = this; me._debug("MgmtNode(updated): data = " + JSON.stringify(data)); let msg = { topic: "management", payload: data }; me.send(msg); } /** * respond to inputs from NodeRED * * @param {object} msg - The incoming message * @param {Function} send - Function to send outgoing messages * @param {Function} done - Function to inform the runtime that this node has finished its operation */ onInput(msg, send, done) { const me = this; me._debug("MgmtNode(input)"); let topicArr = (msg.topic || '').split(me.topicDelim); let topic = topicArr[topicArr.length - 1]; // get last part of topic const topic_upper = topic.toUpperCase(); me._debug("MgmtNode(input): topic = " + topic); try { if (topic_upper === 'RESTART_SERVER') { me._debug("MgmtNode(input): RESTART_SERVER"); this.clientConn.app.Restart(RED.httpNode || RED.httpAdmin, RED.server); } else if (topic_upper === 'REPORT_STATE') { me._debug("MgmtNode(input): REPORT_STATE"); this.clientConn.app.ReportAllStates(); } else if (topic_upper === 'REQUEST_SYNC') { me._debug("MgmtNode(input): REQUEST_SYNC"); this.clientConn.app.RequestSync(); } else if (topic_upper === 'GET_STATE' || topic_upper === 'GETSTATE') { let onlyPersistent = ['filtered_by_id', 'filtered_by_name'].includes(me.set_state_type ); let useNames = ['all_by_name', 'filtered_by_name'].includes(me.set_state_type ); let deviceIds = undefined; if (typeof msg.payload === 'boolean') { onlyPersistent = msg.payload; } else if (typeof msg.payload === 'string') { deviceIds = [msg.payload]; } else if (Array.isArray(msg.payload)) { deviceIds = msg.payload; } else if (typeof msg.payload === 'object') { if (typeof msg.payload.onlyPersistent === 'boolean') { onlyPersistent = msg.payload.onlyPersistent; } if (typeof msg.payload.useNames === 'boolean') { useNames = msg.payload.useNames; } if (typeof msg.payload.devices === 'string') { deviceIds = [msg.payload.devices]; } else if (Array.isArray(msg.payload.devices)) { deviceIds = msg.payload.devices; } } let states = this.clientConn.app.devices.getStates(deviceIds, onlyPersistent, useNames); if (states) { send({ topic: topic, payload: states }); } } else if (topic_upper === 'SET_STATE' || topic_upper === 'SETSTATE') { if (typeof msg.payload === 'object') { this.clientConn.app.devices.setStates(msg.payload); } } done(); } catch (err) { done(err); } } /** * Called by the runtime when this node is being removed or restarted * * @param {boolean} removed - true if the is being removed, false on restart * @param {Function} done - Function to inform the runtime that this node has finished its operation */ onClose(removed, done) { if (removed) { // this node has been deleted this.clientConn.remove(this, 'mgmt'); } else { // this node is being restarted this.clientConn.deregister(this, 'mgmt'); } done(); } sendSetState() { if (this.set_state_type === 'no_nodes') return; let onlyPersistent = ['filtered_by_id', 'filtered_by_name'].includes(this.set_state_type); let useNames = ['all_by_name', 'filtered_by_name'].includes(this.set_state_type); let states = this.clientConn.app.devices.getStates(undefined, onlyPersistent, useNames); if (states) { this.send({ topic: 'set_state', payload: states }); } } } RED.nodes.registerType("google-mgmt", MgmtNode); }