UNPKG

node-red-contrib-zigbee2mqtt-devices

Version:
162 lines (161 loc) 6.63 kB
"use strict"; const types_1 = require("./types"); const mqtt_1 = require("./lib/mqtt"); const nodeInit = (RED) => { const utils = require("./lib/utils.js"); const bavaria = utils.bavaria(); function DeviceConfigNodeConstructor(config) { RED.nodes.createNode(this, config); this.name = config.name; this.deviceName = config.deviceName; this.brightnessSupport = config.brightnessSupport; this.temperatureSupport = config.temperatureSupport; this.colorSupport = config.colorSupport; this.bridge = config.bridge; this.genericMqttDevice = config.genericMqttDevice; this.statusTopic = config.statusTopic; this.commandTopic = config.commandTopic; this.refreshTopic = config.refreshTopic; } RED.nodes.registerType("zigbee2mqtt-device-config", DeviceConfigNodeConstructor); function BridgeConfigConstructor(config) { RED.nodes.createNode(this, config); const EventEmitter = require("events"); const emitter = new EventEmitter(); const subscriptions = {}; const node = this; const broker = RED.nodes.getNode(config.broker); const globalContext = node.context().global; broker.register(this); broker.subscribe(`${config.baseTopic}/#`, 0, (topic, payload, packet) => { for (let key in subscriptions) { subscriptions[key].forEach(sub => { sub.invokeIfMatch(topic, payload.toString("utf8")); }); } }, this.id); this.name = config.name; this.baseTopic = config.baseTopic; this.isConnected = () => broker.connected; this.publish = (topic, payload) => { let msg = { qos: 0, retain: false, topic: topic, payload: payload }; broker.publish(msg); }; this.knownDevices = globalContext.get(`knownDevices_${node.id.replace(".", "_")}`) || []; this.getDeviceList = function (callback) { if (this.knownDevices.length === 0 && callback !== undefined) { callback(); } return this.knownDevices; }; this.subscribeDevice = function (nodeId, device, callback) { this.subscribe(nodeId, `${node.baseTopic}/${device}`, callback, true); }; this.publishDevice = function (device, msg) { if (typeof msg !== "string") { msg = JSON.stringify(msg); } this.publish(`${node.baseTopic}/${device}/set`, msg); }; this.subscribe = (nodeId, topic, callback, jsonPayload = true) => { if (!topic.startsWith(node.baseTopic)) { node.error("Can't subscribe to " + topic); return; } if (!(nodeId in subscriptions)) { subscriptions[nodeId] = []; } subscriptions[nodeId].push(new mqtt_1.MqttSubscription(topic, jsonPayload, callback)); }; this.unsubscribe = (nodeId) => { }; this.setDeviceState = (device, payload) => { if (device !== undefined && device !== "") { try { payload = JSON.stringify(payload); this.publish(`${node.baseTopic}/${device}/set`, payload); } catch (e) { console.error(e); } } }; this.refreshDevice = function (deviceName, force) { if (deviceName !== "" && deviceName !== "---" && (config.allowDeviceStatusRefresh || force)) { this.publish(`${node.baseTopic}/${deviceName}/get`, `{"state": ""}`); } }; let registeredOtaNodeId = ""; let otaCallback = () => { }; let otaDeviceCallback = () => { }; this.registerOtaNode = (nodeId, otaStatusCallback, deviceStatusCallback) => { if (registeredOtaNodeId !== "" && registeredOtaNodeId !== nodeId) { return false; } registeredOtaNodeId = nodeId; otaCallback = otaStatusCallback; otaDeviceCallback = deviceStatusCallback; return true; }; if (config.enabledLogging === true) { this.subscribe(node.id, `${config.baseTopic}/bridge/logging`, (message) => { node.error(message); if (message.level.startsWith("warn")) { node.warn(message.message); } else if (message.level.startsWith("err")) { node.error(message.message); } }); } this.subscribe(node.id, `${config.baseTopic}/bridge/state`, (message) => { function getState(message) { try { // In newer versions the state topic has an object with a state property const messageObj = JSON.parse(message); return messageObj.state; } catch (e) { // Backwards compability: in previous versions the state topic was just a string "online" return message; } } const state = getState(message); if (state === "online") { bavaria.observer.notify(node.id + "_connected"); } }, false); this.subscribe(node.id, `${config.baseTopic}/bridge/devices`, (message) => { handleDeviceMessage(message); }); function handleDeviceMessage(msg) { msg.forEach((device) => { const d = node.knownDevices.find(e => { return e.ieee_address === device.ieee_address; }); if (d) { // replace already known device const index = node.knownDevices.indexOf(d); node.knownDevices.splice(index, 1, device); } else { // new device node.knownDevices.push(device); } }); globalContext.set(`knownDevices_${node.id.replace(".", "_")}`, node.knownDevices); } node.on("close", function (done) { broker.deregister(node, done); }); } RED.nodes.registerType("zigbee2mqtt-bridge-config", BridgeConfigConstructor, { credentials: types_1.BridgeConfigCredentials, }); }; module.exports = nodeInit;