A CLI client for discovering KNX/netIP servers on the network.
Discoverer shows how to implement and start a discovery agent that discovers KNX/netIP servers on the network.
Below are the parameters that the client allows.
Usage: ./discoverer [options] Options: -h, --help Displays this help. -t, --timeout <timeout> Discovery response timeout in seconds. -n, --nat Use Network Address Translation to traverse across network routers. -u, --unicast Force unicast response. (defaults to multicast response) -a, --localAddress <localAddress> The local IP address a response shall be sent to. Implies <unicast> -p, --localPort <localPort> The local UDP port a response shall be sent to (defaults to system assigned). Implies <unicast>. -m, --searchMode <searchMode> Specifies the mode used to send search request. Possible values: (default, extended, both). --filterProg Limit search responses to devices in programming mode. Implies search mode extended or both. --filterMAC <MAC> Limit search responses to the given MAC address. Implies search mode extended or both. --filterService <Service> Limit search responses to devices supporting the given KNXnet/IP service family in at least the given version (e.g. 0202). Implies search mode extended or both. --descriptionType <Type> Force returning DIBs inside the search responses to to at least of the given set of IDs (e.g. 010208). Implies search mode extended or both.
By default the client uses the default network interface determined by the Operating System if no local IP address given. However, if an IP is given, the client will use the interface attached to that IP.
The following lines show a few examples of how to use the client:
./discoverer -m extended -a 127.0.0.1 -p 5543 Device used to send the search request: Network interface: lo, address: 127.0.0.1, port: 5543 No server(s) found on the network.
The command above uses the loopback interface. No KNX servers are available on this interface and therefore none are showed.
./discoverer -m extended Device used to send the search request: Network interface: Unknown, address: 0.0.0.0, port: 0 1 server(s) found on the network. Server: IPR/S3.5.1 IP Router,MDRC Individual address: 1.1.0 Server control endpoint: 10.9.78.33:3671 Supported services: KNXnet/IP Core, Version: 2 KNXnet/IP Device Management, Version: 2 KNXnet/IP Tunnel, Version: 2 KNXnet/IP Routing, Version: 2 KNXnet/IP Remote Configuration, Version: 1 KNXnet/IP Security, Version: 1 Extended hardware information: Mask version: 091a Max. local APDU length: 254 Medium status: Communication possible
Unlike the previous command example, this one uses the default network interface determined by the OS and shows that there is one KNX server on the network with 10.9.78.33 and listening on port 3671. The
searchMode
parameter refers to the KNXnet/IP Core version used. The
extended
mode indicates version 2 and can make use of extended search parameters.
./discoverer -m extended --filterService 0202 Device used to send the search request: Network interface: Unknown, address: 0.0.0.0, port: 0 1 server(s) found on the network. Server: IPR/S3.5.1 IP Router,MDRC Individual address: 1.1.0 Server control endpoint: 10.9.78.33:3671 Supported services: KNXnet/IP Core, Version: 2 KNXnet/IP Device Management, Version: 2 KNXnet/IP Tunnel, Version: 2 KNXnet/IP Routing, Version: 2 KNXnet/IP Remote Configuration, Version: 1 KNXnet/IP Security, Version: 1 Extended hardware information: Mask version: 091a Max. local APDU length: 254 Medium status: Communication possible
The above command makes use of the extended search parameters available only in KNXnet/IP Core version 2. It limits the search responses to devices supporting the given KNXnet/IP service family 02 and in at least the given version 02.
In a network with two KNX routers, one of them only supporting KNXnet/IP Core Version 1, the output showed by the client with the default
searchMode
parameter set would be as follows:
./discoverer -m default Device used to send the search request: Network interface: Unknown, address: 0.0.0.0, port: 0 2 server(s) found on the network. Server: IPR/S3.5.1 IP Router,MDRC Individual address: 1.1.0 Server control endpoint: 10.9.78.33:3671 Supported services: KNXnet/IP Core, Version: 2 KNXnet/IP Device Management, Version: 2 KNXnet/IP Tunnel, Version: 2 KNXnet/IP Routing, Version: 2 KNXnet/IP Remote Configuration, Version: 1 Server: IPS/S3.1.1 IP-Schnittstelle,RE Individual address: 1.1.250 Server control endpoint: 10.9.78.81:3671 Supported services: KNXnet/IP Core, Version: 1 KNXnet/IP Device Management, Version: 1 KNXnet/IP Tunnel, Version: 1 KNXnet/IP Remote Configuration, Version: 1
The client delegates all the implementation of the KNX discovery to a QKnxNetIpServerDiscoveryAgent 实例。
int main(int argc, char *argv[]) { ... QKnxNetIpServerDiscoveryAgent agent;
The discovery agent is started here:
int main(int argc, char *argv[]) { ... QKnxNetIpServerDiscoveryAgent agent; ... QObject::connect(&agent, &QKnxNetIpServerDiscoveryAgent::finished, &discoverer, &QCoreApplication::quit); if (!parser.isSet("localAddress")) { agent.start(QKnxNetIpServerDiscoveryAgent::InterfaceType::Ethernet | QKnxNetIpServerDiscoveryAgent::InterfaceType::Wifi); } else { agent.start(QVector<QHostAddress> { agent.localAddress() }); } if (agent.error() == QKnxNetIpServerDiscoveryAgent::Error::None && agent.state() == QKnxNetIpServerDiscoveryAgent::State::Running) { discoverer.exec(); ... }
When the agent finishes discovering the servers, the main function of the client is resumed. The above code snippet shows how the QKnxNetIpServerDiscoveryAgent::finished () signal triggers a call to QCoreApplication::quit (). The client execution then keeps going after the QCoreApplication::exec ().
Finally, we recover a list of servers and output the information found:
int main(int argc, char *argv[]) { ... if (agent.error() == QKnxNetIpServerDiscoveryAgent::Error::None && agent.state() == QKnxNetIpServerDiscoveryAgent::State::Running) { discoverer.exec(); } const auto servers = agent.discoveredServers(); if (servers.size() > 0) { qInfo().noquote() << Qt::endl << QString::fromLatin1("%1 server(s) found on the network.") .arg(servers.size()); for (auto server : servers) { qInfo().noquote() << QString::fromLatin1(" Network interface: %1, address: %2") .arg(server.networkInterface().humanReadableName(), server.hostAddress().toString()); qInfo().noquote() << QString::fromLatin1(" Server: %1").arg(server.deviceName()); qInfo().noquote() << QString::fromLatin1(" Individual address: %1").arg(server .individualAddress().toString()); qInfo().noquote() << QString::fromLatin1(" Server control endpoint: %1:%2") .arg(server.controlEndpointAddress().toString()).arg(server.controlEndpointPort()); const auto services = server.supportedServices(); qInfo().noquote() << QString::fromLatin1(" Supported services:"); for (const auto service : services) { qInfo().noquote() << QString::fromLatin1(" KNXnet/IP %1, Version: %2") .arg(familyToString(service.ServiceFamily)).arg(service.ServiceFamilyVersion); } const auto dib = server.extendedHardware(); QKnxNetIpExtendedDeviceDibProxy hardware(dib); if (hardware.isValid()) { qInfo() << " Extended hardware information:"; qInfo().noquote() << QString::fromLatin1(" Mask version: %1").arg(hardware .deviceDescriptorType0(), 4, 16, QLatin1Char('0')); qInfo().noquote() << QString::fromLatin1(" Max. local APDU length: %1") .arg(hardware.maximumLocalApduLength()); auto status = server.mediumStatus(); if (status == QKnx::MediumStatus::CommunicationPossible) qInfo() << " Medium status: Communication possible"; else if (status == QKnx::MediumStatus::CommunicationImpossible) qInfo() << " Medium status: Communication impossible"; else qInfo() << " Medium status: Unknown"; } qInfo() << ""; } } else { qInfo().noquote() << "No server(s) found on the network."; } return 0; }
文件: