UNPKG

@smappee/node-red-contrib-smappee

Version:

Smappee Node-RED contains Smappee nodes and example flows

150 lines (122 loc) 3.67 kB
const MqttClient = require('./MqttClient'); /** * Subscriber class for a MQTT connection to a Smappee device. */ class NodeConnection { constructor(node, broker, RED) { this.node = node; this.broker = broker; this.RED = RED; this.messageHandlers = new Map(); } connect(callback = this.connectCallback.bind(this)) { const node = this.node; // Return if a connection is active already if (this.client && this.client.isActive()) { return; } // Create the client this.client = new MqttClient(this.broker); // Connect via MQTT this.client.connect(callback); // Disconnects the client after closing the node node.on('close', function() { if (this.client) { this.disconnect(); } }.bind(this)); // Bind the message handler this.client.handleMessage = this.handleMessage.bind(this); } connectCallback() { this.node.log('Connected to: ' + this.broker); } disconnect() { this.client.disconnect(); this.client = undefined; this.node.log('Disconnected from: ' + this.broker); // Make sure the subscribed nodes show as disconnected for (let key of this.messageHandlers) { if (this.messageHandlers.hasOwnProperty(key)) { const handler = this.messageHandlers[key]; if (handler) { handler.status({fill: 'red', shape: 'dot', text: 'disconnected'}); } } } } /** * Sets a handler for each topic and then subscribes to it. * @param topic * @param handler */ subscribe(topic, handler) { this.connect(); // Keep a list of handlers this.messageHandlers.set(topic, (this.messageHandlers.get(topic) || []).concat(handler)); // Set the status if possible if (typeof handler === 'object' && handler.status) { handler.status({fill: 'grey', shape: 'dot', text: 'connecting'}); } this.client.subscribe(topic); } /** * Unsubscribes a handler from a certain topic * @param topic * @param handler */ unsubscribe(topic, handler) { const handlers = this.messageHandlers.get(topic); const index = handlers.indexOf(handler); if (index > -1) { this.messageHandlers.set(topic, handlers.splice(index, 1)); } } /** * Publishes a message to a certain topic. * @param topic * @param message */ publish(topic, message) { this.connect(); this.client.publish(topic, message); } /** * Only sends the node payload if the topic is relevant. * @param topic * @param message */ handleMessage(topic, message) { let handlers = this.messageHandlers.get(topic) || []; // Consider handlers that listen to wildcards for (let [key, value] of this.messageHandlers) { if (key.indexOf('+') !== -1 || key.indexOf('#') !== -1) { const regex = new RegExp(key.replace(/\+|#/, '.*')); // See if the topic matches the regular expression if (regex.test(topic)) { handlers = handlers.concat(value); } } } // Loop over the handlers for (let handler of handlers) { if (typeof handler === 'function') { handler(message); } else if (typeof handler === 'object') { const deviceConfig = {}; if (handler.device) { deviceConfig.uuid = handler.device.uuid; deviceConfig.serial = handler.device.serial; } handler.status({fill: 'green', shape: 'dot', text: 'connected'}); handler.send({ topic: topic, payload: message, device: deviceConfig, }); } } } } module.exports = NodeConnection;