diff --git a/debian/control b/debian/control
index f63e1acf..4d4348fa 100644
--- a/debian/control
+++ b/debian/control
@@ -395,9 +395,6 @@ Package: nymea-plugin-networkdetector
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
- nmap,
- fping,
- arping,
Conflicts: nymea-plugins-translations (< 1.0.1)
Description: nymea integration plugin for networkdetector
This package contains the nymea integration plugin for detecting and monitoring
diff --git a/networkdetector/README.md b/networkdetector/README.md
index 8c2e0064..3957abc7 100644
--- a/networkdetector/README.md
+++ b/networkdetector/README.md
@@ -1,20 +1,11 @@
# Network detector
-This plugin allows to find and monitor network devices in your local network by using the hostname of the devices.
+This plugin allows to find and monitor network devices in your local network by using the MAC address of the device.
-## Supported Things
+## Supported things
-* Network Device
+* Network device
+ * Information about the network device like IP, hostname, MAC address manufacturer
* Presence sensor appearance
- * Grace period adjustable
* Present and last seen state
-## Requirements
-
-* The application `nmap` has to be installed and nymea has to run as `root`.
-* The network devices needs to be in the same local area network as nymea.
-* The package 'nymea-plugin-networkdetector'
-
-## More
-
-https://nmap.org/
diff --git a/networkdetector/broadcastping.cpp b/networkdetector/broadcastping.cpp
deleted file mode 100644
index 84438989..00000000
--- a/networkdetector/broadcastping.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#include "broadcastping.h"
-#include "extern-plugininfo.h"
-
-#include
-#include
-
-BroadcastPing::BroadcastPing(QObject *parent) : QObject(parent)
-{
-
-}
-
-void BroadcastPing::run()
-{
- qDeleteAll(m_runningPings.keys());
- m_runningPings.clear();
-
- foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
- if (!interface.flags().testFlag(QNetworkInterface::IsUp) || !interface.flags().testFlag(QNetworkInterface::CanBroadcast) || interface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
- continue;
- }
- foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
- if (addressEntry.broadcast().isNull()) {
- continue;
- }
- qCDebug(dcNetworkDetector()) << "Sending Broadcast Ping on" << addressEntry.broadcast().toString() + '/' + QString::number(addressEntry.prefixLength()) + "...";
- QProcess *p = new QProcess(this);
- m_runningPings.insert(p, addressEntry);
- p->start("fping", {"-a", "-c", "1", "-g", addressEntry.broadcast().toString() + "/" + QString::number(addressEntry.prefixLength())});
- connect(p, SIGNAL(finished(int)), this, SLOT(broadcastPingFinished(int)));
- }
- }
- if (m_runningPings.isEmpty()) {
- qCWarning(dcNetworkDetector()) << "Cound not find any suitable interface for broadcast pinging";
- emit finished();
- }
-}
-
-void BroadcastPing::broadcastPingFinished(int exitCode)
-{
- Q_UNUSED(exitCode);
- QProcess *p = static_cast(sender());
- QNetworkAddressEntry addressEntry = m_runningPings.take(p);
- qCDebug(dcNetworkDetector()) << "Broadcast ping finished for network" << addressEntry.broadcast().toString() + '/' + QString::number(addressEntry.prefixLength());
-// qCDebug(dcNetworkDetector()) << p->readAllStandardError();
- p->deleteLater();
-
- if (m_runningPings.isEmpty()) {
- qCDebug(dcNetworkDetector()) << "All broadcast pings finished";
- emit finished();
- }
-}
diff --git a/networkdetector/broadcastping.h b/networkdetector/broadcastping.h
deleted file mode 100644
index c49915fe..00000000
--- a/networkdetector/broadcastping.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef BROADCASTPING_H
-#define BROADCASTPING_H
-
-#include
-#include
-#include
-#include
-
-class BroadcastPing : public QObject
-{
- Q_OBJECT
-public:
- explicit BroadcastPing(QObject *parent = nullptr);
-
-signals:
- void finished();
-
-public slots:
- void run();
-
-private slots:
- void broadcastPingFinished(int exitCode);
-
-private:
- QHash m_runningPings;
-};
-
-#endif // BROADCASTPING_H
diff --git a/networkdetector/devicemonitor.cpp b/networkdetector/devicemonitor.cpp
deleted file mode 100644
index 5c3ad603..00000000
--- a/networkdetector/devicemonitor.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#include "devicemonitor.h"
-
-#include "extern-plugininfo.h"
-
-#include
-
-DeviceMonitor::DeviceMonitor(const QString &name, const QString &macAddress, const QString &ipAddress, bool initialState, QObject *parent):
- QObject(parent),
- m_name(name),
- m_macAddress(macAddress),
- m_ipAddress(ipAddress),
- m_reachable(initialState)
-{
- m_arpLookupProcess = new QProcess(this);
- connect(m_arpLookupProcess, SIGNAL(finished(int)), this, SLOT(arpLookupFinished(int)));
-
- m_arpingProcess = new QProcess(this);
- m_arpingProcess->setProcessChannelMode(QProcess::MergedChannels);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
- // Actually we'd need this fix on older platforms too, but it's hard to figure this out without this API...
- connect(m_arpingProcess, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
- if (error == QProcess::FailedToStart) {
- warn(QString("arping process failed to start. Falling back to ping. This plugin might not work properly on this system."));
- ping();
- }
- });
-#endif
- connect(m_arpingProcess, SIGNAL(finished(int)), this, SLOT(arpingFinished(int)));
-
- m_pingProcess = new QProcess(this);
- m_pingProcess->setProcessChannelMode(QProcess::MergedChannels);
- connect(m_pingProcess, SIGNAL(finished(int)), this, SLOT(pingFinished(int)));
-}
-
-DeviceMonitor::~DeviceMonitor()
-{
-}
-
-void DeviceMonitor::setGracePeriod(int minutes)
-{
- log("Setting grace period to " + QString::number(minutes) + " minutes.");
- m_gracePeriod = minutes;
-}
-
-void DeviceMonitor::update()
-{
- if (m_arpingProcess->state() != QProcess::NotRunning || m_pingProcess->state() != QProcess::NotRunning) {
-// log("Previous ping still running. Not updating.");
- return;
- }
- lookupArpCache();
-}
-
-void DeviceMonitor::lookupArpCache()
-{
- m_arpLookupProcess->start("ip", {"-4", "-s", "neighbor", "list"});
-}
-
-void DeviceMonitor::arpLookupFinished(int exitCode)
-{
- if (exitCode != 0) {
- warn("Error looking up ARP cache.");
- return;
- }
-
- QString data = QString::fromLatin1(m_arpLookupProcess->readAll());
- bool found = false;
- bool needsPing = true;
- QString mostRecentIP = m_ipAddress;
- qlonglong secsSinceLastSeen = -1;
- foreach (QString line, data.split('\n')) {
- line.replace(QRegExp("[ ]{1,}"), " ");
- QStringList parts = line.split(" ");
- int lladdrIndex = parts.indexOf("lladdr");
- if (lladdrIndex == -1 || parts.count() <= lladdrIndex) {
- continue;
- }
- QString entryIP = parts.first();
- QString entryMAC = parts.at(lladdrIndex + 1);
-
- if (entryMAC.toLower() == m_macAddress.toLower()) {
- found = true;
- QString entryIP = parts.first();
- if (parts.last() == "REACHABLE") {
- log("Device found in ARP cache and claims to be REACHABLE (Cache IP: " + entryIP + ")");
- if (!m_reachable) {
- m_reachable = true;
- emit reachableChanged(true);
- }
- emit seen();
- m_lastSeenTime = QDateTime::currentDateTime();
- // Verify if IP address is still the same
- if (entryIP != mostRecentIP) {
- mostRecentIP = entryIP;
- }
- // If we have a reachable entry, stop processing here
- needsPing = false;
- break;
- } else {
- // ARP claims the thing to be stale... Flagging thing to require a ping.
- log("Device found in ARP cache but is marked as " + parts.last() + " (Cache IP: " + entryIP + ")");
-
- int usedIndex = parts.indexOf("used");
- if (usedIndex >= 0 && parts.count() > usedIndex + 1) {
- QString usedFields = parts.at(usedIndex + 1);
- qlonglong newSecsSinceLastSeen = usedFields.split("/").first().toInt();
- if (secsSinceLastSeen == -1 || newSecsSinceLastSeen < secsSinceLastSeen) {
- secsSinceLastSeen = newSecsSinceLastSeen;
- mostRecentIP = entryIP;
- }
- }
- }
- } else if (entryIP == m_ipAddress) {
- warn("There seems to be a thing with our IP but different MAC. Resetting IP config.");
- if (mostRecentIP == m_ipAddress) {
- mostRecentIP.clear();
- }
- }
- }
- if (mostRecentIP != m_ipAddress) {
- log("Device has changed IP: " + m_ipAddress + " -> " + mostRecentIP + ")");
- m_ipAddress = mostRecentIP;
- emit addressChanged(mostRecentIP);
- }
- if (m_ipAddress.isEmpty()) {
- warn("Device not found in ARP cache and no IP config available. Marking as gone.");
- if (m_reachable) {
- m_reachable = false;
- emit reachableChanged(false);
- }
- return;
- }
- if (!found) {
- log("Device not found in ARP cache.");
- arping();
- } else if (needsPing) {
- arping();
- }
-}
-
-void DeviceMonitor::arping()
-{
- QNetworkInterface targetInterface;
- foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
- foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
- QHostAddress clientAddress(m_ipAddress);
- if (clientAddress.isInSubnet(addressEntry.ip(), addressEntry.prefixLength())) {
- targetInterface = interface;
- break;
- }
- }
- }
- if (!targetInterface.isValid()) {
- warn("Could not find a suitable interface to ARP Ping.");
- if (m_reachable) {
- m_reachable = false;
- emit reachableChanged(false);
- }
- return;
- }
-
- log("Sending ARP Ping to " + m_ipAddress + "...");
- m_arpingProcess->start("arping", {"-I", targetInterface.name(), "-f", "-w", "30", m_ipAddress});
-}
-
-void DeviceMonitor::arpingFinished(int exitCode)
-{
- if (exitCode == 0) {
- // we were able to ping the thing
- log("ARP Ping successful.");
- if (!m_reachable) {
- m_reachable = true;
- emit reachableChanged(true);
- }
- emit seen();
- m_lastSeenTime = QDateTime::currentDateTime();
- } else {
- log("ARP Ping failed.");
- ping();
- }
- // read data to discard it from socket
- QString data = QString::fromLatin1(m_arpingProcess->readAll());
- Q_UNUSED(data)
-// qCDebug(dcNetworkDetector()) << "have ping data" << data;
-}
-
-void DeviceMonitor::ping()
-{
- log("Sending ICMP Ping to " + m_ipAddress + "...");
- m_pingProcess->start("ping", {"-c", "30", m_ipAddress});
-}
-
-void DeviceMonitor::pingFinished(int exitCode)
-
-{
- if (exitCode == 0) {
- // we were able to ping the thing
- log("ICMP Ping successful.");
- if (!m_reachable) {
- m_reachable = true;
- emit reachableChanged(true);
- }
- emit seen();
- m_lastSeenTime = QDateTime::currentDateTime();
- } else {
- log("ICMP Ping failed. Last seen: " + m_lastSeenTime.toString() + ", grace period: " + QString::number(m_gracePeriod) + " (until " + m_lastSeenTime.addSecs(60 * m_gracePeriod).toString() + ")");
- if (m_reachable && m_lastSeenTime.addSecs(m_gracePeriod * 60) < QDateTime::currentDateTime()) {
- log("Exceeded grace period of " + QString::number(m_gracePeriod) + " minutes. Marking thing as offline.");
- m_reachable = false;
- emit reachableChanged(false);
- }
- }
- // read data to discard it from socket
- QString data = QString::fromLatin1(m_pingProcess->readAll());
- Q_UNUSED(data)
-// qCDebug(dcNetworkDetector()) << "have ping data" << data;
-}
-
-void DeviceMonitor::log(const QString &message)
-{
- qCDebug(dcNetworkDetector()).noquote().nospace() << m_name << " (" << m_macAddress << ", " << m_ipAddress << "): " << message;
-}
-
-void DeviceMonitor::warn(const QString &message)
-{
- qCWarning(dcNetworkDetector()).noquote().nospace() << m_name << " (" << m_macAddress << ", " << m_ipAddress << "): " << message;
-}
diff --git a/networkdetector/devicemonitor.h b/networkdetector/devicemonitor.h
deleted file mode 100644
index 630a2d81..00000000
--- a/networkdetector/devicemonitor.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef DEVICEMONITOR_H
-#define DEVICEMONITOR_H
-
-#include
-#include
-#include
-
-class DeviceMonitor : public QObject
-{
- Q_OBJECT
-public:
- explicit DeviceMonitor(const QString &name, const QString &macAddress, const QString &ipAddress, bool initialState, QObject *parent = nullptr);
-
- ~DeviceMonitor();
-
- void setGracePeriod(int minutes);
-
- void update();
-
-signals:
- void addressChanged(const QString &address);
- void reachableChanged(bool reachable);
- void seen();
-
-private:
- void lookupArpCache();
- void arping();
- void ping();
-
- void log(const QString &message);
- void warn(const QString &message);
-
-private slots:
- void arpLookupFinished(int exitCode);
- void arpingFinished(int exitCode);
- void pingFinished(int exitCode);
-
-private:
- QString m_name;
- QString m_macAddress;
- QString m_ipAddress;
- QDateTime m_lastSeenTime;
-
- bool m_reachable = false;
- int m_gracePeriod = 5;
-
- QProcess *m_arpLookupProcess = nullptr;
- QProcess *m_arpingProcess = nullptr;
- QProcess *m_pingProcess = nullptr;
-};
-
-#endif // DEVICEMONITOR_H
diff --git a/networkdetector/discovery.cpp b/networkdetector/discovery.cpp
deleted file mode 100644
index 979f3d17..00000000
--- a/networkdetector/discovery.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#include "discovery.h"
-#include "extern-plugininfo.h"
-
-#include
-#include
-#include
-#include
-#include
-
-Discovery::Discovery(QObject *parent) : QObject(parent)
-{
- connect(&m_timeoutTimer, &QTimer::timeout, this, &Discovery::onTimeout);
-}
-
-void Discovery::discoverHosts(int timeout)
-{
- if (isRunning()) {
- qWarning(dcNetworkDetector()) << "Discovery already running. Cannot start twice.";
- return;
- }
- m_timeoutTimer.start(timeout * 1000);
-
- foreach (const QString &target, getDefaultTargets()) {
- QProcess *discoveryProcess = new QProcess(this);
- m_discoveryProcesses.append(discoveryProcess);
- connect(discoveryProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(discoveryFinished(int,QProcess::ExitStatus)));
-
- QStringList arguments;
- arguments << "-oX" << "-" << "-n" << "-sn";
- arguments << target;
-
- qCDebug(dcNetworkDetector) << "Scanning network:" << "nmap" << arguments.join(" ");
- discoveryProcess->start(QStringLiteral("nmap"), arguments);
- }
-
-}
-
-void Discovery::abort()
-{
- foreach (QProcess *discoveryProcess, m_discoveryProcesses) {
- if (discoveryProcess->state() == QProcess::Running) {
- qCDebug(dcNetworkDetector()) << "Kill running discovery process";
- discoveryProcess->terminate();
- discoveryProcess->waitForFinished(5000);
- }
- }
- foreach (QProcess *p, m_pendingArpLookups.keys()) {
- p->terminate();
- delete p;
- }
- m_pendingArpLookups.clear();
- m_pendingNameLookups.clear();
- qDeleteAll(m_scanResults);
- m_scanResults.clear();
-}
-
-bool Discovery::isRunning() const
-{
- return !m_discoveryProcesses.isEmpty() || !m_pendingArpLookups.isEmpty() || !m_pendingNameLookups.isEmpty();
-}
-
-void Discovery::discoveryFinished(int exitCode, QProcess::ExitStatus exitStatus)
-{
- QProcess *discoveryProcess = static_cast(sender());
-
- if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
- qCWarning(dcNetworkDetector()) << "Nmap error failed. Is nmap installed correctly?";
- m_discoveryProcesses.removeAll(discoveryProcess);
- discoveryProcess->deleteLater();
- discoveryProcess = nullptr;
- finishDiscovery();
- return;
- }
-
- QByteArray data = discoveryProcess->readAll();
- m_discoveryProcesses.removeAll(discoveryProcess);
- discoveryProcess->deleteLater();
- discoveryProcess = nullptr;
-
- QXmlStreamReader reader(data);
-
- int foundHosts = 0;
-
- while (!reader.atEnd() && !reader.hasError()) {
- QXmlStreamReader::TokenType token = reader.readNext();
- if(token == QXmlStreamReader::StartDocument)
- continue;
-
- if(token == QXmlStreamReader::StartElement && reader.name() == "host") {
- bool isUp = false;
- QString address;
- QString macAddress;
- QString vendor;
- while (!reader.atEnd() && !reader.hasError() && !(token == QXmlStreamReader::EndElement && reader.name() == "host")) {
- token = reader.readNext();
-
- if (reader.name() == "address") {
- QString addr = reader.attributes().value("addr").toString();
- QString type = reader.attributes().value("addrtype").toString();
- if (type == "ipv4" && !addr.isEmpty()) {
- address = addr;
- } else if (type == "mac") {
- macAddress = addr;
- vendor = reader.attributes().value("vendor").toString();
- }
- }
-
- if (reader.name() == "status") {
- QString state = reader.attributes().value("state").toString();
- if (!state.isEmpty())
- isUp = state == "up";
- }
- }
-
- if (isUp) {
- foundHosts++;
- qCDebug(dcNetworkDetector()) << "Have host:" << address;
-
- Host *host = new Host();
- host->setAddress(address);
-
- if (!macAddress.isEmpty()) {
- host->setMacAddress(macAddress);
- } else {
- QProcess *arpLookup = new QProcess(this);
- m_pendingArpLookups.insert(arpLookup, host);
- connect(arpLookup, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(arpLookupDone(int,QProcess::ExitStatus)));
- arpLookup->start("arp", {"-vn"});
- }
-
- host->setHostName(vendor);
- QHostInfo::lookupHost(address, this, SLOT(hostLookupDone(QHostInfo)));
- m_pendingNameLookups.insert(address, host);
-
- m_scanResults.append(host);
- }
- }
- }
-
- if (foundHosts == 0 && m_discoveryProcesses.isEmpty()) {
- qCDebug(dcNetworkDetector()) << "Network scan successful but no hosts found in this network";
- finishDiscovery();
- }
-}
-
-void Discovery::hostLookupDone(const QHostInfo &info)
-{
- Host *host = m_pendingNameLookups.take(info.addresses().first().toString());
- if (!host) {
- // Probably aborted...
- return;
- }
- if (info.error() != QHostInfo::NoError) {
- qWarning(dcNetworkDetector()) << "Host lookup failed:" << info.errorString();
- }
- if (host->hostName().isEmpty() || info.hostName() != host->address()) {
- host->setHostName(info.hostName());
- }
-
- finishDiscovery();
-}
-
-void Discovery::arpLookupDone(int exitCode, QProcess::ExitStatus exitStatus)
-{
- QProcess *p = static_cast(sender());
- p->deleteLater();
-
- Host *host = m_pendingArpLookups.take(p);
-
- if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
- qCWarning(dcNetworkDetector()) << "ARP lookup process failed for host" << host->address();
- finishDiscovery();
- return;
- }
-
- QString data = QString::fromLatin1(p->readAll());
- foreach (QString line, data.split('\n')) {
- line.replace(QRegExp("[ ]{1,}"), " ");
- QStringList parts = line.split(" ");
- if (parts.count() >= 3 && parts.first() == host->address() && parts.at(1) == "ether") {
- host->setMacAddress(parts.at(2));
- break;
- }
- }
- finishDiscovery();
-}
-
-void Discovery::onTimeout()
-{
- qWarning(dcNetworkDetector()) << "Timeout hit. Stopping discovery";
- while (!m_discoveryProcesses.isEmpty()) {
- QProcess *discoveryProcess = m_discoveryProcesses.takeFirst();
- disconnect(this, SLOT(discoveryFinished(int,QProcess::ExitStatus)));
- discoveryProcess->terminate();
- delete discoveryProcess;
- }
- foreach (QProcess *p, m_pendingArpLookups.keys()) {
- p->terminate();
- m_scanResults.removeAll(m_pendingArpLookups.value(p));
- delete p;
- }
- m_pendingArpLookups.clear();
- m_pendingNameLookups.clear();
- finishDiscovery();
-}
-
-QStringList Discovery::getDefaultTargets()
-{
- QStringList targets;
- foreach (const QHostAddress &interface, QNetworkInterface::allAddresses()) {
- if (!interface.isLoopback() && interface.scopeId().isEmpty() && interface.protocol() == QAbstractSocket::IPv4Protocol) {
- QPair pair = QHostAddress::parseSubnet(interface.toString() + "/24");
- QString newTarget = QString("%1/%2").arg(pair.first.toString()).arg(pair.second);
- if (!targets.contains(newTarget)) {
- targets.append(newTarget);
- }
- }
- }
- return targets;
-}
-
-void Discovery::finishDiscovery()
-{
- if (m_discoveryProcesses.count() > 0 || m_pendingNameLookups.count() > 0 || m_pendingArpLookups.count() > 0) {
- // Still busy...
- return;
- }
-
- QList hosts;
- foreach (Host *host, m_scanResults) {
- if (!host->macAddress().isEmpty()) {
- hosts.append(*host);
- }
- }
- qDeleteAll(m_scanResults);
- m_scanResults.clear();
-
- qCDebug(dcNetworkDetector()) << "Emitting thing discovered for" << hosts.count() << "devices";
- m_timeoutTimer.stop();
- emit finished(hosts);
-}
diff --git a/networkdetector/discovery.h b/networkdetector/discovery.h
deleted file mode 100644
index b74fe2cb..00000000
--- a/networkdetector/discovery.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef DISCOVERY_H
-#define DISCOVERY_H
-
-#include
-#include
-#include
-#include
-
-#include "host.h"
-
-class Discovery : public QObject
-{
- Q_OBJECT
-public:
- explicit Discovery(QObject *parent = nullptr);
-
- void discoverHosts(int timeout);
- void abort();
-
- bool isRunning() const;
-
-
-signals:
- void finished(QList hosts);
-
-private:
- QStringList getDefaultTargets();
-
- void finishDiscovery();
-
-private slots:
- void discoveryFinished(int exitCode, QProcess::ExitStatus exitStatus);
- void hostLookupDone(const QHostInfo &info);
- void arpLookupDone(int exitCode, QProcess::ExitStatus exitStatus);
- void onTimeout();
-
-private:
- QList m_discoveryProcesses;
- QTimer m_timeoutTimer;
-
- QHash m_pendingArpLookups;
- QHash m_pendingNameLookups;
- QList m_scanResults;
-
-};
-
-#endif // DISCOVERY_H
diff --git a/networkdetector/host.cpp b/networkdetector/host.cpp
deleted file mode 100644
index 2aec4ab6..00000000
--- a/networkdetector/host.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#include "host.h"
-
-Host::Host()
-{
- qRegisterMetaType();
- qRegisterMetaType >();
-}
-
-QString Host::macAddress() const
-{
- return m_macAddress;
-}
-
-void Host::setMacAddress(const QString &macAddress)
-{
- m_macAddress = macAddress;
-}
-
-QString Host::hostName() const
-{
- return m_hostName;
-}
-
-void Host::setHostName(const QString &hostName)
-{
- m_hostName = hostName;
-}
-
-QString Host::address() const
-{
- return m_address;
-}
-
-void Host::setAddress(const QString &address)
-{
- m_address = address;
-}
-
-void Host::seen()
-{
- m_lastSeenTime = QDateTime::currentDateTime();
-}
-
-QDateTime Host::lastSeenTime() const
-{
- return m_lastSeenTime;
-}
-
-bool Host::reachable() const
-{
- return m_reachable;
-}
-
-void Host::setReachable(bool reachable)
-{
- m_reachable = reachable;
-}
-
-QDebug operator<<(QDebug dbg, const Host &host)
-{
- dbg.nospace() << "Host(" << host.macAddress() << "," << host.hostName() << ", " << host.address() << ", " << (host.reachable() ? "up" : "down") << ")";
- return dbg.space();
-}
diff --git a/networkdetector/host.h b/networkdetector/host.h
deleted file mode 100644
index 84e48b0d..00000000
--- a/networkdetector/host.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef HOST_H
-#define HOST_H
-
-#include
-#include
-#include
-
-class Host
-{
-public:
- Host();
-
- QString macAddress() const;
- void setMacAddress(const QString &macAddress);
-
- QString hostName() const;
- void setHostName(const QString &hostName);
-
- QString address() const;
- void setAddress(const QString &address);
-
- void seen();
- QDateTime lastSeenTime() const;
-
- bool reachable() const;
- void setReachable(bool reachable);
-
-private:
- QString m_macAddress;
- QString m_hostName;
- QString m_address;
- QDateTime m_lastSeenTime;
- bool m_reachable;
-};
-Q_DECLARE_METATYPE(Host)
-
-QDebug operator<<(QDebug dbg, const Host &host);
-
-#endif // HOST_H
diff --git a/networkdetector/integrationpluginnetworkdetector.cpp b/networkdetector/integrationpluginnetworkdetector.cpp
index 02d609cd..a13d7bd7 100644
--- a/networkdetector/integrationpluginnetworkdetector.cpp
+++ b/networkdetector/integrationpluginnetworkdetector.cpp
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
-* Copyright 2013 - 2020, nymea GmbH
+* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@@ -30,7 +30,6 @@
#include "integrationpluginnetworkdetector.h"
-#include "integrations/thing.h"
#include "plugininfo.h"
#include
@@ -38,131 +37,187 @@
IntegrationPluginNetworkDetector::IntegrationPluginNetworkDetector()
{
- m_broadcastPing = new BroadcastPing(this);
- connect(m_broadcastPing, &BroadcastPing::finished, this, &IntegrationPluginNetworkDetector::broadcastPingFinished);
+
}
+
IntegrationPluginNetworkDetector::~IntegrationPluginNetworkDetector()
{
+
}
void IntegrationPluginNetworkDetector::init()
{
+
+}
+
+void IntegrationPluginNetworkDetector::discoverThings(ThingDiscoveryInfo *info)
+{
+ if (!hardwareManager()->networkDeviceDiscovery()->available()) {
+ qCWarning(dcNetworkDetector()) << "Failed to discover network devices. The network device discovery is not available.";
+ info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Unable to discovery devices in your network."));
+ return;
+ }
+
+ qCDebug(dcNetworkDetector()) << "Starting network discovery...";
+ NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
+ connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, [=](const QHostAddress &address){
+ qCDebug(dcNetworkDetector()) << "Address discovered" << address.toString();
+ });
+
+ connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, [=](const NetworkDeviceInfo &networkDeviceInfo){
+ qCDebug(dcNetworkDetector()) << "-->" << networkDeviceInfo;
+ });
+
+ connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
+ ThingDescriptors descriptors;
+ qCDebug(dcNetworkDetector()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "devices";
+ foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
+
+ qCDebug(dcNetworkDetector()) << "-->" << networkDeviceInfo;
+ QString title;
+ if (networkDeviceInfo.hostName().isEmpty()) {
+ title = networkDeviceInfo.macAddress();
+ } else {
+ title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.macAddress() + ")";
+ }
+ QString description;
+ if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
+ description = networkDeviceInfo.address().toString();
+ } else {
+ description = networkDeviceInfo.address().toString() + " - " + networkDeviceInfo.macAddressManufacturer();
+ }
+
+ ThingDescriptor descriptor(networkDeviceThingClassId, title, description);
+ ParamList params;
+ params.append(Param(networkDeviceThingMacAddressParamTypeId, networkDeviceInfo.macAddress()));
+ descriptor.setParams(params);
+
+ // Check if we already have set up this device
+ Things existingThings = myThings().filterByParam(networkDeviceThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
+ if (existingThings.count() == 1) {
+ qCDebug(dcNetworkDetector()) << "This network device already exists in the system" << networkDeviceInfo;
+ descriptor.setThingId(existingThings.first()->id());
+ }
+ descriptors.append(descriptor);
+ }
+ info->addThingDescriptors(descriptors);
+ info->finish(Thing::ThingErrorNoError);
+ });
}
void IntegrationPluginNetworkDetector::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcNetworkDetector()) << "Setup" << thing->name() << thing->params();
- DeviceMonitor *monitor = new DeviceMonitor(thing->name(),
- thing->paramValue(networkDeviceThingMacAddressParamTypeId).toString(),
- thing->paramValue(networkDeviceThingAddressParamTypeId).toString(),
- thing->stateValue(networkDeviceIsPresentStateTypeId).toBool(),
- this);
- connect(monitor, &DeviceMonitor::reachableChanged, this, &IntegrationPluginNetworkDetector::deviceReachableChanged);
- connect(monitor, &DeviceMonitor::addressChanged, this, &IntegrationPluginNetworkDetector::deviceAddressChanged);
- connect(monitor, &DeviceMonitor::seen, this, &IntegrationPluginNetworkDetector::deviceSeen);
- monitor->setGracePeriod(thing->setting(networkDeviceSettingsGracePeriodParamTypeId).toInt());
- m_monitors.insert(monitor, thing);
- connect(thing, &Thing::settingChanged, this, [this, thing](const ParamTypeId ¶mTypeId, const QVariant &value){
- if (paramTypeId != networkDeviceSettingsGracePeriodParamTypeId) {
+ if (thing->thingClassId() == networkDeviceThingClassId) {
+
+ MacAddress macAddress(thing->paramValue(networkDeviceThingMacAddressParamTypeId).toString());
+ if (macAddress.isNull()) {
+ qCWarning(dcNetworkDetector()) << "Invalid mac address:" << thing->paramValue(networkDeviceThingMacAddressParamTypeId).toString();
+ info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The configured MAC address is not valid."));
return;
}
- DeviceMonitor *monitor = m_monitors.key(thing);
- if (monitor) {
- monitor->setGracePeriod(value.toInt());
- }
- });
- if (!m_pluginTimer) {
- m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30);
- connect(m_pluginTimer, &PluginTimer::timeout, m_broadcastPing, &BroadcastPing::run);
+ NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
+ connect(monitor, &NetworkDeviceMonitor::reachableChanged, this, [=](bool reachable){
+ qCDebug(dcNetworkDetector()) << thing << "reachable changed to" << reachable;
+ thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable);
+ });
- m_broadcastPing->run();
+ connect(monitor, &NetworkDeviceMonitor::lastSeenChanged, this, [=](const QDateTime &lastSeen){
+ QDateTime minuteBased = QDateTime::fromMSecsSinceEpoch((monitor->lastSeen().toMSecsSinceEpoch() / 60000) * 60000);
+ qCDebug(dcNetworkDetector()) << thing << "last seen changed to" << lastSeen.toString() << minuteBased.toString();
+ thing->setStateValue(networkDeviceLastSeenTimeStateTypeId, minuteBased.toMSecsSinceEpoch() / 1000);
+ });
+
+ connect(monitor, &NetworkDeviceMonitor::networkDeviceInfoChanged, this, [=](const NetworkDeviceInfo &networkInfo){
+ qCDebug(dcNetworkDetector()) << thing << "changed" << networkInfo;
+ thing->setStateValue(networkDeviceAddressStateTypeId, networkInfo.address().toString());
+ thing->setStateValue(networkDeviceHostNameStateTypeId, networkInfo.hostName());
+ thing->setStateValue(networkDeviceMacManufacturerNameStateTypeId, networkInfo.macAddressManufacturer());
+ thing->setStateValue(networkDeviceNetworkInterfaceStateTypeId, monitor->networkDeviceInfo().networkInterface().name());
+ });
+
+ m_monitors.insert(thing, monitor);
+ info->finish(Thing::ThingErrorNoError);
+
+ thing->setStateValue(networkDeviceAddressStateTypeId, monitor->networkDeviceInfo().address().toString());
+ thing->setStateValue(networkDeviceHostNameStateTypeId, monitor->networkDeviceInfo().hostName());
+ thing->setStateValue(networkDeviceMacManufacturerNameStateTypeId, monitor->networkDeviceInfo().macAddressManufacturer());
+ thing->setStateValue(networkDeviceNetworkInterfaceStateTypeId, monitor->networkDeviceInfo().networkInterface().name());
+ thing->setStateValue(networkDeviceIsPresentStateTypeId, monitor->reachable());
+ if (!monitor->lastSeen().isNull()) {
+ QDateTime minuteBased = QDateTime::fromMSecsSinceEpoch((monitor->lastSeen().toMSecsSinceEpoch() / 60000) * 60000);
+ thing->setStateValue(networkDeviceLastSeenTimeStateTypeId, minuteBased.toMSecsSinceEpoch() / 1000); }
+ return;
}
- info->finish(Thing::ThingErrorNoError);
-}
-
-void IntegrationPluginNetworkDetector::discoverThings(ThingDiscoveryInfo *info)
-{
- Discovery *discovery = new Discovery(this);
- discovery->discoverHosts(25);
-
- // clean up discovery object when this discovery info is deleted
- connect(info, &ThingDiscoveryInfo::destroyed, discovery, &Discovery::deleteLater);
-
- connect(discovery, &Discovery::finished, info, [this, info](const QList &hosts) {
- qCDebug(dcNetworkDetector()) << "Discovery finished. Found" << hosts.count() << "devices";
- foreach (const Host &host, hosts) {
- ThingDescriptor descriptor(networkDeviceThingClassId, host.hostName().isEmpty() ? host.address() : host.hostName(), host.address() + " (" + host.macAddress() + ")");
-
- foreach (Thing *existingThing, myThings()) {
- if (existingThing->paramValue(networkDeviceThingMacAddressParamTypeId).toString() == host.macAddress()) {
- descriptor.setThingId(existingThing->id());
- break;
- }
- }
-
- ParamList params;
- params << Param(networkDeviceThingMacAddressParamTypeId, host.macAddress());
- params << Param(networkDeviceThingAddressParamTypeId, host.address());
- descriptor.setParams(params);
-
- info->addThingDescriptor(descriptor);
-
- }
- info->finish(Thing::ThingErrorNoError);
- });
+ info->finish(Thing::ThingErrorThingClassNotFound);
}
void IntegrationPluginNetworkDetector::thingRemoved(Thing *thing)
{
- DeviceMonitor *monitor = m_monitors.key(thing);
- m_monitors.remove(monitor);
- delete monitor;
-
- if (m_monitors.isEmpty()) {
- hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
- m_pluginTimer = nullptr;
-
+ if (m_monitors.contains(thing)) {
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}
}
-void IntegrationPluginNetworkDetector::broadcastPingFinished()
+void IntegrationPluginNetworkDetector::executeAction(ThingActionInfo *info)
{
- foreach (DeviceMonitor *monitor, m_monitors.keys()) {
- monitor->update();
+ if (info->thing()->thingClassId() == networkDeviceThingClassId) {
+
+ NetworkDeviceMonitor *monitor = m_monitors.value(info->thing());
+ if (!monitor) {
+ qCWarning(dcNetworkDetector()) << "Could not execute action. There is no monitor registered for" << info->thing();
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ if (info->action().actionTypeId() == networkDevicePingActionTypeId) {
+ PingReply *pingReply = hardwareManager()->networkDeviceDiscovery()->ping(monitor->networkDeviceInfo().address());
+ connect(pingReply, &PingReply::finished, info, [=](){
+ if (pingReply->error() == PingReply::ErrorNoError) {
+ qCDebug(dcNetworkDetector()) << "Ping finished for" << monitor->networkDeviceInfo().address().toString() << pingReply->duration() << "ms";
+ info->finish(Thing::ThingErrorNoError);
+ } else {
+ qCWarning(dcNetworkDetector()) << "Ping" << monitor->networkDeviceInfo().address().toString() << "finished with error" << pingReply->error();
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ }
+ });
+ } else if (info->action().actionTypeId() == networkDeviceArpRequestActionTypeId) {
+ bool result = hardwareManager()->networkDeviceDiscovery()->sendArpRequest(monitor->networkDeviceInfo().address());
+ if (result) {
+ qCDebug(dcNetworkDetector()) << "ARP request sent successfully to" << monitor->networkDeviceInfo().address().toString();
+ info->finish(Thing::ThingErrorNoError);
+ } else {
+ qCWarning(dcNetworkDetector()) << "Failed to send ARP request to" << monitor->networkDeviceInfo().address().toString();
+ info->finish(Thing::ThingErrorHardwareFailure);
+ }
+ } else if (info->action().actionTypeId() == networkDeviceLookupHostActionTypeId) {
+ int lookupId = QHostInfo::lookupHost(monitor->networkDeviceInfo().address().toString(), this, SLOT(onHostLookupFinished(QHostInfo)));
+ m_pendingHostLookup.insert(lookupId, info);
+ connect(info, &ThingActionInfo::aborted, this, [=](){
+ m_pendingHostLookup.remove(lookupId);
+ });
+ }
}
}
-void IntegrationPluginNetworkDetector::deviceReachableChanged(bool reachable)
+void IntegrationPluginNetworkDetector::onHostLookupFinished(const QHostInfo &info)
{
- DeviceMonitor *monitor = static_cast(sender());
- Thing *thing = m_monitors.value(monitor);
- if (thing->stateValue(networkDeviceIsPresentStateTypeId).toBool() != reachable) {
- qCDebug(dcNetworkDetector()) << "Device" << thing->name() << thing->paramValue(networkDeviceThingMacAddressParamTypeId).toString() << "reachable changed" << reachable;
- thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable);
+ ThingActionInfo *actionInfo = m_pendingHostLookup.take(info.lookupId());
+ if (!actionInfo) {
+ qCWarning(dcNetworkDetector()) << "Host loopup finished for" << info.addresses() << info.hostName() << "but the action does not exist any more.";
+ return;
}
-}
-void IntegrationPluginNetworkDetector::deviceAddressChanged(const QString &address)
-{
- DeviceMonitor *monitor = static_cast(sender());
- Thing *thing = m_monitors.value(monitor);
- if (thing->paramValue(networkDeviceThingAddressParamTypeId).toString() != address) {
- qCDebug(dcNetworkDetector()) << "Device" << thing->name() << thing->paramValue(networkDeviceThingMacAddressParamTypeId).toString() << "changed IP address to" << address;
- thing->setParamValue(networkDeviceThingAddressParamTypeId, address);
- }
-}
-
-void IntegrationPluginNetworkDetector::deviceSeen()
-{
- DeviceMonitor *monitor = static_cast(sender());
- Thing *thing = m_monitors.value(monitor);
- QDateTime oldLastSeen = QDateTime::fromTime_t(thing->stateValue(networkDeviceLastSeenTimeStateTypeId).toInt());
- if (oldLastSeen.addSecs(60) < QDateTime::currentDateTime()) {
- thing->setStateValue(networkDeviceLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t());
+ qCDebug(dcNetworkDetector()) << "Host lookup finished" << info.addresses() << info.hostName() << info.error();
+ if (info.error() != QHostInfo::NoError) {
+ qCWarning(dcNetworkDetector()) << "Error occured during host lookup:" << info.errorString();
+ actionInfo->finish(Thing::ThingErrorHardwareFailure);
+ } else {
+ actionInfo->finish(Thing::ThingErrorNoError);
}
}
diff --git a/networkdetector/integrationpluginnetworkdetector.h b/networkdetector/integrationpluginnetworkdetector.h
index a5f0c59c..b83a6812 100644
--- a/networkdetector/integrationpluginnetworkdetector.h
+++ b/networkdetector/integrationpluginnetworkdetector.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
-* Copyright 2013 - 2020, nymea GmbH
+* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@@ -31,15 +31,9 @@
#ifndef INTEGRATIONPLUGINNETWORKDETECTOR_H
#define INTEGRATIONPLUGINNETWORKDETECTOR_H
-#include "integrations/integrationplugin.h"
-#include "host.h"
-#include "discovery.h"
-#include "plugintimer.h"
-#include "devicemonitor.h"
-#include "broadcastping.h"
+#include
+#include
-#include
-#include
#include
class IntegrationPluginNetworkDetector : public IntegrationPlugin
@@ -54,23 +48,19 @@ public:
~IntegrationPluginNetworkDetector();
void init() override;
-
- void setupThing(ThingSetupInfo *info) override;
void discoverThings(ThingDiscoveryInfo *info) override;
+ void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
-
-private slots:
- void deviceReachableChanged(bool reachable);
- void deviceAddressChanged(const QString &address);
- void deviceSeen();
-
- void broadcastPingFinished();
+ void executeAction(ThingActionInfo *info) override;
private:
- PluginTimer *m_pluginTimer = nullptr;
- BroadcastPing *m_broadcastPing = nullptr;
- QHash m_monitors;
+ QHash m_monitors;
+ QHash m_pendingHostLookup;
+
+private slots:
+ void onHostLookupFinished(const QHostInfo &info);
+
};
#endif // INTEGRATIONPLUGINNETWORKDETECTOR_H
diff --git a/networkdetector/integrationpluginnetworkdetector.json b/networkdetector/integrationpluginnetworkdetector.json
index 303cc28e..66be264d 100644
--- a/networkdetector/integrationpluginnetworkdetector.json
+++ b/networkdetector/integrationpluginnetworkdetector.json
@@ -15,31 +15,47 @@
"interfaces": [ "presencesensor" ],
"createMethods": ["user", "discovery"],
"paramTypes": [
- {
- "id": "c6707093-3b51-469d-9fc0-f167bff2a987",
- "name": "address",
- "displayName": "address",
- "type": "QString",
- "inputType": "TextLine"
- },
{
"id": "18fd3b05-478a-49cf-b8ae-3c6a98675ccc",
"name": "macAddress",
- "displayName": "hardware address",
+ "displayName": "MAC address",
"type": "QString",
- "inputType": "TextLine"
- }
- ],
- "settingsTypes": [
- {
- "id": "6c1ec0c8-6a02-4b3c-9064-ee33cfd61fbe",
- "name": "gracePeriod",
- "displayName": "Grace period (Minutes)",
- "type": "uint",
- "defaultValue": 5
+ "inputType": "MacAddress"
}
],
"stateTypes": [
+ {
+ "id": "acee9260-4d01-471a-85c5-4d6116b35ff1",
+ "name": "address",
+ "displayName": "IP address",
+ "displayNameEvent": "IP address changed",
+ "type": "QString",
+ "defaultValue": "127.0.0.1"
+ },
+ {
+ "id": "29c65dcf-090e-4316-8554-68f038a8416f",
+ "name": "hostName",
+ "displayName": "Host name",
+ "displayNameEvent": "Host name changed",
+ "type": "QString",
+ "defaultValue": ""
+ },
+ {
+ "id": "395623b2-5b25-4582-803e-61cd6d40844c",
+ "name": "macManufacturerName",
+ "displayName": "MAC manufacturer name",
+ "displayNameEvent": "MAC manufacturer name changed",
+ "type": "QString",
+ "defaultValue": ""
+ },
+ {
+ "id": "412f0e24-26e7-450b-8e60-bfaf938ea23e",
+ "name": "networkInterface",
+ "displayName": "Network interface",
+ "displayNameEvent": "Network interface changed",
+ "type": "QString",
+ "defaultValue": ""
+ },
{
"id": "cb43e1b5-4f61-4538-bfa2-c33055c542cf",
"name": "isPresent",
@@ -57,6 +73,23 @@
"unit": "UnixTime",
"defaultValue": 0
}
+ ],
+ "actionTypes": [
+ {
+ "id": "e98793b6-2dad-4090-91db-77f8493b4e45",
+ "name": "ping",
+ "displayName": "Ping device"
+ },
+ {
+ "id": "2ca3f99f-7315-4f17-b48d-99f0c151a62c",
+ "name": "arpRequest",
+ "displayName": "Send ARP request"
+ },
+ {
+ "id": "9797dac5-d99a-4bcf-a99a-5b9356bbce76",
+ "name": "lookupHost",
+ "displayName": "Lookup host name"
+ }
]
}
]
diff --git a/networkdetector/networkdetector.pro b/networkdetector/networkdetector.pro
index dc73ff1a..b0e50179 100644
--- a/networkdetector/networkdetector.pro
+++ b/networkdetector/networkdetector.pro
@@ -5,17 +5,9 @@ QT += network
TARGET = $$qtLibraryTarget(nymea_integrationpluginnetworkdetector)
SOURCES += \
- integrationpluginnetworkdetector.cpp \
- host.cpp \
- discovery.cpp \
- devicemonitor.cpp \
- broadcastping.cpp
+ integrationpluginnetworkdetector.cpp
HEADERS += \
- integrationpluginnetworkdetector.h \
- host.h \
- discovery.h \
- devicemonitor.h \
- broadcastping.h
+ integrationpluginnetworkdetector.h
diff --git a/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-de.ts b/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-de.ts
index 390f81de..29d50199 100644
--- a/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-de.ts
+++ b/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-de.ts
@@ -1,72 +1,97 @@
+
+ IntegrationPluginNetworkDetector
+
+
+ Unable to discovery devices in your network.
+
+
+
+
+ The configured MAC address is not valid.
+
+
+
NetworkDetector
+
+
+ Host name
+ The name of the StateType ({29c65dcf-090e-4316-8554-68f038a8416f}) of ThingClass networkDevice
+
+
+
+
+ IP address
+ The name of the StateType ({acee9260-4d01-471a-85c5-4d6116b35ff1}) of ThingClass networkDevice
+
+
+
+
+ Lookup host name
+ The name of the ActionType ({9797dac5-d99a-4bcf-a99a-5b9356bbce76}) of ThingClass networkDevice
+
+
+ MAC address
+ The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {18fd3b05-478a-49cf-b8ae-3c6a98675ccc})
+
+
+
+
+ MAC manufacturer name
+ The name of the StateType ({395623b2-5b25-4582-803e-61cd6d40844c}) of ThingClass networkDevice
+
+
+
+
Network Detector
The name of the plugin NetworkDetector ({8e0f791e-b273-4267-8605-b7c2f55a68ab})
Netzwerk Detektor
+ Network interface
+ The name of the StateType ({412f0e24-26e7-450b-8e60-bfaf938ea23e}) of ThingClass networkDevice
+
+
+
+
+ Ping device
+ The name of the ActionType ({e98793b6-2dad-4090-91db-77f8493b4e45}) of ThingClass networkDevice
+
+
+
+
+ Send ARP request
+ The name of the ActionType ({2ca3f99f-7315-4f17-b48d-99f0c151a62c}) of ThingClass networkDevice
+
+
+
+
nymea
The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6})
nymea
-
+
Network Device
The name of the ThingClass ({bd216356-f1ec-4324-9785-6982d2174e17})
Netzwerkgerät
-
-
- address
- The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {c6707093-3b51-469d-9fc0-f167bff2a987})
- Adresse
-
-
-
- hardware address
- The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {18fd3b05-478a-49cf-b8ae-3c6a98675ccc})
- Geräteadresse
-
-
-
- Grace period (Minutes)
- The name of the ParamType (ThingClass: networkDevice, Type: settings, ID: {6c1ec0c8-6a02-4b3c-9064-ee33cfd61fbe})
- Gnadenfrist (Minuten)
-
- Device is present changed
- The name of the EventType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
- Gerät anwesend geändert
-
-
-
-
Device is present
- The name of the ParamType (ThingClass: networkDevice, EventType: isPresent, ID: {cb43e1b5-4f61-4538-bfa2-c33055c542cf})
-----------
-The name of the StateType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
+ The name of the StateType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
Gerät ist anwesend
-
- Last seen time changed
- The name of the EventType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice
- Zuletzt gesehen geändert
-
-
-
Last seen time
- The name of the ParamType (ThingClass: networkDevice, EventType: lastSeenTime, ID: {b51d54c9-cce1-43f0-a35d-52fc2d8d302c})
-----------
-The name of the StateType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice
+ The name of the StateType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice
Zuletzt gesehen geändert
diff --git a/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-en_US.ts b/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-en_US.ts
index 9ecf1d8a..1e6bb856 100644
--- a/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-en_US.ts
+++ b/networkdetector/translations/8e0f791e-b273-4267-8605-b7c2f55a68ab-en_US.ts
@@ -1,72 +1,97 @@
+
+ IntegrationPluginNetworkDetector
+
+
+ Unable to discovery devices in your network.
+
+
+
+
+ The configured MAC address is not valid.
+
+
+
NetworkDetector
+
+
+ Host name
+ The name of the StateType ({29c65dcf-090e-4316-8554-68f038a8416f}) of ThingClass networkDevice
+
+
+
+
+ IP address
+ The name of the StateType ({acee9260-4d01-471a-85c5-4d6116b35ff1}) of ThingClass networkDevice
+
+
+
+
+ Lookup host name
+ The name of the ActionType ({9797dac5-d99a-4bcf-a99a-5b9356bbce76}) of ThingClass networkDevice
+
+
+ MAC address
+ The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {18fd3b05-478a-49cf-b8ae-3c6a98675ccc})
+
+
+
+
+ MAC manufacturer name
+ The name of the StateType ({395623b2-5b25-4582-803e-61cd6d40844c}) of ThingClass networkDevice
+
+
+
+
Network Detector
The name of the plugin NetworkDetector ({8e0f791e-b273-4267-8605-b7c2f55a68ab})
+ Network interface
+ The name of the StateType ({412f0e24-26e7-450b-8e60-bfaf938ea23e}) of ThingClass networkDevice
+
+
+
+
+ Ping device
+ The name of the ActionType ({e98793b6-2dad-4090-91db-77f8493b4e45}) of ThingClass networkDevice
+
+
+
+
+ Send ARP request
+ The name of the ActionType ({2ca3f99f-7315-4f17-b48d-99f0c151a62c}) of ThingClass networkDevice
+
+
+
+
nymea
The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6})
-
+
Network Device
The name of the ThingClass ({bd216356-f1ec-4324-9785-6982d2174e17})
-
-
- address
- The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {c6707093-3b51-469d-9fc0-f167bff2a987})
-
-
-
-
- hardware address
- The name of the ParamType (ThingClass: networkDevice, Type: thing, ID: {18fd3b05-478a-49cf-b8ae-3c6a98675ccc})
-
-
-
-
- Grace period (Minutes)
- The name of the ParamType (ThingClass: networkDevice, Type: settings, ID: {6c1ec0c8-6a02-4b3c-9064-ee33cfd61fbe})
-
-
- Device is present changed
- The name of the EventType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
-
-
-
-
-
Device is present
- The name of the ParamType (ThingClass: networkDevice, EventType: isPresent, ID: {cb43e1b5-4f61-4538-bfa2-c33055c542cf})
-----------
-The name of the StateType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
+ The name of the StateType ({cb43e1b5-4f61-4538-bfa2-c33055c542cf}) of ThingClass networkDevice
-
- Last seen time changed
- The name of the EventType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice
-
-
-
-
Last seen time
- The name of the ParamType (ThingClass: networkDevice, EventType: lastSeenTime, ID: {b51d54c9-cce1-43f0-a35d-52fc2d8d302c})
-----------
-The name of the StateType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice
+ The name of the StateType ({b51d54c9-cce1-43f0-a35d-52fc2d8d302c}) of ThingClass networkDevice