UNPKG

node-red-contrib-datacake-helpers

Version:

Node-RED nodes to interact with the Datacake GraphQL API for KPIs and device stats. Includes other helper nodes for device management.

197 lines (169 loc) 7.41 kB
const axios = require('axios'); module.exports = function(RED) { function DatacakeGraphQLDeviceNode(config) { RED.nodes.createNode(this, config); const node = this; // Get configuration node this.datacakeConfig = RED.nodes.getNode(config.datacakeConfig); this.deviceId = config.deviceId; // Store available devices from the config this.availableDevices = config.availableDevices || []; if (!this.datacakeConfig) { this.status({ fill: "red", shape: "ring", text: "Missing configuration" }); return; } this.status({ fill: "green", shape: "dot", text: "Ready" }); // Function to fetch device data from Datacake const fetchDeviceData = async () => { if (!node.deviceId) { node.error("Device ID not configured"); node.status({ fill: "red", shape: "ring", text: "Device ID not configured" }); return null; } try { const response = await axios({ url: 'https://api.datacake.co/graphql/', method: 'post', headers: { 'Content-Type': 'application/json', 'Authorization': `Token ${node.datacakeConfig.credentials.workspaceToken}` }, data: { query: ` query { device(deviceId:"${node.deviceId}") { id serialNumber verboseName location online lastHeard lastHeardThreshold currentMeasurements(allActiveFields: true) { field { id fieldName fieldType unit } value valueString } } } ` } }); if (response.data.errors) { throw new Error(response.data.errors[0].message); } return response.data; } catch (error) { node.error(`Error fetching device data: ${error.message}`); node.status({ fill: "red", shape: "ring", text: `Error: ${error.message}` }); return null; } }; // Process the raw data into a flattened structure const processDeviceData = (data) => { if (!data || !data.data || !data.data.device) return null; const device = data.data.device; // Create a base object with device information const result = { id: device.id, serialNumber: device.serialNumber, verboseName: device.verboseName, location: device.location, online: device.online, lastHeard: device.lastHeard, lastHeardThreshold: device.lastHeardThreshold }; // Add flattened measurements if (device.currentMeasurements && Array.isArray(device.currentMeasurements)) { device.currentMeasurements.forEach(measurement => { const fieldName = measurement.field.fieldName; const unit = measurement.field.unit; // Use valueString if available, otherwise use value const value = measurement.valueString !== "" ? measurement.valueString : measurement.value; // Store the raw value result[fieldName] = value; // Store field metadata result[`${fieldName}_metadata`] = { id: measurement.field.id, type: measurement.field.fieldType, unit: unit }; }); } return result; }; // Listen for incoming messages node.on('input', async function(msg, send, done) { node.status({ fill: "blue", shape: "dot", text: "Fetching data..." }); const data = await fetchDeviceData(); if (data) { const processedData = processDeviceData(data); if (processedData) { msg.payload = processedData; node.status({ fill: "green", shape: "dot", text: "Data fetched" }); send(msg); } else { node.status({ fill: "yellow", shape: "ring", text: "No valid data" }); } } if (done) { done(); } }); node.on('close', function() { // Clean up }); } // Function to dynamically fetch device list for the editor RED.httpAdmin.get('/datacakegraphql/devices', RED.auth.needsPermission('datacakegraphql.read'), async function(req, res) { if (!req.query.configId) { res.status(400).json({ error: "No config node ID provided" }); return; } const configNode = RED.nodes.getNode(req.query.configId); if (!configNode) { res.status(400).json({ error: "Config node not found" }); return; } try { const response = await axios({ url: 'https://api.datacake.co/graphql/', method: 'post', headers: { 'Content-Type': 'application/json', 'Authorization': `Token ${configNode.credentials.workspaceToken}` }, data: { query: ` query { allDevices(inWorkspace:"${configNode.workspaceUuid}", searchTags:[], searchName:"") { id serialNumber verboseName location tags online } } ` } }); if (response.data.errors) { throw new Error(response.data.errors[0].message); } res.status(200).json(response.data); } catch (error) { res.status(500).json({ error: error.message }); } }); RED.nodes.registerType("datacakegraphql-device", DatacakeGraphQLDeviceNode, { credentials: {} }); }