From 5cc83bb95625cfd70f7222796f601ab4dda46376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 1 Jul 2020 15:14:34 +0200 Subject: [PATCH] Update database and add lqi and timestamp for nodes --- libnymea-zigbee/zigbeenetwork.cpp | 12 +++++- libnymea-zigbee/zigbeenetworkdatabase.cpp | 45 ++++++++++++++++++++--- libnymea-zigbee/zigbeenetworkdatabase.h | 3 +- libnymea-zigbee/zigbeenode.cpp | 10 +++++ libnymea-zigbee/zigbeenode.h | 4 ++ 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 8e8c0c2..3f2d162 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -243,7 +243,7 @@ void ZigbeeNetwork::removeZigbeeNode(const ZigbeeAddress &address) connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, zdoReply, node](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbeeNode()) << "Failed to send management leave request to" << node << zdoReply->error(); - qCWarning(dcZigbeeNode()) << "This node is gonna be removed internally and tried to remove once it shows up the next time."; + qCWarning(dcZigbeeNode()) << "This node is gonna be removed internally. TODO: try to remove using ZDO once it shows up the next time."; } removeNode(node); @@ -264,7 +264,15 @@ void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node) } // FIXME: check when and how the note will be reachable - //node->setConnected(state() == StateRunning); + + // Update database metrics of the node + connect(node, &ZigbeeNode::lqiChanged, this, [this, node](quint8 lqi){ + m_database->updateNodeLqi(node, lqi); + }); + + connect(node, &ZigbeeNode::lastSeenChanged, this, [this, node](const QDateTime &lastSeen){ + m_database->updateNodeLastSeen(node, lastSeen); + }); // Note: if a cluster shows up after initialization (out of spec devices), save the cluster and it's attributes foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { diff --git a/libnymea-zigbee/zigbeenetworkdatabase.cpp b/libnymea-zigbee/zigbeenetworkdatabase.cpp index f8c6819..ee7db2b 100644 --- a/libnymea-zigbee/zigbeenetworkdatabase.cpp +++ b/libnymea-zigbee/zigbeenetworkdatabase.cpp @@ -74,12 +74,16 @@ QList ZigbeeNetworkDatabase::loadNodes() quint16 shortAddress = nodesQuery.value("shortAddress").toUInt(); QByteArray nodeDescriptor = QByteArray::fromBase64(nodesQuery.value("nodeDescriptor").toByteArray()); quint16 powerDescriptor = nodesQuery.value("powerDescriptor").toUInt(); + quint8 lqi = nodesQuery.value("lqi").toUInt(); + quint64 lastSeen = nodesQuery.value("timestamp").toULongLong(); // Build the node object ZigbeeNode *node = new ZigbeeNode(m_network, shortAddress, ZigbeeAddress(ieeeAddress), m_network); node->m_nodeDescriptor = ZigbeeDeviceProfile::parseNodeDescriptor(nodeDescriptor); node->m_macCapabilities = node->nodeDescriptor().macCapabilities; node->m_powerDescriptor = ZigbeeDeviceProfile::parsePowerDescriptor(powerDescriptor); + node->m_lqi = lqi; + node->m_lastSeen = QDateTime::fromMSecsSinceEpoch(lastSeen * 1000); qCDebug(dcZigbeeNetworkDatabase()) << "Loaded" << node; @@ -202,9 +206,9 @@ bool ZigbeeNetworkDatabase::initDatabase() "(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string "shortAddress INTEGER NOT NULL, " // uint16 "nodeDescriptor BLOB NOT NULL, " // bytes as received from the node - "powerDescriptor INTEGER NOT NULL, " - "lqi INTEGER," - "timestamp )"); // uint16 + "powerDescriptor INTEGER NOT NULL, " // uint16 + "lqi INTEGER NOT NULL," // uint8 + "timestamp INTEGER NOT NULL)"); // unix timestamp with the last communication createIndices("ieeeAddressIndex", "nodes", "ieeeAddress"); } @@ -379,12 +383,14 @@ bool ZigbeeNetworkDatabase::saveAttribute(ZigbeeCluster *cluster, const ZigbeeCl bool ZigbeeNetworkDatabase::saveNode(ZigbeeNode *node) { qCDebug(dcZigbeeNetworkDatabase()) << "Save" << node; - QString queryString = QString("INSERT OR REPLACE INTO nodes (ieeeAddress, shortAddress, nodeDescriptor, powerDescriptor) " - "VALUES (\"%1\", \"%2\", \"%3\", \"%4\");") + QString queryString = QString("INSERT OR REPLACE INTO nodes (ieeeAddress, shortAddress, nodeDescriptor, powerDescriptor, lqi, timestamp) " + "VALUES (\"%1\", \"%2\", \"%3\", \"%4\", \"%5\", \"%6\");") .arg(node->extendedAddress().toString()) .arg(node->shortAddress()) .arg(node->nodeDescriptor().descriptorRawData.toBase64().data()) // Note: convert to base64 for saving zeros as string - .arg(node->powerDescriptor().powerDescriptoFlag); + .arg(node->powerDescriptor().powerDescriptoFlag) + .arg(node->lqi()) + .arg(node->lastSeen().toMSecsSinceEpoch() / 1000); qCDebug(dcZigbeeNetworkDatabase()) << queryString; m_db.exec(queryString); @@ -403,6 +409,33 @@ bool ZigbeeNetworkDatabase::saveNode(ZigbeeNode *node) return true; } +bool ZigbeeNetworkDatabase::updateNodeLqi(ZigbeeNode *node, quint8 lqi) +{ + qCDebug(dcZigbeeNetworkDatabase()) << "Update nod LQI" << node << lqi; + QString queryString = QString("UPDATE nodes SET lqi = \"%1\" WHERE ieeeAddress = \"%2\";").arg(lqi).arg(node->extendedAddress().toString()); + m_db.exec(queryString); + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcZigbeeNetworkDatabase()) << "Could not update node LQI value in the database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return false; + } + + return true; +} + +bool ZigbeeNetworkDatabase::updateNodeLastSeen(ZigbeeNode *node, const QDateTime &lastSeen) +{ + quint64 timestamp = lastSeen.toMSecsSinceEpoch() / 1000; + qCDebug(dcZigbeeNetworkDatabase()) << "Update node last seen UTC timestamp" << node << timestamp; + QString queryString = QString("UPDATE nodes SET timestamp = \"%1\" WHERE ieeeAddress = \"%2\";").arg(timestamp).arg(node->extendedAddress().toString()); + m_db.exec(queryString); + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcZigbeeNetworkDatabase()) << "Could not update node timestamp value in the database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return false; + } + + return true; +} + bool ZigbeeNetworkDatabase::removeNode(ZigbeeNode *node) { qCDebug(dcZigbeeNetworkDatabase()) << "Remove" << node; diff --git a/libnymea-zigbee/zigbeenetworkdatabase.h b/libnymea-zigbee/zigbeenetworkdatabase.h index dc38daa..bab99d4 100644 --- a/libnymea-zigbee/zigbeenetworkdatabase.h +++ b/libnymea-zigbee/zigbeenetworkdatabase.h @@ -63,7 +63,8 @@ public slots: bool saveOutputCluster(ZigbeeCluster *cluster); bool saveAttribute(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute); bool saveNode(ZigbeeNode *node); - + bool updateNodeLqi(ZigbeeNode *node, quint8 lqi); + bool updateNodeLastSeen(ZigbeeNode *node, const QDateTime &lastSeen); bool removeNode(ZigbeeNode *node); }; diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index baf1585..87109c7 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -92,6 +92,11 @@ quint8 ZigbeeNode::lqi() const return m_lqi; } +QDateTime ZigbeeNode::lastSeen() const +{ + return m_lastSeen; +} + ZigbeeDeviceProfile::NodeDescriptor ZigbeeNode::nodeDescriptor() const { return m_nodeDescriptor; @@ -548,6 +553,11 @@ void ZigbeeNode::handleDataIndication(const Zigbee::ApsdeDataIndication &indicat emit lqiChanged(m_lqi); } + // Update the UTC timestamp of last seen for reachable verification + if (m_lastSeen != QDateTime::currentDateTimeUtc()) { + m_lastSeen = QDateTime::currentDateTimeUtc(); + emit lastSeenChanged(m_lastSeen); + } // Check if this indocation is related to any pending reply if (indication.profileId == Zigbee::ZigbeeProfileDevice) { diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 3c8e7b6..e3059aa 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -29,6 +29,7 @@ #define ZIGBEENODE_H #include +#include #include "zigbee.h" #include "zigbeeaddress.h" @@ -66,6 +67,7 @@ public: ZigbeeNodeEndpoint *getEndpoint(quint8 endpointId) const; quint8 lqi() const; + QDateTime lastSeen() const; // Information from descriptors ZigbeeDeviceProfile::NodeDescriptor nodeDescriptor() const; @@ -93,6 +95,7 @@ private: bool m_connected = false; State m_state = StateUninitialized; quint8 m_lqi = 0; + QDateTime m_lastSeen; // Node information ZigbeeDeviceProfile::NodeDescriptor m_nodeDescriptor; @@ -122,6 +125,7 @@ signals: void nodeInitializationFailed(); void stateChanged(State state); void lqiChanged(quint8 lqi); + void lastSeenChanged(const QDateTime &lastSeen); void connectedChanged(bool connected); void clusterAdded(ZigbeeCluster *cluster); void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);