Control your KNX intallation via Node.js!
KNX IP protocol implementation in pure Node.js
This is the official engine of Node-Red node KNX-Ultimate (https://flows.nodered.org/node/node-red-contrib-knx-ultimate)
I had many users asking for a node.js release of that engine, so here is it.
The node will be KNX Secure compatible. I'm already working on that.
Here the usage sample (you can find this sample in the "sample.js" file):
const knx = require("./index.js");
const dptlib = require('./src/dptlib');
let knxUltimateClientProperties = {
ipAddr: "224.0.23.12",
ipPort: "3671",
physAddr: "1.1.100",
suppress_ack_ldatareq: false,
loglevel: "error",
localEchoInTunneling: true,
hostProtocol: "Multicast",
isSecureKNXEnabled: false,
jKNXSecureKeyring: "",
localIPAddress: "",
KNXEthInterface: "Auto",
};
const knxUltimateClient = new knx.KNXClient(knxUltimateClientProperties);
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.indication, handleBusEvents);
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.error, err => {
console.log("Error", err)
});
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.disconnected, info => {
console.log("Disconnected", info)
});
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.close, info => {
console.log("Closed", info)
});
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.connected, info => {
console.log("Connected. On Duty", info)
});
knxUltimateClient.on(knx.KNXClient.KNXClientEvents.connecting, info => {
console.log("Connecting...", info)
});
knxUltimateClient.Connect();
function handleBusEvents(_datagram, _echoed) {
let _evt = "";
if (_datagram.cEMIMessage.npdu.isGroupRead) _evt = "GroupValue_Read";
if (_datagram.cEMIMessage.npdu.isGroupResponse) _evt = "GroupValue_Response";
if (_datagram.cEMIMessage.npdu.isGroupWrite) _evt = "GroupValue_Write";
console.log("src: " + _datagram.cEMIMessage.srcAddress.toString() + " dest: " + _datagram.cEMIMessage.dstAddress.toString(), " event: " + _evt);
}
sortBy = (field) => (a, b) => {
if (a[field] > b[field]) { return 1 } else { return -1 }
};
onlyDptKeys = (kv) => {
return kv[0].startsWith("DPT")
};
extractBaseNo = (kv) => {
return {
subtypes: kv[1].subtypes,
base: parseInt(kv[1].id.replace("DPT", ""))
}
};
convertSubtype = (baseType) => (kv) => {
let value = `${baseType.base}.${kv[0]}`;
let sRet = value + " " + kv[1].name;
return {
value: value
, text: sRet
}
}
toConcattedSubtypes = (acc, baseType) => {
let subtypes =
Object.entries(baseType.subtypes)
.sort(sortBy(0))
.map(convertSubtype(baseType))
return acc.concat(subtypes)
};
dptGetHelp = dpt => {
var sDPT = dpt.split(".")[0];
var jRet;
if (sDPT == "0") {
jRet = {
"help":
`// KNX-Ultimate set as UNIVERSAL NODE
// Example of a function that sends a message to the KNX-Ultimate
msg.destination = "0/0/1"; // Set the destination
msg.payload = false; // issues a write or response (based on the options Output Type above) to the KNX bus
msg.event = "GroupValue_Write"; // "GroupValue_Write" or "GroupValue_Response", overrides the option Output Type above.
msg.dpt = "1.001"; // for example "1.001", overrides the Datapoint option. (Datapoints can be sent as 9 , "9" , "9.001" or "DPT9.001")
return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki"
};
res.json(jRet);
return;
}
jRet = { "help": "NO", "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome" };
const dpts =
Object.entries(dptlib)
.filter(onlyDptKeys)
for (let index = 0; index < dpts.length; index++) {
if (dpts[index][0].toUpperCase() === "DPT" + sDPT) {
jRet = { "help": (dpts[index][1].basetype.hasOwnProperty("help") ? dpts[index][1].basetype.help : "NO"), "helplink": (dpts[index][1].basetype.hasOwnProperty("helplink") ? dpts[index][1].basetype.helplink : "https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome") };
break;
}
}
return (jRet);
}
const dpts =
Object.entries(dptlib)
.filter(onlyDptKeys)
.map(extractBaseNo)
.sort(sortBy("base"))
.reduce(toConcattedSubtypes, [])
dpts.forEach(element => {
console.log(element.text + " USAGE: " + dptGetHelp(element.value).help);
console.log(" ");
});
console.log("WARNING: I'm about to write to your BUS in 10 seconds! Press Control+C to abort!")
console.log("WARNING: I'm about to write to your BUS in 10 seconds! Press Control+C to abort!")
console.log("WARNING: I'm about to write to your BUS in 10 seconds! Press Control+C to abort!")
console.log("WARNING: I'm about to write to your BUS in 10 seconds! Press Control+C to abort!")
console.log("WARNING: I'm about to write to your BUS in 10 seconds! Press Control+C to abort!")
setTimeout(() => {
let payload = true;
knxUltimateClient.write("0/1/1", payload, "1.001");
payload = { red: 125, green: 0, blue: 0 };
knxUltimateClient.write("0/1/2", payload, "232.600");
knxUltimateClient.read("0/0/1");
payload = false;
knxUltimateClient.respond("0/0/1", payload, "1.001");
}, 10000);