Handle network address changes and remove unrecognized nodes from the network once and for all if they show up again
parent
85856eaaa8
commit
2ed1487053
|
|
@ -298,6 +298,12 @@ ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (ZigbeeNode *node, m_temporaryNodes) {
|
||||||
|
if (node->shortAddress() == shortAddress) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -631,10 +637,13 @@ void ZigbeeNetwork::handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we have a node, uninitalized node or temporary node
|
||||||
ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress);
|
ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication;
|
qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication;
|
||||||
// FIXME: check if we want to create it since the device definitly exists within the network
|
// Maybe the network address has changed due to parent node switching. Lets fetch the IEEE address and check again if know this node.
|
||||||
|
// If the node is known, the network address gets updated, otherwise the leave network command will be sent.
|
||||||
|
verifyUnrecognizedNode(indication.sourceShortAddress);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -650,11 +659,15 @@ void ZigbeeNetwork::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeData
|
||||||
// Get the node
|
// Get the node
|
||||||
ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress);
|
ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication;
|
qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication from an unrecognized node. Checking IEEE address for this node" << indication;
|
||||||
// FIXME: maybe create and init the node, since it is in the network, but not recognized
|
|
||||||
// FIXME: maybe remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join.
|
// Maybe the network address has changed due to parent node switching. Lets fetch the IEEE address and check again if know this node.
|
||||||
|
// If the node is known, the network address gets updated, otherwise the leave network command will be sent.
|
||||||
|
|
||||||
|
verifyUnrecognizedNode(indication.sourceShortAddress);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the node handle this indication
|
// Let the node handle this indication
|
||||||
handleNodeIndication(node, indication);
|
handleNodeIndication(node, indication);
|
||||||
}
|
}
|
||||||
|
|
@ -677,9 +690,9 @@ void ZigbeeNetwork::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAd
|
||||||
setNodeReachable(node, true);
|
setNodeReachable(node, true);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNetwork()) << "Already known device announced with different network address. FIXME: update the network address or reinitialize node...";
|
qCDebug(dcZigbeeNetwork()) << "Already known device announced with different network address. Updating the network address internally of this node...";
|
||||||
//removeNode(node);
|
updateNodeNetworkAddress(node, shortAddress);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -688,6 +701,79 @@ void ZigbeeNetwork::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAd
|
||||||
node->startInitialization();
|
node->startInitialization();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetwork::verifyUnrecognizedNode(quint16 shortAddress)
|
||||||
|
{
|
||||||
|
// 1. Create a temporary node for message handling
|
||||||
|
// 2. Get the IEEE address
|
||||||
|
// 3. Check if we have a node for this address
|
||||||
|
// Yes -> update the network address and save database
|
||||||
|
// No -> send management leave request to the node
|
||||||
|
|
||||||
|
ZigbeeNode *node = new ZigbeeNode(this, shortAddress, ZigbeeAddress(), this);
|
||||||
|
m_temporaryNodes.append(node);
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Start verify process for unrecognized node" << node;
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Request IEEE address from unrecognized node" << node;
|
||||||
|
ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestIeeeAddress();
|
||||||
|
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||||
|
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||||
|
qCWarning(dcZigbeeNode()) << "Failed to request IEEE address from unrecognized" << node << zdoReply->error();
|
||||||
|
// Remove and delete this temporary node since we did not know the IEEE address
|
||||||
|
m_temporaryNodes.removeAll(node);
|
||||||
|
node->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray response = zdoReply->responseData();
|
||||||
|
QDataStream stream(&response, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
quint8 sqn; quint8 statusInt; quint64 ieeeAddressInt;
|
||||||
|
stream >> sqn >> statusInt >> ieeeAddressInt;
|
||||||
|
ZigbeeDeviceProfile::Status status = static_cast<ZigbeeDeviceProfile::Status>(statusInt);
|
||||||
|
ZigbeeAddress ieeeAddress(ieeeAddressInt);
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << "Get IEEE address from unrecognized node finished" << status << ieeeAddress.toString() << node << ZigbeeUtils::convertByteArrayToHexString(zdoReply->responseData());
|
||||||
|
|
||||||
|
if (hasNode(ieeeAddress)) {
|
||||||
|
// We know this node with this IEEE address, let's update the network address and save the new address in the database
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Found node for unrecognized network address with IEEE address" << ieeeAddress.toString() << "Updating the network address internally...";
|
||||||
|
m_temporaryNodes.removeAll(node);
|
||||||
|
node->deleteLater();
|
||||||
|
|
||||||
|
ZigbeeNode *existingNode = getZigbeeNode(ieeeAddress);
|
||||||
|
updateNodeNetworkAddress(existingNode, shortAddress);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// We don't know any node with this ieeeAddress. Let's try to make it leave the network
|
||||||
|
qCWarning(dcZigbeeNetwork()) << "Could not find any node with IEEE address" << ieeeAddress.toString() << "Requesting node to leave the network" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Request unrecognized" << node << "to leave the newtork";
|
||||||
|
ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestMgmtLeaveNetwork();
|
||||||
|
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||||
|
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||||
|
qCWarning(dcZigbeeNode()) << "Failed to request unrecognized node to leave the network" << node << zdoReply->error();
|
||||||
|
m_temporaryNodes.removeAll(node);
|
||||||
|
node->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Removed unrecognized node successfully from the network" << node;
|
||||||
|
m_temporaryNodes.removeAll(node);
|
||||||
|
node->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetwork::updateNodeNetworkAddress(ZigbeeNode *node, quint16 shortAddress)
|
||||||
|
{
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Network address of" << node << "has changed to" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
|
node->m_shortAddress = shortAddress;
|
||||||
|
emit node->shortAddressChanged(shortAddress);
|
||||||
|
|
||||||
|
m_database->updateNodeNetworkAddress(node, shortAddress);
|
||||||
|
setNodeReachable(node, true);
|
||||||
|
}
|
||||||
|
|
||||||
ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request)
|
ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request)
|
||||||
{
|
{
|
||||||
ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this);
|
ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this);
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ private:
|
||||||
QDir m_settingsDirectory = QDir("/etc/nymea/");
|
QDir m_settingsDirectory = QDir("/etc/nymea/");
|
||||||
QList<ZigbeeNode *> m_nodes;
|
QList<ZigbeeNode *> m_nodes;
|
||||||
QList<ZigbeeNode *> m_uninitializedNodes;
|
QList<ZigbeeNode *> m_uninitializedNodes;
|
||||||
|
QList<ZigbeeNode *> m_temporaryNodes;
|
||||||
|
|
||||||
void printNetwork();
|
void printNetwork();
|
||||||
|
|
||||||
|
|
@ -210,6 +211,9 @@ protected:
|
||||||
|
|
||||||
void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities);
|
void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities);
|
||||||
|
|
||||||
|
void verifyUnrecognizedNode(quint16 shortAddress);
|
||||||
|
void updateNodeNetworkAddress(ZigbeeNode *node, quint16 shortAddress);
|
||||||
|
|
||||||
// Network reply methods
|
// Network reply methods
|
||||||
ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest());
|
ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest());
|
||||||
void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess);
|
void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess);
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ bool ZigbeeNetworkDatabase::saveNode(ZigbeeNode *node)
|
||||||
|
|
||||||
bool ZigbeeNetworkDatabase::updateNodeLqi(ZigbeeNode *node, quint8 lqi)
|
bool ZigbeeNetworkDatabase::updateNodeLqi(ZigbeeNode *node, quint8 lqi)
|
||||||
{
|
{
|
||||||
qCDebug(dcZigbeeNetworkDatabase()) << "Update nod LQI" << node << lqi;
|
qCDebug(dcZigbeeNetworkDatabase()) << "Update node LQI" << node << lqi;
|
||||||
QString queryString = QString("UPDATE nodes SET lqi = \"%1\" WHERE ieeeAddress = \"%2\";").arg(lqi).arg(node->extendedAddress().toString());
|
QString queryString = QString("UPDATE nodes SET lqi = \"%1\" WHERE ieeeAddress = \"%2\";").arg(lqi).arg(node->extendedAddress().toString());
|
||||||
m_db.exec(queryString);
|
m_db.exec(queryString);
|
||||||
if (m_db.lastError().type() != QSqlError::NoError) {
|
if (m_db.lastError().type() != QSqlError::NoError) {
|
||||||
|
|
@ -446,6 +446,19 @@ bool ZigbeeNetworkDatabase::updateNodeLqi(ZigbeeNode *node, quint8 lqi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZigbeeNetworkDatabase::updateNodeNetworkAddress(ZigbeeNode *node, quint16 networkAddress)
|
||||||
|
{
|
||||||
|
qCDebug(dcZigbeeNetworkDatabase()) << "Update node network address" << node << ZigbeeUtils::convertUint16ToHexString(networkAddress);
|
||||||
|
QString queryString = QString("UPDATE nodes SET shortAddress = \"%1\" WHERE ieeeAddress = \"%2\";").arg(networkAddress).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)
|
bool ZigbeeNetworkDatabase::updateNodeLastSeen(ZigbeeNode *node, const QDateTime &lastSeen)
|
||||||
{
|
{
|
||||||
quint64 timestamp = lastSeen.toMSecsSinceEpoch() / 1000;
|
quint64 timestamp = lastSeen.toMSecsSinceEpoch() / 1000;
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ public slots:
|
||||||
bool saveAttribute(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
|
bool saveAttribute(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
|
||||||
bool saveNode(ZigbeeNode *node);
|
bool saveNode(ZigbeeNode *node);
|
||||||
bool updateNodeLqi(ZigbeeNode *node, quint8 lqi);
|
bool updateNodeLqi(ZigbeeNode *node, quint8 lqi);
|
||||||
|
bool updateNodeNetworkAddress(ZigbeeNode *node, quint16 networkAddress);
|
||||||
bool updateNodeLastSeen(ZigbeeNode *node, const QDateTime &lastSeen);
|
bool updateNodeLastSeen(ZigbeeNode *node, const QDateTime &lastSeen);
|
||||||
bool removeNode(ZigbeeNode *node);
|
bool removeNode(ZigbeeNode *node);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ private:
|
||||||
signals:
|
signals:
|
||||||
void nodeInitializationFailed();
|
void nodeInitializationFailed();
|
||||||
void stateChanged(State state);
|
void stateChanged(State state);
|
||||||
|
void shortAddressChanged(quint16 shortAddress);
|
||||||
void lqiChanged(quint8 lqi);
|
void lqiChanged(quint8 lqi);
|
||||||
void lastSeenChanged(const QDateTime &lastSeen);
|
void lastSeenChanged(const QDateTime &lastSeen);
|
||||||
void manufacturerNameChanged(const QString &manufacturerName);
|
void manufacturerNameChanged(const QString &manufacturerName);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue