diff --git a/networkdetector/integrationpluginnetworkdetector.cpp b/networkdetector/integrationpluginnetworkdetector.cpp index a13d7bd7..41f7cfc3 100644 --- a/networkdetector/integrationpluginnetworkdetector.cpp +++ b/networkdetector/integrationpluginnetworkdetector.cpp @@ -120,41 +120,59 @@ void IntegrationPluginNetworkDetector::setupThing(ThingSetupInfo *info) return; } + // Handle reconfigure + if (m_monitors.contains(thing)) { + hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); + } + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress); - connect(monitor, &NetworkDeviceMonitor::reachableChanged, this, [=](bool reachable){ - qCDebug(dcNetworkDetector()) << thing << "reachable changed to" << reachable; - thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable); - }); - - 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; + QHostAddress cachedAddress; + if (!monitor->networkDeviceInfo().address().isNull()) { + cachedAddress = monitor->networkDeviceInfo().address(); + } else { + cachedAddress = QHostAddress(thing->stateValue(networkDeviceAddressStateTypeId).toString()); + } + + // If the address is not known yet, let the monitor do the work and finish the setup... + if (cachedAddress.isNull()) { + setupMonitorConnections(thing, monitor); + info->finish(Thing::ThingErrorNoError); + thing->setStateValue(networkDeviceIsPresentStateTypeId, monitor->reachable()); + return; + } + + // Make an initial ping in order to check if the device reachable state has changed compaired to the cached state + qCDebug(dcNetworkDetector()) << "Send initial ping to" << cachedAddress.toString() << "in order to get initial reachable state..."; + PingReply *pingReply = hardwareManager()->networkDeviceDiscovery()->ping(cachedAddress); + connect(pingReply, &PingReply::finished, this, [=](){ + + qCDebug(dcNetworkDetector()) << "Initial ping finished" << pingReply->error(); + + // However the ping result is, the monitor has catched up internally with the reachable state... + + info->finish(Thing::ThingErrorNoError); + + if (!monitor->networkDeviceInfo().address().isNull()) + 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()); + + setupMonitorConnections(thing, monitor); + + if (!monitor->lastSeen().isNull()) { + QDateTime minuteBased = QDateTime::fromMSecsSinceEpoch((monitor->lastSeen().toMSecsSinceEpoch() / 60000) * 60000); + thing->setStateValue(networkDeviceLastSeenTimeStateTypeId, minuteBased.toMSecsSinceEpoch() / 1000); + } + + }); + } else { + info->finish(Thing::ThingErrorThingClassNotFound); } - - info->finish(Thing::ThingErrorThingClassNotFound); } void IntegrationPluginNetworkDetector::thingRemoved(Thing *thing) @@ -162,6 +180,10 @@ void IntegrationPluginNetworkDetector::thingRemoved(Thing *thing) if (m_monitors.contains(thing)) { hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); } + + if (m_gracePeriodTimers.contains(thing)) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_gracePeriodTimers.take(thing)); + } } void IntegrationPluginNetworkDetector::executeAction(ThingActionInfo *info) @@ -205,6 +227,53 @@ void IntegrationPluginNetworkDetector::executeAction(ThingActionInfo *info) } } +void IntegrationPluginNetworkDetector::setupMonitorConnections(Thing *thing, NetworkDeviceMonitor *monitor) +{ + connect(monitor, &NetworkDeviceMonitor::reachableChanged, thing, [=](bool reachable){ + qCDebug(dcNetworkDetector()) << thing->name() << "monitor reachable changed to" << reachable; + if (reachable) { + thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable); + // Remove any possible running grace priod timer + if (m_gracePeriodTimers.contains(thing)) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_gracePeriodTimers.take(thing)); + } + } else { + int gracePeriodSeconds = thing->setting(networkDeviceSettingsGracePeriodParamTypeId).toInt() * 60; + if (gracePeriodSeconds == 0) { + thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable); + } else { + // Let's wait the grace period before setting not present + PluginTimer *timer = hardwareManager()->pluginTimerManager()->registerTimer(gracePeriodSeconds); + connect(timer, &PluginTimer::timeout, thing, [=](){ + if (thing->stateValue(networkDeviceIsPresentStateTypeId).toBool() && monitor->lastSeen().addSecs(gracePeriodSeconds) < QDateTime::currentDateTime()) { + qCDebug(dcNetworkDetector()) << thing->name() << "still not reachable after a grace period of" << gracePeriodSeconds << "seconds. Mark device as not reachable."; + thing->setStateValue(networkDeviceIsPresentStateTypeId, reachable); + hardwareManager()->pluginTimerManager()->unregisterTimer(m_gracePeriodTimers.take(thing)); + } + }); + + m_gracePeriodTimers.insert(thing, timer); + qCDebug(dcNetworkDetector()) << "Starting grace period timer" << m_gracePeriodTimers << "seconds"; + timer->start(); + } + } + }); + + connect(monitor, &NetworkDeviceMonitor::lastSeenChanged, thing, [=](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, thing, [=](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()); + }); +} + void IntegrationPluginNetworkDetector::onHostLookupFinished(const QHostInfo &info) { ThingActionInfo *actionInfo = m_pendingHostLookup.take(info.lookupId()); diff --git a/networkdetector/integrationpluginnetworkdetector.h b/networkdetector/integrationpluginnetworkdetector.h index b83a6812..2fd1a2a0 100644 --- a/networkdetector/integrationpluginnetworkdetector.h +++ b/networkdetector/integrationpluginnetworkdetector.h @@ -33,6 +33,7 @@ #include #include +#include #include @@ -56,8 +57,11 @@ public: private: QHash m_monitors; + QHash m_gracePeriodTimers; QHash m_pendingHostLookup; + void setupMonitorConnections(Thing *thing, NetworkDeviceMonitor *monitor); + private slots: void onHostLookupFinished(const QHostInfo &info); diff --git a/networkdetector/integrationpluginnetworkdetector.json b/networkdetector/integrationpluginnetworkdetector.json index 66be264d..043a4e61 100644 --- a/networkdetector/integrationpluginnetworkdetector.json +++ b/networkdetector/integrationpluginnetworkdetector.json @@ -23,6 +23,15 @@ "inputType": "MacAddress" } ], + "settingsTypes": [ + { + "id": "6c1ec0c8-6a02-4b3c-9064-ee33cfd61fbe", + "name": "gracePeriod", + "displayName": "Grace period (Minutes)", + "type": "uint", + "defaultValue": 5 + } + ], "stateTypes": [ { "id": "acee9260-4d01-471a-85c5-4d6116b35ff1", @@ -30,7 +39,8 @@ "displayName": "IP address", "displayNameEvent": "IP address changed", "type": "QString", - "defaultValue": "127.0.0.1" + "defaultValue": "127.0.0.1", + "cached": true }, { "id": "29c65dcf-090e-4316-8554-68f038a8416f", @@ -38,7 +48,8 @@ "displayName": "Host name", "displayNameEvent": "Host name changed", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "cached": true }, { "id": "395623b2-5b25-4582-803e-61cd6d40844c", @@ -46,7 +57,8 @@ "displayName": "MAC manufacturer name", "displayNameEvent": "MAC manufacturer name changed", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "cached": true }, { "id": "412f0e24-26e7-450b-8e60-bfaf938ea23e", @@ -54,7 +66,8 @@ "displayName": "Network interface", "displayNameEvent": "Network interface changed", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "cached": true }, { "id": "cb43e1b5-4f61-4538-bfa2-c33055c542cf", @@ -62,7 +75,8 @@ "displayName": "Device is present", "displayNameEvent": "Device is present changed", "type": "bool", - "defaultValue": false + "defaultValue": false, + "cached": true }, { "id": "b51d54c9-cce1-43f0-a35d-52fc2d8d302c", @@ -71,7 +85,8 @@ "displayNameEvent": "Last seen time changed", "type": "int", "unit": "UnixTime", - "defaultValue": 0 + "defaultValue": 0, + "cached": true } ], "actionTypes": [