smithtek-nodered
Version:
NodeRED node to post data on SmithTek using MQTT.
137 lines (118 loc) • 4.83 kB
JavaScript
const mqtt = require("mqtt");
const fs = require("fs").promises; // Use promise-based fs methods
const path = require("path");
function defineOutputObject(topic, message) {
let finalValue;
let variable = topic;
if (topic.endsWith("/lv")) {
variable = topic.slice(0, topic.length - 3);
}
const topicElements = variable.split("/");
variable = topicElements[topicElements.length - 1];
finalValue = parseOutputValue(topic, variable, message);
return finalValue;
}
function parseOutputValue(topic, variable, message) {
let finalValue;
try {
const parsedMessage = JSON.parse(message.toString());
finalValue = topic.endsWith("/lv")
? parsedMessage
: parsedMessage[variable] && parsedMessage[variable].value;
} catch (err) {
console.error("Error parsing message:", err);
}
return finalValue;
}
function getSubscribePaths(config) {
const paths = [];
const labelString = "label_variable_";
const checkboxString = "checkbox_variable_";
const checkboxString2 = "_last_value";
for (let i = 1; i < 11; i++) {
const completeLabelString = labelString + i.toString();
const completeCheckboxString = checkboxString + i.toString() + checkboxString2;
if (config[completeLabelString]) {
let devicePath = `/v1.6/devices/${config.device_label}/${config[completeLabelString]}`;
if (config[completeCheckboxString]) {
devicePath += "/lv";
}
paths.push(devicePath);
}
}
return paths;
}
module.exports = function (RED) {
function SmithTekNode(config) {
RED.nodes.createNode(this, config);
const ENDPOINTS_URLS = {
business: "industrial.api.ubidots.com",
};
const useTLS = config.tls_checkbox_in;
const endpointUrl = ENDPOINTS_URLS.business;
const URL_PREFIX = "mqtt://";
const port = 1883;
const portTLS = 8883;
const topics = getSubscribePaths(config);
this.status({ fill: "green", shape: "ring", text: "Disconnected" });
fs.readFile(path.join(__dirname, "../keys/certificate.pem"), "utf8")
.then(certificate => {
const client = mqtt.connect(URL_PREFIX + endpointUrl, {
username: config.token,
password: "",
port: useTLS ? portTLS : port,
cert: useTLS ? certificate : undefined,
protocol: useTLS ? "mqtts" : "mqtt",
reconnectPeriod: 10000
});
client.on("connect", () => {
this.status({ fill: "green", shape: "dot", text: "Connected" });
const options = { qos: 1 };
client.subscribe(topics, options);
});
client.on("message", (topic, message) => {
const finalValue = defineOutputObject(topic, message);
try {
this.emit("input", { payload: finalValue });
} catch (e) {
console.error("Error when trying to emit:", e);
this.status({ fill: "red", shape: "ring", text: "Disconnected" });
}
});
const handleDisconnect = () => {
client.unsubscribe(topics);
this.status({ fill: "red", shape: "ring", text: "Disconnected" });
};
client.on("close", handleDisconnect);
client.on("error", handleDisconnect);
client.on("reconnect", handleDisconnect);
this.on("error", (msg) => {
console.error("SmithTek Client: Inside error function", msg);
if (client) {
client.end(true);
}
this.status({ fill: "red", shape: "ring", text: "Disconnected" });
});
this.on("close", () => {
if (client) {
client.end(true);
}
});
this.on('input', (msg, send, done) => {
try {
send(msg);
} catch (err) {
console.error('Error in client when sending data to debug node,', err);
this.error(err, msg);
}
if (done) {
done();
}
});
})
.catch(err => {
console.error("Error reading certificate:", err);
});
}
RED.nodes.registerType("smithtek_in", SmithTekNode);
};