A reactive, non-blocking Java library for KNX Net/IP communication.
The purpose of this library is designed for developers to allow their applications to communicate with KNX world via their KNX Net/IP device (by using either a KNX router or a KNX interface). Tunneling and routing modes are supported.
For a demo application see knx-demo-tty-monitor and for first examples see knx-examples.
- No KNX Secure which are offered by newest generation of KNX Net/IP devices (because I do not have a KNX router that supports KNX secure)
- Java 11+
- Make sure that you have Java 11+ installed and running as Java 11+
- Tunneling: KNX Router or Interface
- One free tunneling connection available
- IP-Address (optional, if not provided - the auto-discovery service will be used)
- Routing: KNX Router only
- Filter table on your KNX router device is properly configured, otherwise packets won't be forwarded
- IP Multicast Address that is used by your KNX router (optional, if not provided, the default 224.0.23.12 multicast address will be used)
The communication between KNX Net/IP device and the KNX client is reactive and non-blocking which allows a very fast communication and we may have multiple channels simultaneously open:
- Discovery Channel for discovery service (multicast)
- Description Channel for receiving description information
- Control Channel for tunneling; control-related frames like connect, disconnect and connection state
- Data Channel for tunneling; data-related frames like read/write requests from and to KNX
- Multicast Channel for routing; data-related frames
According to the KNX specification the communication is defaulted to tunneling mode and without Network Address Translation (NAT). The knx-core also offers the communication using routing instead of tunneling.
DefaultKnxClient.createStarted(); // IP Address resolved using discovery service
DefaultKnxClient.createStarted("192.168.0.3"); // Defined IP Address with default KNX Port
DefaultKnxClient.createStarted("192.168.0.3:1234"); // Defined IP Address with custom KNX Port
Using ConfigBuilder
we can configure the KNX Client like above:
var config = ConfigBuilder.tunneling().build();
var config = ConfigBuilder.tunneling(address).build();
var config = ConfigBuilder.tunneling(address, port).build();
DefaultKnxClient.createStarted(config);
Network Address Translation (NAT) is available for tunneling mode only; for routing
NAT is not required. Sometimes we need NAT, eg. in dockerized image. To use the NAT we
need to enable it explicitly by true
:
var config = ConfigBuilder.tunneling(true).build();
var config = ConfigBuilder.tunneling(address, true).build();
var config = ConfigBuilder.tunneling(address, port, true).build();
DefaultKnxClient.createStarted(config);
If you specific an IP Address that is in a Class D address (i.e. four first bits of the address are 1110,
, CIDR notation "224.0.0.0/4") then it is a IP multicast address and for this purpose the routing
communication will be used automatically. The standardized IP multicast address for KNX is 224.0.23.12
.
DefaultKnxClient.createStarted("224.0.23.12"); // IP Multicast Address (KNX Specification)
DefaultKnxClient.createStarted("224.1.2.3"); // IP Multicast Address (Custom)
You can use the ConfigBuilder
to define the routing mode:
var config = ConfigBuilder.routing().build();
var config = ConfigBuilder.routing(address).build();
var config = ConfigBuilder.routing(address, port).build();
DefaultKnxClient.createStarted(config);
In KNX every group object is a data point and it represents data. In order to have a standardized interpretation of the data the Data Point Type (DPT) have been introduced by the KNX Association to define how the data is encoded.
The KNX Client supports various data point types and is designed to translate data point types in a fluent way into a KNX byte-array compatible format. Following are supported:
DPT | Description | DPT | Description |
---|---|---|---|
1.xxx | Binary | 21.xxx | 8-Bit Flagged Messages |
2.xxx | Controlled Binary | 22.xxx | 16-Bit Flagged Messages |
3.xxx | Controlled Step/Interval | 23.xxx | 2-Bit Enumeration |
4.xxx | Character | 24.xxx | ISO-8859-1 Characters (variable length) |
5.xxx | 8-Bit Unsigned Value | 25.xxx | 2-Nibble Set |
6.xxx | 8-Bit Signed Value | 26.xxx | Scene Information |
7.xxx | 2-Octet Unsigned Value | 27.xxx | Combined Info On/Off |
8.xxx | 2-Octet Signed Value | 28.xxx | UTF-8 Characters (variable length) |
9.xxx | 2-Octet Float Value | 29.xxx | 8-Octet Signed Value Electrical Energy |
10.xxx | Time | ||
11.xxx | Date (Year: 1990..2089) | ||
12.xxx | 4-Octet Unsigned Value | ||
13.xxx | 4-Octet Signed Value | ||
14.xxx | 4-Octet Float Value | ||
15.xxx | Access Data | ||
16.xxx | 14-Octet Characters | ||
17.xxx | Scene Number | ||
18.xxx | Controlled Scene Number | ||
19.xxx | Date and Time (Year: 1900..2155) | ||
20.xxx | 8-Bit Enumeration |
Based on article from KNX Association the DPT1 until DPT20 are most often used data point types.
For other DPTs which are not on the list yet, you can either implement the Data Point Type by yourself
by extending the DataPointType
. Alternatively use the built-in DPTRaw
whereas the raw value is in
byte array format.
Given example, we want to get data point for date and time that represents Saturday, 2013-08-17 04:10:45
.
According to the data point type table above we would use the DPT19 which is 19.001
:
var dayOfWeek = DayOfWeek.SATURDAY;
var date = LocalDate.of(2013, 8, 17);
var time = LocalTime.of(04, 10, 45);
DPT19.DATE_TIME.of(dayOfWeek, date, time);
The KNX Client was also designed to provide a less barrier using human-friendly text:
DPT19.DATE_TIME.of("Saturday", "04:10:45", "2013-08-17"); // All information
DPT19.DATE_TIME.of("2013-08-17", "04:10:45"); // Only date and time
DPT19.DATE_TIME.of("04:10:45", "2013-08-17"); // Order doesn't matter, auto-detected
The KNX Group Address represents the destination address of the telegram for an action; eg. switch on lamp. In order to be operational at least two group objects to be linked; one for sending telegram and one for receiving the telegram.
In ETS we have three types of group address structures which are all stored in a data length of 16 bits (2 octets):
- Three-Level: Main, Middle and Sub (Range:
0/0/1 - 31/7/255
) - Two-Level: Main and Sub (Range:
0/1 - 31/2047
) - Free-Level: Address (Range:
1 - 65535
)
From KNX topology point of view 1/2/100
, (Three-Level) 1/612
(Two-Level) and 2660
(Free-Level)
represents the same group address.
GroupAddress.of(int, int, int); // Three-Level Structure
GroupAddress.of(int, int); // Two-Level Structure
GroupAddress.of(int); // Free-Level Structure
GroupAddress.of(String); // Auto-detecting and parsing based on format
The KNX Individual Address defines the location of the device within the KNX topology.
The Individual Address is represented in a data length of 16 bits (2 octets) with a fixed structure
and in a range from 0.0.1
- 15.15.255
. First is the Area, middle is the Line and last is
the Device Address. The Individual Address 0.0.0
is not allowed, and represents the undefined
state.
IndividualAddress.of(int, int, int); // Area, Line and Device Address
IndividualAddress.of(String); // Format: "<Area>.<Line>.<Device Address>" (e.g. "1.2.3")
This section is written for experienced Java developers and explains how to integrate the
KNX client with your own application. Use the try-with-resources
to create and start
the KNX communication. The closure of KNX communication will be handled automatically by
the KNX client then:
try (var client = DefaultKnxClient.createStarted("address:port")) {
// do something...
}
DefaultKnxClient.createStarted("address:port").use { client ->
// do something...
}
Below are some practical first-to-use examples. For more examples, see knx-examples repository.
Let's start with an easy sample: You want to switch on
a lamp. The KNX actuator listens
on group address 1/2/110
which is configured for switching on/off a lamp. For this case we have to use the KNX DPT1
for 1-bit values, it is the same what you have to define in the ETS that is used to configure the KNX infrastructure:
public final class LampOnExample {
public static void main(final String[] args) {
// this is the group address where the KNX actuator listens to switch on/off a lamp
final var groupAddress = GroupAddress.of(1, 2, 110);
// create KNX client and connect to KNX Net/IP device using auto-discovery
try (final var client = DefaultKnxClient.createStarted()) {
// switch on the lamp (boolean: true) --> translated to '0x01' and sent to KNX Net/IP device
client.writeRequest(groupAddress, DPT1.SWITCH.of(true)); // or DPT1.SWITCH.of((byte)0x01)
// or DPT1.SWITCH.of("on")
}
// auto-closed and disconnected by KNX client
}
}
fun main() {
// this is the group address where the KNX actuator listens to switch on/off a lamp
val groupAddress = GroupAddress.of(1, 2, 110);
// create KNX client and connect to KNX Net/IP device using auto-discovery
DefaultKnxClient.createStarted().use { client ->
// switch on the lamp (boolean: true) --> translated to '0x01' and sent to KNX Net/IP device
client.writeRequest(groupAddress, DPT1.SWITCH.of(true)); // or DPT1.SWITCH.of((byte)0x01)
// or DPT1.SWITCH.of("on")
}
}
Given sample, you want to inverse the status of your lamp:
- if the lamp is
on
, the lamp should beoff
- if the lamp is
off
, the lamp should beon
To get the most recent status of lamp, we need this information from the KNX actuator. As
per KNX Project Design Guidelines we have multiple KNX group addresses, here in our example
the group address 1/2/110
is responsible for switching on/off the lamp (=write). The group address
1/2/113
is used for status feedback of the lamp (=read).
public final class LampInverseExample {
public static void main(final String[] args) {
// this is the group address where the KNX actuator returns the status of lamp
final var readGroupAddress = GroupAddress.of(1, 2, 113);
// this is the group address where the KNX actuator listens to switch on/off the lamp
final var writeGroupAddress = GroupAddress.of(1, 2, 110);
// create KNX client and connect to KNX Net/IP device using auto-discovery
try (final var client = DefaultKnxClient.createStarted()) {
// send a 'read' request to KNX
client.readRequest(readGroupAddress);
// KNX actuator will send a response to the KNX client with actual lamp status
final var status = client.getStatusPool().getValue(readGroupAddress, DPT1.SWITCH).getValue();
// lamp status will be inverted (on -> off / off -> on)
final var statusInverted = !status;
// send a 'write' request to KNX
client.writeRequest(writeGroupAddress, DPT1.SWITCH.of(statusInverted));
}
// auto-closed and disconnected by KNX client
}
}
The default configuration settings used by KNX Client are as per KNX Specification
but gives you some freedom to adjust some configurations; e.g. change to use another
KNX port which differs from the officially registered KNX port 3671
at IANA.
All KNX Core configurations can be found in: CoreConfigs.java
Name | Type | Default Value | Description |
---|---|---|---|
NAT | Boolean |
false |
Enable/Disable the NAT for tunneling communication. Communication: Tunneling Config Field: li.pitschmann.knx.core.config.CoreConfigs.NAT Config Key: client.nat.enabled |
KNX Project Path | Path |
Latest *.knxproj file in current work directory. |
Absolute path to the *.knxproj file that is created/maintained by ETS tool. Config Field: li.pitschmann.knx.core.config.CoreConfigs.PROJECT_PATH Config Key: project.path |
Search | |||
Request Timeout | Long |
10000 milliseconds |
Timeout for search requests to find KNX Net/IP device in your network using multicast. Communication: Tunneling (Discovery Channel, multicast) Config Field: CoreConfigs.Search.REQUEST_TIMEOUT Config Key: client.communication.search.requestTimeout |
Description | |||
Request Timeout | Long |
10000 milliseconds |
Timeout for description requests to fetch device information about KNX Net/IP device. Communication: Tunneling (Description Channel) Config Field: CoreConfigs.Description.REQUEST_TIMEOUT Config Key: client.communication.description.requestTimeout |
Local Port | Integer |
0 (=random free port) |
Port that should be bound by KNX Client on local machine. Communication: Tunneling (Description Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Description.PORT Config Key: client.communication.description.port |
Socket Timeout | Long |
3000 milliseconds |
Timeout for description channel socket. Communication: Tunneling (Description Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Description.SOCKET_TIMEOUT Config Key: client.communication.description.socketTimeout |
Connect | |||
Request Timeout | Long |
10000 milliseconds |
Timeout for connect requests to establish a tunneling connection to KNX Net/IP device. Communication: Tunneling (Control Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Connect.REQUEST_TIMEOUT Config Key: client.communication.connect.requestTimeout |
Disconnect | |||
Request Timeout | Long |
10000 milliseconds |
Timeout for disconnect requests sent to KNX Net/IP device. Communication: Tunneling (Control Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Disconnect.REQUEST_TIMEOUT Config Key: client.communication.disconnect.requestTimeout |
Response Timeout | Long |
1000 milliseconds |
Timeout for disconnect response from KNX Net/IP device after disconnect request. Communication: Tunneling (Control Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Disconnect.RESPONSE_TIMEOUT Config Key: client.communication.disconnect.responseTimeout |
Connection State | |||
Request Timeout | Long |
10000 milliseconds |
Timeout for connection state requests for request if KNX Net/IP device is still reachable. Communication: Tunneling (Control Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.ConnectionState.REQUEST_TIMEOUT Config Key: client.communication.connectionState.requestTimeout |
Heartbeat Interval | Long |
60000 milliseconds |
Interval when connection state requests should be sent to KNX Net/IP device. Config Field: li.pitschmann.knx.core.config.CoreConfigs.ConnectionState.HEARTBEAT_INTERVAL Config Key: client.communication.connectionState.heartbeatInterval |
Heartbeat Timeout | Long |
120000 milliseconds |
Ultimate timeout when disconnect sequence should be initiated by KNX Client when no connection state response was received. Communication: Tunneling (Control Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.ConnectionState.HEARTBEAT_TIMEOUT Config Key: client.communication.connectionState.heartbeatTimeout |
Control Channel | |||
Local Port | Integer |
0 (=random free port) |
Port that should be bound by KNX Client on local machine for all control channel related packets. Config Field: li.pitschmann.knx.core.config.CoreConfigs.Control.PORT Config Key: client.communication.control.port |
Socket Timeout | Long |
3000 milliseconds |
Timeout for control channel socket Config Field: li.pitschmann.knx.core.config.CoreConfigs.Control.SOCKET_TIMEOUT Config Key: client.communication.control.socketTimeout |
Tunneling | |||
Request Timeout | Long |
1000 milliseconds |
Timeout for tunneling requests sent to KNX Net/IP device. Communication: Tunneling (Data Channel) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Tunneling.REQUEST_TIMEOUT Config Key: client.communication.tunneling.requestTimeout |
Data Channel | |||
Local Port | Integer |
0 (=random free port) |
Port that should be bound by KNX Client on local machine for all data channel related packets. Communication: Tunneling Config Field: li.pitschmann.knx.core.config.CoreConfigs.Data.PORT Config Key: client.communication.data.port |
Socket Timeout | Long |
3000 milliseconds |
Timeout for data channel socket. Communication: Tunneling Config Field: li.pitschmann.knx.core.config.CoreConfigs.Data.SOCKET_TIMEOUT Config Key: client.communication.data.socketTimeout |
Remote Endpoint | |||
Address | InetAddress |
unbound (uses discovery) |
Remote IP Address of KNX Net/IP device. Communication: Tunneling (Control and Data Channel) Config Field: not available Config Key: client.endpoint.address |
Port | Integer |
3671 |
Port of KNX Net/IP device to accept KNX requests. Communication: Tunneling (Control and Data Channel) Config Field: not available Config Key: client.endpoint.port |
Multicast | |||
Address | InetAddress |
224.0.23.12 |
Multicast Address that may be joined by KNX Net/IP device. Communication: Routing, Tunneling (Search only) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Multicast.ADDRESS Config Key: client.communication.multicast.address |
Port | Integer |
3671 |
Port of Multicast that may be joined by KNX Net/IP device. Communication: Routing, Tunneling (Search only) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Multicast.PORT Config Key: client.communication.multicast.port |
Time-To-Live (TTL) | Integer |
4 hops |
Defines the range over which a multicast packet is propagated in your intranet. Communication: Routing, Tunneling (Search only) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Multicast.TIME_TO_LIVE Config Key: client.communication.multicast.timeToLive |
Socket Timeout | Long |
3000 milliseconds |
Timeout for multicast channel socket. Communication: Routing, Tunneling (Search only) Config Field: li.pitschmann.knx.core.config.CoreConfigs.Multicast.SOCKET_TIMEOUT Config Key: client.communication.multicast.socketTimeout |
Communication | |||
Executor Pool Size | Integer |
10 |
The size of communicator thread pool size that may send packets in parallel. Communication: Routing, Tunneling Config Field: li.pitschmann.knx.core.config.CoreConfigs.Communication.EXECUTOR_POOL_SIZE Config Key: client.communication.executorPoolSize |
Plugin | |||
Executor Pool Size | Integer |
10 |
The size of plugin thread pool size that may notify plugins in parallel. Config Field: li.pitschmann.knx.core.config.CoreConfigs.Plugin.EXECUTOR_POOL_SIZE Config Key: client.plugin.executorPoolSize |
Initialization Timeout | Long |
10000 milliseconds |
Timeout how long a plugin may take for initialization before it is rejected by the plugin manager Config Field: li.pitschmann.knx.core.config.CoreConfigs.Plugin.INITIALIZATION_TIMEOUT Config Key: client.plugin.initializationTimeout |