Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

knxultimate

Supergiovane3.4kMIT5.1.4TypeScript support: included

KNX IP protocol implementation for Node. This is the ENGINE of Node-Red KNX-Ultimate node.

knx, eib, knx-ultimate, knxultimate, iot, knx secure

readme

Logo

CI NPM version NPM downloads per month NPM downloads total MIT License JavaScript Style Guide Youtube

Control your KNX intallation via Node.js. It includes also KNX IP Secure and Data Secure!

This is the official engine of Node-Red's node node-red-contrib-knx-ultimate

Many of you asked for a node.js release of that engine, so i decided to create this package.

If you enjoy my work developing this package, do today a kind thing for someone too. This will be the reward for my work.


  npm i knxultimate

Logo






Authorized KNX logo by KNX Association*

CHANGELOG

Technology Supported
KNX Tunnelling (UDP)
KNX Routing (Multicast)
KNX IP Secure/Data secure

Please subscribe to my channel, to learn how to use it Youtube

Donate via PayPal

CONNECTION SETUP

These are the properties you can pass to KNXClient (see examples for full usage):

Property Applies to Description
hostProtocol (string) all One of: "TunnelUDP" (plain tunnelling via UDP), "Multicast" (plain routing via multicast 224.0.23.12), "TunnelTCP" (KNX/IP Secure tunnelling over TCP).
ipAddr (string) all KNX/IP peer address. Use "224.0.23.12" for routing (multicast), or the interface/router IP for tunnelling.
ipPort (number/string) all KNX/IP port. Default 3671.
physAddr (string) Optional all Source IA on bus (e.g. "1.1.200"). Multicast: required. TunnelUDP: used as cEMI source. TunnelTCP (secure): ignored as bus source — the gateway assigns the tunnel IA; Data Secure uses the interface IA from ETS for authentication.
loglevel (string) all One of: disable, error, warn, info, debug, trace.
localIPAddress (string) all Optional. Binds the local UDP/TCP socket to a specific local interface IP. Useful with multiple NICs.
interface (string) all Optional. Local interface name to select the NIC (alternative to localIPAddress).
KNXQueueSendIntervalMilliseconds (number) all Optional. Inter‑telegram delay in ms. Default ~25ms. Don’t go below 20ms.
suppress_ack_ldatareq (bool) tunnelling (UDP/TCP) Optional. Avoid requesting/handling L_DATA_REQ bus ACK in tunnelling. Leave false unless your interface needs it.
theGatewayIsKNXVirtual (bool) tunnelling Optional. Special handling for ETS KNX Virtual (adds localIPAddress to tunnel endpoint). Default false.
isSecureKNXEnabled (bool) secure tunnelling & secure routing Enable KNX/IP Secure. With TunnelTCP: session handshake + Secure Wrapper. With Multicast: secure routing (Secure Wrapper, timer sync).
secureTunnelConfig (object) secure tunnelling & secure routing KNX Secure configuration. See below.
secureRoutingWaitForTimer (bool) secure routing (multicast) Optional. Wait for first timer sync (0955/0950) before sending. Default true.

Secure configuration object (secureTunnelConfig):

Field Description
tunnelInterfaceIndividualAddress (string) Optional Interface IA as in ETS. TunnelTCP: if unset/empty the client auto‑selects a usable tunnel from the ETS keyring (tries in sequence until auth/connect succeed) and uses it. Multicast: not used.
knxkeys_file_path (string) Path to ETS keyring .knxkeys file.
knxkeys_password (string) ETS project password to decrypt the keyring.
tunnelUserPassword (string) Optional Provide the KNX Secure tunnel password directly (no .knxkeys). Enables secure tunnelling only; Data Secure and secure routing stay disabled.
tunnelUserId (number) Optional KNX Secure tunnel user ID. Defaults to 2. Useful when your gateway uses a custom account.

Note on KNX Secure: KNXClient supports KNX/IP Secure for both tunnelling (TCP) and routing (multicast). Group Addresses found in the ETS keyring are protected with Data Secure; GA not in the keyring remain plain. With tunnelUserPassword alone you still get secure tunnelling, but Data Secure and secure multicast are unavailable.

SUPPORTED DATAPOINTS

For each Datapoint, there is a sample on how to format the payload (telegram) to be passed.

For example, pass a true for datapoint "1.001", or { red: 125, green: 0, blue: 0 } for datapoint "232.600".

It support a massive number of Datapoints. Please run the examples/showDatapoints.ts file to view all datapoints in the output console.

Be aware, that the descriptions you'll see, are taken from Node-Red KNX-Ultimate node, so there is more code than you need here. Please take only the msg.payload part in consideration.

You should see something like this in the console window (the msg.payload is what you need to pass as payload):

METHODS/PROPERTIES OF KNXULTIMATE

Method Description
.Connect() Connects to the KNX Gateway
.Disconnect() Gracefully disconnects from the KNX Gateway
.write (GA, payload, datapoint) Sends a WRITE telegram to the BUS. GA is the group address (for example "0/0/1"), payload is the value you want to send (for example true), datapoint is a string representing the datapoint (for example "5.001")
.writeRaw (GA, payload, datapoint) Sends a WRITE telegram to the BUS. GA is the group address (for example "0/0/1"), payload is the buffer you want to send, datapoint is a string representing the datapoint (for example "5.001")
.respond (GA, payload, datapoint) Sends a RESPONSE telegram to the BUS. GA is the group address (for example "0/0/1"), payload is the value you want to send (for example true), datapoint is a string representing the datapoint (for example "5.001")
.read (GA) Sends a READ telegram to the BUS. GA is the group address (for example "0/0/1").
. discover() Sends a discover request on the KNX default multicast port and returns the results as an array. This is an async method. See the example in the examples folder
.getGatewayDescription() Sends a gateway description request. It works after an established connection. The async results will be sent to the descriptionResponse event. There is an example in the examples folder named gatewaydescription.ts .
Property Description
.isConnected() Returns true if you the client is connected to the KNX Gateway Router/Interface, false if not connected.
.clearToSend true if you can send a telegram, false if the client is still waiting for the last telegram's ACK or whenever the client cannot temporary send the telegram. In tunneling mode, you could also refer to the event KNXClientEvents.ackReceived, that is fired everytime a telegram has been succesfully acknowledge or not acknowledge. See the sample.js file.
.channelID The actual Channel ID. Only defined after a successfull connection

EVENTS

List of events raised by KNXultimate, in proper order. For the signatures, please see the examples folder.

Event Description
connecting KNXUltimate is connecting to the KNX/IP Gateway. Please wait for the connected event to start sending KNX telegrams.
connected KNXUltimate has successfully connected with the KNX/IP Gateway.
indication KNXUltimate has received a KNX telegram, that's avaiable in te the datagram variable. Please see the examples.
ackReceived Ack telegram from KNX/IP Gateway has been received. This confirms that the telegram sent by KNXUltimate has reached the KNX/IP Gateway successfully.
disconnected The KNX connection has been disconnected.
close The main KNXUltimate socket has been closed.
error KNXUltimate has raised an error. The error description is provided as well.
descriptionResponse Gather the getGatewayDescription responses. There is an example in the examples folder named gatewaydescription.ts .

LOG STREAM

KNXUltimate logging is managed by Winston logger. In case you want to intercept library logs you can use our logStram exported from default entrypoint. Example:

import { logStream } from 'knxultimate'  

logStream.on('data', (log) => {  
    // handle log  
    if(log.level === 'ERROR)  
        console.log(`${log.timestamp} ${log.message}`)  
}) 
Field Description
timestamp ISO formatted date (YYYY-MM-DD HH:mm:ss.SSS)
level Log level in uppercase (ERROR, WARN, INFO, DEBUG)
label Module name in uppercase (specified when creating logger)

Plain KNX: Quick Examples

Below are short, progressively richer examples to connect in plain (non‑secure) KNX and listen or interact with the bus. Copy/paste inline; no extra files are created.

1) Minimal tunnelling (UDP) listener

import KNXClient from 'knxultimate'

const client = new KNXClient({
  hostProtocol: 'TunnelUDP',
  ipAddr: '192.168.1.117',  // your KNX/IP interface IP
  ipPort: 3671,
  loglevel: 'info',
})

client.on('connected', () => console.log('✓ Plain tunnelling connected'))
client.on('error', (e) => console.error('Error:', e.message))
client.on('disconnected', (reason) => console.log('Disconnected:', reason))

client.on('indication', (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi) return
  const src = cemi.srcAddress?.toString?.()
  const dst = cemi.dstAddress?.toString?.()
  const isWrite = cemi.npdu?.isGroupWrite
  const isResp = cemi.npdu?.isGroupResponse
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  console.log('indication', { src, dst, isWrite, isResp, raw: raw?.toString('hex') })
})

client.Connect()

2) Decode a boolean datapoint (1.001)

import KNXClient, { KNXClientEvents } from 'knxultimate'
import { dptlib } from 'knxultimate'

const client = new KNXClient({ hostProtocol: 'TunnelUDP', ipAddr: '192.168.1.117', ipPort: 3671 })

client.on(KNXClientEvents.indication, (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi?.npdu) return
  const dst = cemi.dstAddress?.toString?.()
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  if (!dst || !raw) return
  if (dst === '0/1/25') { // for example: a status GA known to be 1.001
    const cfg = dptlib.resolve('1.001')
    const value = dptlib.fromBuffer(raw, cfg)
    console.log(`dst=${dst} ->`, value)
  }
})

client.Connect()

3) Plain routing (Multicast) listener

import KNXClient from 'knxultimate'

const client = new KNXClient({
  hostProtocol: 'Multicast',
  ipAddr: '224.0.23.12',
  ipPort: 3671,
  physAddr: '1.1.200',   // set your device IA for routing
  loglevel: 'info',
})

client.on('connected', () => console.log('✓ Plain multicast ready'))
client.on('error', (e) => console.error('Error:', e.message))
client.on('indication', (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi?.npdu) return
  const dst = cemi.dstAddress?.toString?.()
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  console.log('routing ind', { dst, raw: raw?.toString('hex') })
})

client.Connect()

4) Write and then READ a status (plain)

import KNXClient from 'knxultimate'
import { dptlib } from 'knxultimate'

const client = new KNXClient({ hostProtocol: 'TunnelUDP', ipAddr: '192.168.1.117', ipPort: 3671 })

function waitForStatus(ga: string, timeoutMs = 3000): Promise<number> {
  return new Promise((resolve, reject) => {
    const t = setTimeout(() => { client.off('indication', onInd); reject(new Error('Timeout')) }, timeoutMs)
    const onInd = (packet: any) => {
      const cemi = packet?.cEMIMessage
      if (!cemi || cemi.dstAddress?.toString?.() !== ga) return
      const npdu = cemi.npdu
      if (!(npdu?.isGroupResponse || npdu?.isGroupWrite)) return
      const raw: Buffer = npdu?.dataValue ?? Buffer.alloc(1, 0)
      const bit = (raw.readUInt8(0) ?? 0) & 0x01
      clearTimeout(t)
      client.off('indication', onInd)
      resolve(bit)
    }
    client.on('indication', onInd)
  })
}

async function main() {
  client.Connect()
  await new Promise<void>((res) => client.once('connected', () => res()))
  // Write ON    n
  client.write('0/1/1', true, '1.001')
  // Read status
  client.read('0/1/25')
  const val = await waitForStatus('0/1/25', 3000)
  console.log('Status:', val ? 'ON' : 'OFF')
}

main().catch(console.error)

KNX/IP Secure: Quick Examples

Below are progressively richer examples to connect to a KNX/IP Secure gateway and listen for telegrams with decrypted payloads. These are meant to be copy‑pasted inline (no files are added under examples/). All snippets assume TypeScript/Node 18+.

Important notes

  • The client emits the full datagram on indication, and its cEMIMessage is already plain (decrypted) when keys are available in your ETS keyring.
  • Never commit your .knxkeys file. Keep its path/password in environment variables or local config.
  • Secure TCP tunnel auto‑select: if secureTunnelConfig.tunnelInterfaceIndividualAddress is omitted or empty, the client tries all interfaces found in the ETS keyring until authentication and connect succeed, then proceeds and keeps the tunnel open. The chosen IA is exposed on client._options.secureTunnelConfig.tunnelInterfaceIndividualAddress after connect.

1) Minimal secure tunnelling (TCP) listener

import KNXClient, { SecureConfig } from 'knxultimate'

// 1) Configure ETS keyring + the interface IA used in your project
const secureCfg: SecureConfig = {
  // tunnelInterfaceIndividualAddress: '1.1.254',   // Optional: omit to auto‑select a free tunnel
  knxkeys_file_path: process.env.KNX_KEYS_PATH || '/path/to/Project.knxkeys',
  knxkeys_password: process.env.KNX_KEYS_PASSWORD || 'your-ets-password',
}

// 2) Create a KNX/IP Secure TCP client
const client = new KNXClient({
  hostProtocol: 'TunnelTCP',
  ipAddr: '192.168.1.4',
  ipPort: 3671,
  isSecureKNXEnabled: true,
  secureTunnelConfig: secureCfg,
  loglevel: 'info',
})

client.on('connected', () => console.log('✓ Secure tunnel connected'))
client.on('error', (e) => console.error('Error:', e.message))
client.on('disconnected', (reason) => console.log('Disconnected:', reason))

// 3) Listen: cEMI payload is already decrypted when Data Secure is used
client.on('indication', (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi) return
  const dst = cemi.dstAddress?.toString?.()
  const src = cemi.srcAddress?.toString?.()
  const isWrite = cemi.npdu?.isGroupWrite
  const isResp = cemi.npdu?.isGroupResponse
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  console.log('indication', { src, dst, isWrite, isResp, raw: raw?.toString('hex') })
})

async function main() {
  client.Connect()
  await new Promise<void>((res) => client.once('connected', () => res()))
  console.log('Listening… Press Ctrl+C to exit')
}

main().catch(console.error)

1b) Secure tunnelling with only tunnel password

When you do not have access to the ETS keyring you can still negotiate KNX/IP Secure by providing the tunnel IA and password directly. This gives you encrypted tunnelling, while Data Secure and secure multicast stay disabled. The user ID defaults to 2, which is the standard KNX Secure tunnel account.

import KNXClient, { SecureConfig } from 'knxultimate'

const tunnelPassword = process.env.KNX_TUNNEL_PASSWORD
if (!tunnelPassword) {
  throw new Error('Set KNX_TUNNEL_PASSWORD with your secure tunnel password')
}

const secureCfg: SecureConfig = {
  tunnelInterfaceIndividualAddress: '1.1.254',
  tunnelUserPassword: tunnelPassword,
  tunnelUserId: 2, // Replace with your tunnel user ID from ETS (number or numeric string)
}

const client = new KNXClient({
  hostProtocol: 'TunnelTCP',
  ipAddr: '192.168.1.4',
  ipPort: 3671,
  isSecureKNXEnabled: true,
  secureTunnelConfig: secureCfg,
})

client.on('connected', () => console.log('✓ Secure tunnel connected (manual password)'))
client.on('error', (e) => console.error('Error:', e.message))

client.Connect()

Note: ETS assigns a dedicated tunnelUserId to each secure tunnel. Set secureTunnelConfig.tunnelUserId (number or numeric string) together with the password, otherwise the gateway replies with Secure Session Status = 1 and the connection is closed.

Secure workflow recap

  • KNX IP Tunnelling Secure protects the TCP channel. The gateway authenticates a tunnel user by ID + password during the Secure Session Authenticate (0x0953) step. Provide the password either from the keyring (secureTunnelConfig.knxkeys_*) or manually via secureTunnelConfig.tunnelUserPassword; in both cases the tunnelUserId must match the ETS commissioning data.
  • KNX Data Secure protects group-address telegrams. It relies on group keys stored in the ETS keyring, so a .knxkeys file plus its password are mandatory whenever you need encrypted group communication.
  • Supported combinations
    • Keyring only: set knxkeys_file_path/knxkeys_password and omit tunnelUserPassword. Both the tunnel password and the group keys are loaded from the keyring.
  • Manual tunnel password only: set both tunnelUserPassword and tunnelUserId without a keyring. The IP channel is secured, but Data Secure stays disabled because no group keys are present.
    • Keyring + manual password: provide the keyring for Data Secure and override the tunnelling password with tunnelUserPassword (useful when the ETS export does not include the tunnel password). Ensure knxkeys_* and tunnelUserPassword are both configured.
  • To retrieve the tunnel user ID/password pair, open the secure tunnelling interface in ETS (or inspect the .knxkeys entry). Default ETS IDs are typically small integers (e.g. 2, 3, …) but may differ per installation.

2) Decode datapoints (boolean 1.001) from decrypted payloads

import KNXClient, { SecureConfig } from 'knxultimate'
import { dptlib } from 'knxultimate'

const secureCfg: SecureConfig = {
  // tunnelInterfaceIndividualAddress: '1.1.254',   // Optional (auto‑select if omitted)
  knxkeys_file_path: process.env.KNX_KEYS_PATH || '/path/to/Project.knxkeys',
  knxkeys_password: process.env.KNX_KEYS_PASSWORD || 'your-ets-password',
}

const client = new KNXClient({
  hostProtocol: 'TunnelTCP',
  ipAddr: '192.168.1.4',
  ipPort: 3671,
  isSecureKNXEnabled: true,
  secureTunnelConfig: secureCfg,
  loglevel: 'info',
})

client.on('indication', (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi?.npdu) return
  const dst = cemi.dstAddress?.toString?.()
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  if (!dst || !raw) return

  // Example: decode boolean status for GA 1/1/2 as DPT 1.001
  if (dst === '1/1/2') {
    const cfg = dptlib.resolve('1.001')
    const value = dptlib.fromBuffer(raw, cfg)
    console.log(`dst=${dst} ->`, value)
  }
})

client.Connect()

3) Secure routing (multicast) listener

For routers supporting KNX Secure routing (multicast 224.0.23.12). The ETS keyring must include the Backbone key; the client will automatically use it to decrypt SecureWrapper frames and present decrypted cEMI payloads.

import KNXClient, { SecureConfig } from 'knxultimate'

const secureCfg: SecureConfig = {
  knxkeys_file_path: process.env.KNX_KEYS_PATH || '/path/to/Project.knxkeys',
  knxkeys_password: process.env.KNX_KEYS_PASSWORD || 'your-ets-password',
}

const client = new KNXClient({
  hostProtocol: 'Multicast',
  ipAddr: '224.0.23.12',
  ipPort: 3671,
  physAddr: '1.1.250',   // your device IA used as source on bus
  isSecureKNXEnabled: true,
  secureTunnelConfig: secureCfg,
  loglevel: 'info',
})

client.on('connected', () => console.log('✓ Secure multicast ready'))
client.on('error', (e) => console.error('Error:', e.message))
client.on('indication', (packet) => {
  const cemi = packet?.cEMIMessage
  if (!cemi?.npdu) return
  const dst = cemi.dstAddress?.toString?.()
  const raw: Buffer | undefined = cemi.npdu?.dataValue
  console.log('routing ind', { dst, raw: raw?.toString('hex') })
})

client.Connect()

4) Send a READ and get a decrypted status

import KNXClient, { SecureConfig } from 'knxultimate'
import { dptlib } from 'knxultimate'

const secureCfg: SecureConfig = {
  tunnelInterfaceIndividualAddress: '1.1.254',
  knxkeys_file_path: process.env.KNX_KEYS_PATH || '/path/to/Project.knxkeys',
  knxkeys_password: process.env.KNX_KEYS_PASSWORD || 'your-ets-password',
}

const client = new KNXClient({
  hostProtocol: 'TunnelTCP',
  ipAddr: '192.168.1.4',
  ipPort: 3671,
  isSecureKNXEnabled: true,
  secureTunnelConfig: secureCfg,
})

function waitForStatus(ga: string, timeoutMs = 5000): Promise<number> {
  return new Promise((resolve, reject) => {
    const t = setTimeout(() => {
      client.off('indication', onInd)
      reject(new Error('Timeout waiting for status'))
    }, timeoutMs)
    const onInd = (packet: any) => {
      const cemi = packet?.cEMIMessage
      if (!cemi || cemi.dstAddress?.toString?.() !== ga) return
      const npdu = cemi.npdu
      const isResp = npdu?.isGroupResponse
      const isWrite = npdu?.isGroupWrite
      if (!(isResp || isWrite)) return
      const raw: Buffer = npdu?.dataValue ?? Buffer.alloc(1, 0)
      const bit = (raw.readUInt8(0) ?? 0) & 0x01
      clearTimeout(t)
      client.off('indication', onInd)
      resolve(bit)
    }
    client.on('indication', onInd)
  })
}

async function main() {
  client.Connect()
  await new Promise<void>((res) => client.once('connected', () => res()))
  // Example: query a status GA and decode as boolean 1.001
  const statusGA = '1/1/2'
  client.read(statusGA)
  const val = await waitForStatus(statusGA, 5000)
  console.log(`Status on ${statusGA}:`, val ? 'ON' : 'OFF')
}

main().catch(console.error)

Tips

  • For tunnelling (TCP), the source IA is assigned by the gateway. For routing (multicast), set physAddr in options.
  • If you see decrypted payloads as null, verify that the GA has a Data Secure key in your .knxkeys and that the ETS keyring and password are correct. | message | Log message content | | stack | Error stack trace (only present for errors) |

Log Levels

Level Description
disable No logging
error Only logs errors
warn Logs errors and warnings
info Logs normal operations
debug Logs detailed information
trace Most verbose logging level

For a complete example of logging usage, see logging.ts in the examples folder.

DECONDING THE TELEGRAMS FROM BUS

Decoding is very simple.

Just require the dptlib and use it to decode the RAW telegram

import { dptlib } from "knxultimate";
let dpt = dptlib.resolve("1.001");
let jsValue = dptlib.fromBuffer(RAW VALUE (SEE SAMPLES), dpt); // THIS IS THE DECODED VALUE

EXAMPLES

All examples live in the examples folder. You can run them directly with TypeScript via esbuild-register (no build step needed).

  • Generic command: node -r esbuild-register -e "require('./examples/<file>.ts')"
  • For secure samples, npm scripts are available:
    • npm run example:secure:tunnel (secure tunnelling TCP)
    • npm run example:secure:multicast (secure routing multicast)

Examples overview:

  • Recommended starting point → template: well-commented skeleton showing how to configure plain vs secure connections, wire up core events, and encode/decode datapoint payloads. Use this file as a base for new scripts.

  • sample: Full walkthrough — connect, read/write, decode values. Warning: sends telegrams to your KNX BUS.

  • simpleSample: Minimal connect + single write. Warning: sends telegrams.
  • test-toggle: Interactive ON/OFF toggle from CLI. Warning: sends telegrams.
  • disconnection: Demonstrates clean disconnects and error handling.
  • logging: Shows how to attach to the log stream and change log levels.
  • monitorBusMinimal: Minimal listener that connects and prints incoming telegrams. Warning: connects to the bus but does not send telegrams.
  • showDatapoints: Lists supported datapoints and shows how payloads are built. Safe: does not send to the bus.
  • datapointBasics: Demonstrates encoding and decoding a few datapoint values locally. Safe.
  • discovery: Discovers KNX/IP interfaces/routers (SEARCH_REQUEST). Safe.
  • discoverInterfacesSimple: Uses discoverInterfaces() to print a concise summary of each gateway. Safe.
  • Run: node -r esbuild-register -e "require('./examples/discoverInterfacesSimple.ts')" [iface] [timeoutMs]
  • gatewaydescription: Requests and prints extended gateway information. Safe.
  • samplePlainTunnelUPD: Plain KNX/IP tunnelling over UDP (hostProtocol: 'TunnelUDP'). ON/OFF + status read via a KNX interface.
    • Run: node -r esbuild-register -e "require('./examples/samplePlainTunnelUPD.ts')"
  • samplePlainMulticast: Plain KNX routing over multicast (hostProtocol: 'Multicast'). Uses RoutingIndication with cEMI L_DATA_REQ. ON/OFF + status read via a KNX router (no secure).
    • Run: node -r esbuild-register -e "require('./examples/samplePlainMulticast.ts')"
  • sampleSecureTunnelTCP: KNX/IP Secure tunnelling over TCP (hostProtocol: 'TunnelTCP' + isSecureKNXEnabled: true). Performs session handshake + Secure Wrapper. Applies Data Secure for GA present in the ETS keyring. ON/OFF + status read.
    • Requires: set .knxkeys path + password in the example file. Optionally omit tunnelInterfaceIndividualAddress to auto‑select a free tunnel from the keyring.
    • Run: npm run example:secure:tunnel or node -r esbuild-register -e "require('./examples/sampleSecureTunnelTCP.ts')"
  • sampleSecureTunnelTCPNoDataSecure: KNX/IP Secure tunnelling over TCP using only the manual tunnel password/ID (no keyring, Data Secure disabled). Demonstrates secure channel establishment when group keys are unavailable.
    • Configure: set tunnelInterfaceIndividualAddress, tunnelUserPassword, and tunnelUserId in the file.
    • Run: node -r esbuild-register -e "require('./examples/sampleSecureTunnelTCPNoDataSecure.ts')"
  • sampleSecureMulticast: KNX/IP Secure routing over multicast (hostProtocol: 'Multicast' + isSecureKNXEnabled: true). Synchronizes timer via 0x0955, wraps frames in Secure Wrapper, and applies Data Secure per GA. ON/OFF + status read.
    • Requires: set .knxkeys path + password in the example file.
    • Run: npm run example:secure:multicast or node -r esbuild-register -e "require('./examples/sampleSecureMulticast.ts')"
  • dumpKeyringCredentials: Loads a .knxkeys file, decrypts all stored tunnel passwords, authentication codes, device credentials, group keys, and backbone keys, and prints them to the console. Safe.
    • Run: node -r esbuild-register -e "require('./examples/dumpKeyringCredentials.ts')" [path/to/keyring.knxkeys] [ets-password]

Discovery details

  • Functions: KNXClient.discover(), KNXClient.discoverDetailed(), KNXClient.discoverInterfaces().
  • Default port: if a KNX interface does not advertise a port in the SEARCH_RESPONSE HPAI (missing or zero), discovery uses 3671 as the port.
  • Each helper now fires both multicast and unicast search bursts concurrently on every selected NIC so interfaces that only answer one transport are still found.
  • Return formats:
  • discover() → strings formatted as ip:port:name:ia:Security:Transport; highlights whether the result is plain/secure and which transport to use.
    • Example: 192.168.1.4:3671:MyGW:1.1.1:Secure KNX:TCP, 224.0.23.12:3671:MyRouter:1.1.0:Plain KNX:Multicast.
  • discoverDetailed() → strings formatted as ip:port:name:ia:service1,service2:type; focuses on human-readable service families (routing, tunnelling, etc.) and whether the entry corresponds to tunnelling or routing.
  • discoverInterfaces() → array of objects { ip, port, name, ia, services, type, transport }, giving parsed fields and an inferred transport, with services exposed as an array of service names.

Example usage

import KNXClient from 'knxultimate'

// Simple list with security + transport
const list = await KNXClient.discover(5000)
for (const entry of list) {
  const [ip, port, name, ia, security, transport] = entry.split(':')
  console.log({ ip, port, name, ia, security, transport })
}

// Detailed strings
const detailed = await KNXClient.discoverDetailed(5000)
// ip:port:name:ia:service1,service2:type

// Structured objects
const objects = await KNXClient.discoverInterfaces(5000)
// [{ ip, port, name, ia, services, type, transport }, ...]

Source Individual Address (IA): UDP vs TCP

  • TunnelUDP: uses physAddr as the source IA on the bus.
  • TunnelTCP (secure): after a successful connect, uses the tunnel-assigned IA as the cEMI source on the bus; the Data Secure authentication, however, uses the interface IA from the ETS keyring (not the dynamic tunnel IA).
  • Tips for UDP tunnelling:
    • If your interface times out on L_DATA_REQ ACK, try suppress_ack_ldatareq: true.
    • With multiple NICs, set localIPAddress (or interface) to bind the correct local interface.

KNX IP Secure (tunnelling & routing) and Data Secure

KNXClient supports KNX/IP Secure and Data Secure.

  • Requirements: KNX Secure router/interface and ETS keyring (.knxkeys). For TunnelTCP, the interface IA is optional — if omitted, the client auto‑selects a usable tunnel from the keyring.
  • Data Secure: Group Addresses present in the keyring are encrypted end‑to‑end; GA not present remain plain.
  • Modes:
    • TunnelTCP + isSecureKNXEnabled: true → secure session (Secure Wrapper) + Data Secure per GA.
    • Multicast + isSecureKNXEnabled: true → secure routing (Secure Wrapper over multicast with timer synchronization via 0x0955) + Data Secure per GA.

Routing (Multicast) specifics

  • Outgoing frames are injected as L_DATA_IND when using routing (both plain and secure). This mirrors ETS and xKNX behavior and ensures devices react correctly to injected telegrams. Do not use L_DATA_REQ for routing injection.
  • Secure routing needs a synchronized timer. By default the client waits until the timer is authenticated before sending. Additionally, on secure multicast startup the client proactively sends a TimerNotify (0x0955) once, so the timer can authenticate immediately even if the router doesn’t broadcast it right away. Plain multicast is unaffected.
  • Option: secureRoutingWaitForTimer (default true) controls gating of outgoing frames until the timer is authenticated.

Authorized senders (Data Secure, secure routing)

  • When sending to a Data Secure Group Address over routing, KNX routers enforce an “authorized senders” list per GA. If your current physAddr is not authorized for that GA, the router will drop the telegram.
  • The client automatically avoids this problem by selecting an allowed sender IA for each secure GA based on the ETS keyring. If the configured physAddr is not in the GA’s Senders list, the library overrides the source IA with one that is authorized for that GA (taken from the keyring’s Senders for that GA) before building the Secure APDU.
  • Prerequisites: your .knxkeys (ETS Project Keyring) must include the target GA and its Senders list. If no Senders are present for that GA in the keyring, the client keeps physAddr and the router may still drop the frame as unauthorized.
  • This behavior is automatic whenever hostProtocol: 'Multicast' and isSecureKNXEnabled: true and the GA is protected by a Data Secure key in the keyring. No additional option is required.

Mixed secure/plain on one instance

  • A single KNXClient instance can handle Data Secure and plain Group Addresses at the same time. Data Secure is applied per‑GA: if a GA has a key in the ETS keyring, the APDU is encrypted; if not, the APDU stays plain.
  • Secure routing (multicast): when isSecureKNXEnabled: true, all routing frames are transported inside the KNX/IP Secure Wrapper (0x0950). “Plain” APDUs still travel inside that wrapper. This allows mixing secure and plain GA on the same instance. If you also need to emit non‑wrapped plain routing frames simultaneously, run a second KNXClient with isSecureKNXEnabled: false.
  • Secure tunnelling (TCP): the tunnel is always wrapped (Secure Wrapper). APDU encryption (Data Secure) remains per‑GA; GA without keys remain plain.
  • Receive path: with secure enabled, the client decrypts 0x0950 frames and forwards the inner plain cEMI; it also accepts non‑wrapped routing frames if present on the bus. The indication event always exposes a plain (decrypted) cEMI when keys are available.

Troubleshooting (routing)

  • If an actuator doesn’t react to writes sent over routing, verify that your app injects L_DATA_IND (not L_DATA_REQ). From version 5.0.0‑beta the library automatically uses L_DATA_IND for multicast writes/reads/responses.
  • For secure routing, ensure your ETS keyring contains a Backbone key and that the target Group Addresses are present with keys (Data Secure). You can list them with the example examples/listSecureGroups.ts.

Behavior when fields are unset

  • secureTunnelConfig.tunnelInterfaceIndividualAddress (TunnelTCP): if omitted/empty, the client auto‑selects a tunnel from the ETS keyring and retries interfaces until authentication and connect succeed. The chosen IA is exposed runtime in client._options.secureTunnelConfig.tunnelInterfaceIndividualAddress after connect.
  • physAddr:
    • Multicast: must be provided; it’s your node’s source IA on the bus.
    • TunnelUDP: optional; used as cEMI source if set.
    • TunnelTCP: optional and ignored for the bus source (gateway provides the tunnel IA); Data Secure signs as the interface IA from the keyring.

Secure TCP auto‑selection details

  • IA selection: the client runs discovery for ipAddr:ipPort, reads the gateway “Host” IA, and selects keyring interfaces whose Host matches it. Candidates are sorted descending (e.g. …255, …254, …253). If no match by Host, it falls back to all keyring interfaces of type Tunneling.
  • Single‑NIC discovery: when options.interface is empty/undefined, discovery is executed only on the local NIC that shares the same subnet of ipAddr (no scan across all OS interfaces).
  • Timeouts: detailed discovery runs ~3s on the chosen NIC; if nothing is found, a lightweight simple discovery runs ~5s on the same NIC and is adapted to the detailed format.
  • Logging: look for lines starting with “Secure TCP:” to follow selection steps (discovered Host IA, candidates, chosen IA).
  • Override: set secureTunnelConfig.tunnelInterfaceIndividualAddress and/or interface explicitly to skip the auto‑selection.

HOW TO COLLABORATE

If you want to help us in this project, you're wellcome!

Please refer to the development page.


SUGGESTION

Why not to try Node-Red https://nodered.org and the awesome KNX-Ultimate node https://flows.nodered.org/node/node-red-contrib-knx-ultimate ?




Logo

changelog

5.1.4 (2025-10-11)

Features

  • discovery methods send both multicast and unicast bursts in parallel so as not to miss gateways that only respond to one of the two transports. (#71) (f95b6d8)

5.1.3 (2025-09-23)

Features

5.1.2 (2025-09-22)

Features

  • added mock secure server for tests (80f2057)
  • added tests on sec primitives (5dc5d40)
  • more tests in secure (db7b123)

5.1.1 (2025-09-22)

Features

  • added tunneluserID in case of manual credentials withoud keyring (d98864e)

5.1.0 (2025-09-19)

Features

  • Added secure tunnel/password authentication other than the keyring file. (#62) (ca83ed0)

5.0.0 (2025-09-16)

Bug Fixes

5.0.0-beta.5 (2025-09-15)

Bug Fixes

  • fixed multicast secure issue (8289661)

Features

  • auto tunnel selection in TCP Secure (09d4c1c)

5.0.0-beta.4 (2025-09-13)

Bug Fixes

  • regression in secure connection keep alive. (c6da3aa)

5.0.0-beta.3 (2025-09-13)

Bug Fixes

  • fided heartbeat in TunnelTCP secure (06f24af)
  • fixed tests and update README (87c9b01)
  • fixed wrong heartbeat log (b46d5de)

5.0.0-beta.2 (2025-09-12)

5.0.0-beta.1 (2025-09-11)

5.0.0-beta.0 (2025-09-11)

Bug Fixes

  • #23 writeRaw broken with length <= 6bits (#24) (bfbc7ab)
  • #30 short value 0x3f decoding (#29) (34b21be)
  • add build step to ci (0618bc7)
  • add missing helps in dpts (be3dee3)
  • async closeSocket thtows an error if the socket is already closed. (f81d1d0)
  • better checks of socket ready state (#39) (a65d4b1)
  • better rounding on dpt 9.001 (#33) (30fe11d), closes #32
  • better timers management for race conditions and leak prevention (#17) (8ffcd93)
  • clear the queueitem in case of errors (e7a718d)
  • client close (fd91d96)
  • disconnect request not sent properly in KNXClient.ts (#55) (0de4c00)
  • ensure _clearToSend is correctly set during discovery (#34) (5d4a2e4)
  • examples (4c26f5a)
  • exiting the queue loop after error (6d67807)
  • export all packet types (196f712)
  • export dptlib (a32d2ec)
  • finish conversion of curve25519 (1e2743a)
  • fix DPT10.001 Time error when time passed as string (ad2c314)
  • fix missing "test" folder (f24f5f2)
  • fix multicast socket, by removing the local ip interface from the binding (99e1176)
  • fixed an issue when "suppress ACK request" was set to true. (1c70745)
  • fixed an uncaught exception (f9645c4)
  • fixed base beta release (56e7f96)
  • fixed DPT6002 not showing up (a4e95dd)
  • Fixed import issue (c666954)
  • fixed lint issues in new DPT 6002 (1b30857)
  • fixed queue ACK issue. Now, the replies from request coming from the KNX Gateway, are put as priority item in the kNX output queue. (76ded4b)
  • improve messages types (b6c9f49)
  • improved disconnect logic (8e55945)
  • improved types of events (4658b45)
  • index.ts of dtplib was whrowing an unmeaningful error. (#47) (d517a82)
  • ipAddressHelper uncatched error when running on raspberry pi, having interfaces without any ip. (#44) (4b29af6)
  • issue where DPT9 was giving error (#21) (f0c9120)
  • limiter improvements (#28) (90ca11f)
  • logger and deprecated buffer slice to subarray (ddd6733)
  • make release-it adding a patch release instead of main release. (#51) (22bf2e9)
  • refactor method names and added js docs (#19) (0bf6af4)
  • remove many useless try catches (3c528f1)
  • remove references to KNXEthInterface (2c1912f)
  • removed the "test" folder from the include array (b7341c9)
  • removed unwanted "desc" prop from DatapointConfig root. (#48) (16d7538)
  • socket end (64a6296)
  • some other types (5d84716)
  • some types (b01ef85)
  • test connect/disconnect (b378c6a)
  • the loglevel is now fixed. (4faeab4)
  • the tunnel socket creation function (createSocket), adding reusable option and specifying the port. This will likely prevent some UDP packets not arriving at the socket, due to operating system routing restrictions. (fed7e20)
  • tlvinfo type (1972fee)
  • typo (f5c461c)
  • typo on knx client (53e6b1b)
  • updated gitignore to exclude some personal keys (f4b7d09)
  • use destroy for TCP socket close (d00359f)
  • useless statics (8da73f2)
  • vscode default fomatter (c267cbf)
  • wrong address parsing (e529650)
  • wrong overload of discovery method (709b7d1)
  • feat!: implemented KNX routing secure (#60) (18671d6), closes #60

Features

  • Ad DPT 14.1200 (#50) (7830ae3)
  • Add Hager TXA223/225 custom status DPT 60002 (cb66cdd)
  • added all subtypes to datapoint 20.x (#45) (ce436c0)
  • Added first files for support to KNX Secure and Data Secure Tunneling (e4fa892)
  • added getGatewayDescription method, to gather infos of the connected gateway (9c6ae5d)
  • added src and destination addresses in the LDataInd LOG. (#46) (a2f53e2)
  • added the gatewaydescription.ts sample (b68427c)
  • added the KNX/IP Gateway description gatherer, wich contains the gateway's name, tunneling/routing modes etc.. (97c5bdc)
  • client and other types (06ea902)
  • device info in "discover", added KNXClient.getGatewayDescription (#40) (06c7ed6), closes /github.com/Supergiovane/KNXUltimate/pull/40#discussion_r1850563396
  • discovery (#15) (087477e)
  • eslint + prettier (6c10385)
  • finish converting dptlib (6d5e75b)
  • going on (7ebdec3)
  • going on with protcol (0fe5d62)
  • going on with refactor (a57efb3)
  • Preliminary support for knx virtual & ACK fix (#53) (abd36a9)
  • protocol cemi conversion (5e31a0a)
  • refactor errors (c8623e1)
  • securwe keyring (3574fe0)
  • transparent KNX queue. The sent telegrams are now queued and transmitted to the bus by obeying the time interval specified by the new property "KNXQueueSendIntervalMilliseconds" (d4e8fd3)
  • Turn unknown error 0x25 to E_NO_MORE_UNIQUE_CONNECTIONS (deabcfd)
  • typed event emitter (ea29beb)
  • typescript refactor (81d00af)
  • zio cantante aggiungere qui la porca di quella merdassa perchè non committa vacca mincha merdosa (f2fe52c)

BREAKING CHANGES

  • deleted the echoLocalTelegramsInTunneling property. If you don't know what it is, it's not a breaking change for you.

  • doc: updated docs.

  • fix: fixed test fails

  • fix: lint da figa!!

  • chore: workaround test

  • fix: caxxo

4.1.3 (2025-05-16)

Bug Fixes

  • disconnect request not sent properly in KNXClient.ts (#55) (4253064)

4.1.2 (2025-04-30)

Features

  • Preliminary support for knx virtual & ACK fix (#53) (d2a340a)

4.1.1 (2025-04-16)

Bug Fixes

  • make release-it adding a patch release instead of main release. (#51) (211c0ef)

Features

4.1.0 (2025-04-12)

Bug Fixes

  • removed unwanted "desc" prop from DatapointConfig root. (#48) (a73166a)

4.1.0-beta.10 (2025-03-12)

Bug Fixes

  • index.ts of dtplib was whrowing an unmeaningful error. (#47) (168d73a)

4.1.0-beta.9 (2025-03-04)

Features

  • added src and destination addresses in the LDataInd LOG. (#46) (1f5947d)

4.1.0-beta.8 (2025-01-28)

Features

  • added all subtypes to datapoint 20.x (#45) (9051dbe)

4.1.0-beta.7 (2024-12-30)

Bug Fixes

  • ipAddressHelper uncatched error when running on raspberry pi, having interfaces without any ip. (#44) (a9e46ee)

4.1.0-beta.4 (2024-12-07)

4.1.0-beta.3 (2024-12-07)

4.1.0-beta.2 (2024-12-06)

4.1.0-beta.1 (2024-11-21)

Bug Fixes

  • better checks of socket ready state (#39) (92a2172)
  • fixed base beta release (c9dfa79)

Features

4.0.0-beta.6 (2024-11-18)

Bug Fixes

  • clear the queueitem in case of errors (393b818)
  • exiting the queue loop after error (0bb3c19)
  • fixed an uncaught exception (b48a5b1)

4.0.0-beta.5 (2024-11-17)

4.0.0-beta.4 (2024-11-15)

Bug Fixes

  • fix multicast socket, by removing the local ip interface from the binding (ca01449)

4.0.0-beta.3 (2024-11-15)

Bug Fixes

  • fix missing "test" folder (821e398)
  • removed the "test" folder from the include array (742a028)
  • the tunnel socket creation function (createSocket), adding reusable option and specifying the port. This will likely prevent some UDP packets not arriving at the socket, due to operating system routing restrictions. (3fdd938)

Features

  • added getGatewayDescription method, to gather infos of the connected gateway (88b883a)
  • added the gatewaydescription.ts sample (41b1f66)
  • added the KNX/IP Gateway description gatherer, wich contains the gateway's name, tunneling/routing modes etc.. (f99170f)

4.0.0-beta.2 (2024-10-17)

4.0.0-beta.1 (2024-10-17)

Bug Fixes

4.0.0-beta.0 (2024-10-15)

Bug Fixes

3.0.4 (2024-10-08)

3.0.3 (2024-09-16)

3.0.2 (2024-09-16)

Bug Fixes

  • fixed queue ACK issue. Now, the replies from request coming from the KNX Gateway, are put as priority item in the kNX output queue. (93ca4cc)

3.0.1 (2024-09-16)

Bug Fixes

  • fixed an issue when "suppress ACK request" was set to true. (83a5f5d)

3.0.0 (2024-09-15)

3.0.0-beta.1 (2024-09-12)

Bug Fixes

3.0.0-beta.0 (2024-09-08)

Features

  • transparent KNX queue. The sent telegrams are now queued and transmitted to the bus by obeying the time interval specified by the new property "KNXQueueSendIntervalMilliseconds" (93a65c9)

2.3.5 (2024-07-08)

2.3.4 (2024-07-08)

Bug Fixes

  • async closeSocket thtows an error if the socket is already closed. (31baf39)

2.3.3 (2024-06-14)

Bug Fixes

  • vscode default fomatter (82ce441)

2.3.2 (2024-06-14)

Bug Fixes

  • fix DPT10.001 Time error when time passed as string (23a27ab)

2.3.1 (2024-06-13)

Bug Fixes

  • fixed DPT6002 not showing up (593e548)

2.3.0 (2024-06-13)

Bug Fixes

  • fixed lint issues in new DPT 6002 (529d392)

Features

  • Add Hager TXA223/225 custom status DPT 60002 (c61f576)

2.2.0 (2024-06-12)

Bug Fixes

Features

  • Turn unknown error 0x25 to E_NO_MORE_UNIQUE_CONNECTIONS (67f5dd8)

2.1.4 (2024-05-30)

2.1.3 (2024-05-28)

Bug Fixes

  • issue where DPT9 was giving error (#21) (2ac791e)

2.1.3 (2024-05-28)

Bug Fixes

New Contributors

2.1.2 (2024-04-24)

Bug Fixes

  • refactor method names and added js docs (#19) (432db89)
  • wrong overload of discovery method (a41b65c)

2.1.1 (2024-04-23)

Bug Fixes

  • better timers management for race conditions and leak prevention (#17) (494af28)

2.1.0 (2024-04-23)

Features

2.0.0-beta.0 (2024-04-18)

Bug Fixes

Features

Fixes

  • TunnelUDP keeps using configured physAddr as source IA; the tunnel-assigned IA from CONNECT_RESPONSE is now applied only for TunnelTCP (secure). Improves compatibility and restores legacy behavior expected by tools/tests.

Tests/CI

  • Stabilized integration tests by avoiding real os.networkInterfaces() in CI and lowering log verbosity during tests.

Docs

  • Clarified IA behavior for TunnelUDP vs TunnelTCP in README, plus tips for UDP tunnelling (ACK suppression and localIPAddress).