node-red-contrib-deconz
Version:
deCONZ connectivity nodes for node-red
190 lines (169 loc) • 5.81 kB
JavaScript
const ConfigMigration = require("../src/migration/ConfigMigration");
const OutputMsgFormatter = require("../src/runtime/OutputMsgFormatter");
const dotProp = require("dot-prop");
const Utils = require("../src/runtime/Utils");
const NodeType = "deconz-get";
module.exports = function (RED) {
const defaultRule = {
type: "state",
format: "single",
};
const defaultConfig = {
name: "",
statustext: "",
statustext_type: "auto",
search_type: "device",
device_list: [],
device_name: "",
query: "{}",
outputs: 1,
output_rules: [defaultRule],
};
class deConzItemGet {
constructor(config) {
RED.nodes.createNode(this, config);
let node = this;
node.config = config;
node.ready = false;
node.cleanStatusTimer = null;
node.status({});
//get server node
node.server = RED.nodes.getNode(node.config.server);
if (!node.server) {
node.status({
fill: "red",
shape: "dot",
text: "node-red-contrib-deconz/get:status.server_node_error",
});
return;
}
let initNode = function () {
node.server.off("onStart", initNode);
if (node.server.migrateNodeConfiguration(node)) {
// Make sure that all expected config are defined
node.config = Object.assign({}, defaultConfig, node.config);
node.server.updateNodeStatus(node, null);
node.ready = true;
}
};
if (node.server.state.pooling.isValid === true) {
(async () => {
await Utils.sleep(1500);
initNode();
})()
.then()
.catch((error) => {
console.error(error);
});
} else {
node.server.on("onStart", initNode);
}
node.on("input", (message_in, send, done) => {
// For maximum backwards compatibility, check that send and done exists.
send =
send ||
function () {
node.send.apply(node, arguments);
};
done =
done ||
function (err) {
if (err) node.error(err, message_in);
};
(async () => {
let waitResult = await Utils.waitForEverythingReady(node);
if (waitResult) {
done(RED._(waitResult));
return;
}
let unreachableDevices = [];
let msgs = new Array(this.config.output_rules.length);
let devices = [];
switch (node.config.search_type) {
case "device":
for (let path of node.config.device_list) {
devices.push({
data: node.server.device_list.getDeviceByPath(path),
});
}
break;
case "json":
case "jsonata":
const querySrc = await new Promise((resolve, reject) => {
RED.util.evaluateJSONataExpression(
RED.util.prepareJSONataExpression(node.config.query, node),
message_in,
(err, value) => {
if (err) reject(err);
else resolve(value);
}
);
});
try {
for (let r of node.server.device_list.getDevicesByQuery(
querySrc
).matched) {
devices.push({ data: r });
}
} catch (e) {
node.status({
fill: "red",
shape: "dot",
text: "node-red-contrib-deconz/server:status.query_error",
});
done(e.toString());
return;
}
break;
}
node.config.output_rules.forEach((saved_rule, index) => {
// Make sure that all expected config are defined
const rule = Object.assign({}, defaultRule, saved_rule);
// Only if it's not on start and the start msg are blocked
// Clean up old msgs
msgs.fill(undefined);
// Format msgs, can get one or many msgs.
let formatter = new OutputMsgFormatter(rule, NodeType, node.config);
let msgToSend = formatter.getMsgs(devices, undefined, {
src_msg: RED.util.cloneMessage(message_in),
});
// Make sure that the result is an array
if (!Array.isArray(msgToSend)) msgToSend = [msgToSend];
// Send msgs
for (let msg of msgToSend) {
msgs[index] = msg;
send(msgs);
if (
dotProp.get(msg, "meta.state.reachable") === false ||
dotProp.get(msg, "meta.config.reachable") === false
) {
let device_path = dotProp.get(msg, "meta.device_path");
if (device_path && !unreachableDevices.includes(device_path)) {
done(
`Device "${dotProp.get(
msg,
"meta.name"
)}" is not reachable.`
);
unreachableDevices.push(device_path);
}
}
}
// Update node status
if (index === 0) node.server.updateNodeStatus(node, msgToSend);
});
if (node.config.statustext_type === "auto")
node.cleanStatusTimer = setTimeout(function () {
node.status({}); //clean
}, 3000);
if (unreachableDevices.length === 0) done();
})()
.then()
.catch((error) => {
console.error(error);
});
});
}
}
RED.nodes.registerType(NodeType, deConzItemGet);
};