node-red-contrib-knx-ultimate
Version:
Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable.
177 lines (157 loc) • 8.04 kB
JavaScript
module.exports = function (RED) {
// msg is:
// // Build final input message object
// return {
// topic: _outputtopic
// , payload: jsValue
// , devicename: (typeof _devicename !== 'undefined') ? _devicename : ""
// , payloadmeasureunit: sPayloadmeasureunit
// , payloadsubtypevalue: sPayloadsubtypevalue
// , knx:
// {
// event: _event
// , dpt: sInputDpt
// //, details: dpt
// , dptdesc: sDptdesc
// , source: _srcGA
// , destination: _destGA
// , rawValue: _Rawvalue
// }
// };
// The node.exposedGAs is and array of:
// {
// address,
// dpt,
// payload
// }
function knxUltimateGlobalContext(config) {
RED.nodes.createNode(this, config)
var node = this;
node.server = RED.nodes.getNode(config.server)
node.topic = node.name;
node.name = config.name === undefined ? "KNXGlobalContext" : config.name;
node.outputtopic = node.name;
node.dpt = "";
node.notifyreadrequest = false
node.notifyreadrequestalsorespondtobus = "false";
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = "";
node.notifyresponse = true;
node.notifywrite = true;
node.initialread = false
node.listenallga = true;
node.outputtype = "write";
node.outputRBE = false // Apply or not RBE to the output (Messages coming from flow)
node.inputRBE = false // Apply or not RBE to the input (Messages coming from BUS)
node.currentPayload = "" // Current value for the RBE input and for the .previouspayload msg
node.passthrough = "no";
node.formatmultiplyvalue = 1;
node.formatnegativevalue = "leave";
node.formatdecimalsvalue = 999;
node.writeExecutionInterval = config.writeExecutionInterval === undefined ? 1000 : config.writeExecutionInterval;
node.exposeAsVariable = config.exposeAsVariable !== undefined ? config.exposeAsVariable : "exposeAsVariableREADONLY"; // Should expose the Group Addresses to the Global Context?
node.exposedGAs = [];
node.timerExposedGAs = null;
// Used to call the status update from the config node.
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
if (node.server == null) { node.status({ fill: "red", shape: "dot", text: "[NO GATEWAY SELECTED]" }); return; }
GA = GA === undefined ? "" : GA;
payload = payload === undefined ? "" : payload;
var dDate = new Date();
node.status({ fill: fill, shape: shape, text: GA + " " + payload + " " + text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" });
}
// exposeAsVariableREADWRITE
//#region "WRITE TO BUS"
goTimerGo = () => {
if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs); // 21/03/2021
node.timerExposedGAs = setTimeout(() => {
var oContext = node.context().global.get(node.name + "_WRITE") || [];
node.context().global.set(node.name + "_WRITE", []); // Delete the var
for (let index = 0; index < oContext.length; index++) {
let element = oContext[index];
if (!element.hasOwnProperty("address")) {
node.setNodeStatus({ fill: "RED", shape: "dot", text: "NO Group Address set", payload: "", GA: "", dpt: "", devicename: "" });
RED.log.error("knxUltimateGlobalContext: No group address set in node " + node.id);
oContext = null; // 21/03/2022
goTimerGo();
return;
}
if (!element.hasOwnProperty("payload")) {
node.setNodeStatus({ fill: "RED", shape: "dot", text: "NO payload set" , payload: "", GA: "", dpt: "", devicename: ""});
RED.log.error("knxUltimateGlobalContext: No payload set for address " + element.address + " in node " + node.id);
oContext = null; // 21/03/2022
goTimerGo();
return;
}
// 13/09/2021 retrieve the datapoint if not specified
if (!element.hasOwnProperty("dpt") || element.dpt === undefined || element.dpt === "") {
try {
let sDPT = node.server.csv.find(item => item.ga === element.address).dpt;
element.dpt = sDPT;
} catch (error) {
node.setNodeStatus({ fill: "RED", shape: "dot", text: "Datapoint not found in CSV for " + element.address, payload: "", GA: "", dpt: "", devicename: "" });
RED.log.error("knxUltimateGlobalContext: Datapoint not found in CSV for address " + element.address + " in node " + node.id);
oContext = null; // 21/03/2022
goTimerGo();
return;
}
}
node.setNodeStatus({ fill: "green", shape: "dot", text: "Write", payload: element.payload, GA: element.address, dpt: element.dpt || "", devicename: "" });
node.server.writeQueueAdd({ grpaddr: element.address, payload: element.payload, dpt: element.dpt || "", outputtype: "write", nodecallerid: node.id });
}
oContext = null; // 21/03/2022
goTimerGo();
}, node.writeExecutionInterval);
}
// 21/02/2021 timer for write to BUS
if (node.exposeAsVariable === "exposeAsVariableREADWRITE") {
goTimerGo();
node.setNodeStatus({ fill: "green", shape: "dot", text: "Start Writing" , payload: "", GA: "", dpt: "", devicename: ""});
} else {
if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs);
node.context().global.set(node.name + "_WRITE", []); // Delete the var
}
//#endregion
// This function is called by the knx-ultimate config node, to output a msg.payload.
node.handleSend = msg => {
if (node.exposeAsVariable !== "exposeAsVariableNO") {
try {
var oGa = node.exposedGAs.find(ga => ga.address === msg.knx.destination);
} catch (error) {
console.log(error);
}
if (oGa === undefined) {
node.exposedGAs.push({ address: msg.knx.destination, dpt: msg.knx.dpt, payload: msg.payload });
} else {
oGa.dpt = msg.knx.dpt;
oGa.payload = msg.payload;
}
// Save into the global Context
try {
node.context().global.set(node.name + "_READ", node.exposedGAs);
} catch (error) {
console.log(error);
}
oGa = null; // 21/03/2022
} else {
node.exposedGAs = [];
node.context().global.set(node.name + "_READ", node.exposedGAs);
}
};
node.on("input", function (msg) {
})
node.on("close", function (done) {
if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs);
node.exposedGAs = [];
if (node.server) {
node.server.removeClient(node);
}
done();
})
// On each deploy, unsubscribe+resubscribe
if (node.server) {
node.server.removeClient(node);
node.server.addClient(node);
}
}
RED.nodes.registerType("knxUltimateGlobalContext", knxUltimateGlobalContext)
}