# knust - a asynchronous KNX/IP Library for Rust
[](https://crates.io/crates/knust)
[](https://docs.rs/knust)
[](https://opensource.org/licenses/MIT)
knust is a high-performance, memory-safe implementation of the KNX/IP protocol for building automation systems. It provides async/await support and strong type safety while maintaining compatibility with KNX standards.
## Features
- **Async/await support** with tokio for non-blocking I/O
- **Memory-safe protocol parsing** with zero unsafe code in public API
- **Multiple connection types**: Tunneling (point-to-point) and Routing (multicast)
- **KNX IP Secure** and experimental **KNX Data Security** support
- **Gateway discovery** for automatic network configuration
- **Comprehensive error handling** with structured error types
- **Property-based testing** for correctness verification
- **Performance monitoring** and memory management
- **Extensive logging** with component-specific levels
## Cargo Features
- `dpt` (**on** by default) — datapoint-type encode/decode (DPT 1..251). Disable
for a raw-frame-only client that never interprets group values.
- `ets` (off) — ETS CSV group-address import (`parse_ets_csv`). Implies `dpt`.
- `server` (off) — act as a KNXnet/IP tunneling server (`TunnelServer::bind`).
Most consumers are clients and don't need it — see [Server](#server) below.
- `secure` (off) — KNX IP Secure (session handshake, verified against real
hardware) and KNX Data Security (group encryption, **experimental** and
unverified against a reference implementation), plus KNX keyring
(`.knxkeys`) parsing/validation. Implies `ets`.
## Quick Start
Add Knx to your `Cargo.toml`:
```toml
[dependencies]
knust = "0.1.0"
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
```
### Basic Usage
There's no built-in device abstraction layer — you send telegrams and read
group values directly. See [`examples/custom_devices.rs`](examples/custom_devices.rs)
for a pattern to build a device layer on top of these primitives.
```rust
use knust::{Knx, ConnectionConfig, ConnectionType};
use knust::protocol::{Address, GroupAddress, IndividualAddress};
use knust::protocol::telegram::{Direction, Priority, Telegram, TelegramType};
#[tokio::main]
async fn main() -> Result<(), knust::KnxError> {
// Configure connection
let config = ConnectionConfig {
connection_type: ConnectionType::Tunneling,
gateway_ip: Some("192.168.1.100".parse().unwrap()),
individual_address: IndividualAddress::new(1, 1, 240),
..Default::default()
};
// Create Knx instance
let knx = Knx::new(config).await?;
// Connect to KNX network
knx.connect().await?;
// Switch a light on (GroupValueWrite to 1/2/3)
let switch_on = Telegram {
source: IndividualAddress::new(1, 1, 240),
destination: Address::Group(GroupAddress::from_parts(1, 2, 3)?),
payload: vec![0x01],
priority: Priority::Normal,
direction: Direction::Outgoing,
telegram_type: TelegramType::GroupValueWrite,
gateway_id: None,
timestamp: std::time::SystemTime::now(),
};
knx.send_telegram(&switch_on).await?;
// Disconnect
knx.disconnect().await?;
Ok(())
}
```
### Builder Pattern
```rust
use knust::Knx;
let knx = Knx::builder()
.connection_type(ConnectionType::Tunneling)
.gateway_ip("192.168.1.100".parse().unwrap())
.individual_address(IndividualAddress::new(1, 1, 240))
.timeout_ms(5000)
.auto_reconnect(true)
.build()
.await?;
```
## Connection Types
### Tunneling (Point-to-Point)
Best for reliable communication with a single KNX/IP gateway:
```rust
let config = ConnectionConfig {
connection_type: ConnectionType::Tunneling,
gateway_ip: Some("192.168.1.100".parse().unwrap()),
gateway_port: Some(3671),
individual_address: IndividualAddress::new(1, 1, 240),
..Default::default()
};
```
### Routing (Multicast)
Best for monitoring multiple devices on the network:
```rust
let config = ConnectionConfig {
connection_type: ConnectionType::Routing,
local_ip: Some("192.168.1.50".parse().unwrap()),
individual_address: IndividualAddress::new(1, 1, 241),
..Default::default()
};
```
### Secure Connections
For encrypted communication using KNX IP Secure (requires the `secure`
feature — without it, or without `security` set, `connect()` returns a
configuration error rather than silently falling back to plaintext):
```rust
use knust::transport::SecurityConfig;
let security_config = SecurityConfig {
device_auth_password: "DeviceAuthPassword123!".to_string(),
user_password: Some("MySecurePassword".to_string()),
session_timeout: 300,
keyring_path: Some("/path/to/keyring.knxkeys".to_string()),
};
let config = ConnectionConfig {
connection_type: ConnectionType::SecureTunneling,
gateway_ip: Some("192.168.1.100".parse().unwrap()),
security: Some(security_config),
..Default::default()
};
```
## Reading Group Values
```rust
use std::time::Duration;
// Read a temperature sensor (DPT 9.001) and wait for the response
let payload = knx
.read_group_value(GroupAddress::from_parts(2, 1, 1)?, Duration::from_secs(5))
.await?;
let temperature = knust::protocol::dpt::Dpt::<knust::protocol::dpt::Temperature>::decode(&payload)?;
println!("Temperature: {:.1}°C", temperature.value().value());
```
## Gateway Discovery
Automatically discover KNX/IP gateways on your network:
```rust
use knust::transport::GatewayScanner;
let scanner = GatewayScanner::new().await?;
let gateways = scanner.discover(Duration::from_secs(10)).await?;
for gateway in gateways {
println!("Found gateway: {} at {}", gateway.name, gateway.addr);
println!(" Supports tunneling: {}", gateway.capabilities.supports_tunneling);
println!(" Supports routing: {}", gateway.capabilities.supports_routing);
}
```
## Security Features
The following require the `secure` feature.
### KNX Data Security
Encrypt group communication using KNX Data Security. **Experimental** —
unlike KNX IP Secure (the session handshake above), this hasn't been
verified against a reference implementation or real hardware, and isn't
wired into the telegram send/receive path automatically; use
`security::group::encrypt_group_payload`/`decrypt_group_payload` directly
on APDU bytes:
```rust
use knust::security::{KeyRing, SecurityKey};
let mut keyring = KeyRing::new();
// Add group keys
let group_key = SecurityKey::from_hex("0123456789ABCDEF0123456789ABCDEF")?;
keyring.add_group_key(GroupAddress::from_parts(1, 2, 1)?, group_key);
// Check if group is secured
if keyring.is_group_secured(&GroupAddress::from_parts(1, 2, 1)?) {
println!("Group 1/2/1 is secured");
}
```
### Sequence Number Validation
Protect against replay attacks:
```rust
let sender = IndividualAddress::new(1, 2, 3);
match keyring.validate_sequence(sender, sequence_number) {
Ok(()) => println!("Sequence number valid"),
Err(e) => println!("Replay attack detected: {}", e),
}
```
## Logging and Debugging
Configure comprehensive logging for troubleshooting:
```rust
use knust::{LoggingConfig, LogLevel, Component, logging::init_logging};
let mut logging_config = LoggingConfig::new();
logging_config.set_default_level(LogLevel::Info);
logging_config.set_component_level(Component::Transport, LogLevel::Debug);
logging_config.set_component_level(Component::Protocol, LogLevel::Trace);
logging_config.set_protocol_events(true);
logging_config.set_hex_dump(true);
init_logging(logging_config);
```
## Memory Management
Monitor and optimize memory usage:
```rust
// Get memory statistics
let stats = knx.memory_stats().await;
println!("Current usage: {} bytes", stats.current_usage);
println!("Peak usage: {} bytes", stats.peak_usage);
// Check memory bounds
if !knx.memory_within_bounds() {
println!("Memory usage exceeds limits!");
}
// Force cleanup
let freed = knx.force_cleanup().await;
println!("Freed {} bytes", freed);
```
## Error Handling
Knx provides comprehensive error types with context:
```rust
use knust::KnxError;
match knx.connect().await {
Ok(()) => println!("Connected successfully"),
Err(KnxError::Transport(e)) => println!("Transport error: {}", e),
Err(KnxError::Protocol(e)) => println!("Protocol error: {}", e),
Err(KnxError::Device(e)) => println!("Device error: {}", e),
Err(KnxError::Security(e)) => println!("Security error: {}", e),
Err(e) => println!("Other error: {}", e),
}
```
## Examples
The repository includes examples covering common tasks (`cargo run --example <name>`,
some require the `secure`/`ets` features):
- **custom_devices**: recommended pattern for building a device layer on `send_telegram`/`read_group_value`
- **send_telegrams**: sending raw telegrams
- **value_reader**: reading and decoding group values
- **gateway_discovery**: discovering gateways on the network
- **secure_connection**: KNX IP Secure / Data Security
- **configuration_examples**: `ConnectionConfig` variations
- **logging_demo**: component-level logging setup
- **memory_optimization_demo**: memory monitoring and cleanup
- **tunneling_connection** / **tcp_connection_demo**: UDP and TCP tunneling
- **connection_handling**: reconnect/backoff handling
- **packet_listener** / **telegram_monitor**: passive bus monitoring
- **datetime_sync**: sending DPT 10/11 time and date
- **color_dpt_demo**: RGB/RGBW/XYY color DPTs
- **sequence_validation_demo**: UDP sequence number handling
Run `ls examples/` for the full, current list.
## Configuration Files
The optional `ets` feature adds ETS CSV group-address import
(`parse_ets_csv`). The optional `secure` feature adds a KNX keyring
(`.knxkeys`) parser — see `Configuration` and `KeyringParser` in
`knust::config`. There is no ETS project (`.knxproj`/XML) import or generic
TOML/JSON application-config format.
## Server
**`TunnelServer`** (this crate, `server` feature) acts as a KNXnet/IP
gateway: `TunnelServer::bind(addr, individual_address).await?` binds a
UDP+TCP tunneling endpoint and starts serving connecting clients
immediately (`bind_secure` additionally requires KNX IP Secure). It's a
software bridge endpoint, not a full line of real device addresses.
## Testing
Knx includes comprehensive test coverage with both unit tests and property-based tests:
```bash
# Run all tests
cargo test
# Run property-based tests
cargo test property_
# Run integration tests
cargo test --test integration_tests
# Run with logging
RUST_LOG=debug cargo test
```
## Performance
Knx is designed for high performance:
- **Zero-copy parsing** where possible
- **Async I/O** with tokio for scalability
- **Memory pooling** for connection management
- **Hot path optimization** for telegram processing
- **Configurable memory limits** and cleanup
## Compatibility
- **Rust Edition**: 2024
- **MSRV**: 1.85.1
- **KNX Standards**: KNX/IP, KNX IP Secure; KNX Data Security is experimental (see crate docs)
- **Platforms**: Linux, macOS, Windows
- **Async Runtime**: tokio
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- Based on the [xknx Python library](https://github.com/xknx/xknx)
- KNX Association for the protocol specifications
- Rust community for excellent async ecosystem