Re-add grace period and introduce cached reachable state over nymea restarts

master
Simon Stürz 2022-05-04 09:29:30 +02:00
parent 9828e6ec11
commit 2a0fbe90f8
3 changed files with 125 additions and 37 deletions

View File

@ -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());

View File

@ -33,6 +33,7 @@
#include <integrations/integrationplugin.h>
#include <network/networkdevicediscovery.h>
#include <plugintimer.h>
#include <QHostInfo>
@ -56,8 +57,11 @@ public:
private:
QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
QHash<Thing *, PluginTimer *> m_gracePeriodTimers;
QHash<int, ThingActionInfo *> m_pendingHostLookup;
void setupMonitorConnections(Thing *thing, NetworkDeviceMonitor *monitor);
private slots:
void onHostLookupFinished(const QHostInfo &info);

View File

@ -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": [