UNPKG

node-red-contrib-netpie

Version:

Node-RED module for connecting to NETPIE IoT Platform

235 lines (205 loc) 7.99 kB
module.exports = function(RED) { const axios = require('axios'); const feedtime = require('feedtime'); const CONFIG = require('./config'); function convert_feed_data(resobj, type) { let out = { series: [], data: [], labels: [] } if (type == 'node-red-dashboard') { let slist = resobj.queries[0].results; for (let s of slist) { if (s.tags && s.tags.attr) { out.series.push(s.tags.attr[0]); out.data.push( s.values.map(item => { return { x: item[0], y:item[1] } })); } } } return [out]; } function Feed(config) { RED.nodes.createNode(this, config); let node = this; let current = {}; let eventlist = {}; function addListener(obj, event, callback) { if (eventlist[event]) return; eventlist[event] = 1; obj.on(event, callback) } const deviceConfigNode = RED.nodes.getNode(config.deviceconfig); let flowchannelmqtt = deviceConfigNode.flowchannelmqtt; if (!deviceConfigNode) { node.error("Device configuration node not found."); return; } config.deviceid = deviceConfigNode.deviceid; config.devicetoken = deviceConfigNode.devicetoken; if (!config.deviceid || !config.devicetoken) { node.error("deviceid and devicetoken are required."); return; } config.api_endpoint = CONFIG.NETPIE.apihost; config.ds_endpoint = CONFIG.NETPIE.dshost; const useFlowChannel = deviceConfigNode.flowchannelmqtt ; current.towatch = config.subfeedupdated && useFlowChannel; function updateNodeStatus(current) { let color, shape, text; if (current.towatch) { if (current.clientstatus) { shape = 'dot'; color = 'green'; text = 'watching'; } else { color = 'grey'; text = ''; shape = 'ring'; } } else { color = 'white'; text = ''; shape = null; } node.status({fill: color, shape: shape, text: text}) } if (config.active && config.subfeedupdated && useFlowChannel) { function initializeFeed() { current.clientstatus = 1; node.log('feed connected'); updateNodeStatus(current); } if (deviceConfigNode.isConnected()) { initializeFeed(); } else { addListener(deviceConfigNode, `connect`, initializeFeed); } addListener(deviceConfigNode, `disconnect`, function() { current.clientstatus = 0; node.log('feed disconnected'); updateNodeStatus(current); }); addListener(deviceConfigNode, `feed/data/updated:${config.deviceid}`, function(payload) { if (payload && payload.newdata) { for (let key in payload.newdata) { let msg = { topic: key, payload: payload.newdata[key], timestamp: payload.timestamp } node.send(msg); } } }); addListener(deviceConfigNode, `error`, function(error) { node.error(error); }); } else { updateNodeStatus(current); } node.on('close', function(done){ current.clientstatus = 0; updateNodeStatus(current); setTimeout(() => { done(); }, 500); }); node.on('input', function(msg) { let begints, endts; // Parse begin timestamp if (config.beginabsolutedatepropertyType == 'msg' && config.beginabsolutedateproperty !== undefined) { let field = 'from'; begints = feedtime.parse(msg[field]); } else if (config.beginabsolutedatepropertyType == 'datetime' && config.beginabsolutedateproperty !== undefined ) { begints = feedtime.parse(config.beginabsolutedateproperty); } else if (config.beginabsolutedatepropertyType == 'str' && config.beginabsolutedateproperty !== undefined) { begints = feedtime.parse(config.beginabsolutedateproperty); } if (!begints) { begints = { value: Number(config.beginrelativevalue) || 0, unit: config.beginrelativeunit } } // Parse end timestamp if (config.endabsolutedatepropertyType == 'msg' && config.endabsolutedateproperty !== undefined) { let field = 'to'; endts = feedtime.parse(msg[field]); } else if (config.endabsolutedatepropertyType == 'datetime' && config.endabsolutedateproperty !== undefined) { endts = feedtime.parse(config.endabsolutedateproperty); } else if (config.endabsolutedatepropertyType == 'str' && config.endabsolutedateproperty !== undefined) { endts = feedtime.parse(config.endabsolutedateproperty); } if (!endts) { endts = { value: Number(config.endrelativevalue) || 0, unit: config.endrelativeunit } if (endts.value == 0) { endts = Date.now(); } } // Build query object let cmdobj = { metrics: [ { name: config.deviceid, group_by: [ { name: "tag", tags: [ "attr" ] } ], aggregators : [ { name: 'avg', sampling: { value: config.samplingvalue, unit: config.samplingunit } } ] } ] } // Set time ranges if (typeof(begints) == 'number') { cmdobj.start_absolute = begints || Date.now(); } else if (typeof(begints) == 'object') { cmdobj.start_relative = begints; } if (typeof(endts) == 'number') { cmdobj.end_absolute = endts || Date.now(); } else if (typeof(endts) == 'object') { cmdobj.end_relative = endts; } // Execute query via REST API let axiosobj = { method: 'post', url: `${config.ds_endpoint}/feed/api/v1/datapoints/query`, data: cmdobj, responseType: 'json', headers: {'Authorization': `Device ${config.deviceid}:${config.devicetoken}`} } axios(axiosobj).then((response) => { msg.payload = convert_feed_data(response.data, 'node-red-dashboard'); node.send(msg); }).catch((error) => { node.error('Feed query error: ' + error.message); }); }); } RED.nodes.registerType("feed", Feed); };