From 806065ff5c0b38d75fe03a1b03655b1d94eac023 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 18 Feb 2022 18:03:46 +0100 Subject: [PATCH] Timeout ZDO replies I've been observing devices that won't reply to ZDO node descriptor requests, at least not on the first attempt as well as out-of-spec devices which claim to have an endpoint x but then won't reply on getting the endpoint descriptor. I have a Lumi (lumi.sensor_switch.aq2) button here which allows to reproduce both of those. It will never reply on the first attemt. Anyhow, it happens that the ZDO, waiting on the data indication never finishes because there does not seem to be a timeout connected to it and it fails initialisation. Adding a timeout, the code retries and it seems to succeed on the second attempt. --- libnymea-zigbee/zdo/zigbeedeviceobject.cpp | 30 +++++++++++-------- .../zdo/zigbeedeviceobjectreply.cpp | 8 ++++- libnymea-zigbee/zdo/zigbeedeviceobjectreply.h | 3 ++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp index 3e5f98c..4fb7c2b 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp @@ -76,7 +76,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNetworkAddress() // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -121,7 +121,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestIeeeAddress() // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -164,7 +164,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNodeDescriptor() // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -207,7 +207,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestPowerDescriptor() // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -249,7 +249,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestActiveEndpoints() // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -291,7 +291,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestSimpleDescriptor(quint8 endp // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -339,7 +339,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindGroupAddress(quint8 sour // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -389,7 +389,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindIeeeAddress(quint8 sourc // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -441,7 +441,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestUnbind(const ZigbeeDevicePro // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -484,7 +484,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindRegister(const ZigbeeAdd // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -535,7 +535,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLeaveNetwork(bool rejoin // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -576,7 +576,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLqi(quint8 startIndex) // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -618,7 +618,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtBind(quint8 startIndex) // Send the request, on finished read the confirm information ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); - connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + connect(networkReply, &ZigbeeNetworkReply::finished, zdoReply, [this, networkReply, zdoReply](){ if (!verifyNetworkError(zdoReply, networkReply)) { finishZdoReply(zdoReply); return; @@ -668,6 +668,9 @@ bool ZigbeeDeviceObject::verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, Z // The request has been transported successfully to he destination, now // wait for the expected indication or check if we already recieved it zdoReply->m_apsConfirmReceived = true; + if (!zdoReply->m_zdpIndicationReceived) { + zdoReply->m_timeoutTimer.start(); + } success = true; break; case ZigbeeNetworkReply::ErrorInterfaceError: @@ -719,6 +722,7 @@ void ZigbeeDeviceObject::finishZdoReply(ZigbeeDeviceObjectReply *zdoReply) } m_pendingReplies.remove(zdoReply->transactionSequenceNumber()); + zdoReply->m_timeoutTimer.stop(); zdoReply->finished(); } diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp index 1d4a0a6..cc536a6 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp @@ -27,11 +27,17 @@ #include "zigbeedeviceobjectreply.h" +#include + ZigbeeDeviceObjectReply::ZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, QObject *parent) : QObject(parent), m_request(request) { - + m_timeoutTimer.setInterval(5000); + connect(&m_timeoutTimer, &QTimer::timeout, this, [this](){ + m_error = ErrorTimeout; + emit finished(); + }); } void ZigbeeDeviceObjectReply::setZigbeeApsStatus(Zigbee::ZigbeeApsStatus status) diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h index e3633fb..12d4e55 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h @@ -29,6 +29,7 @@ #define ZIGBEEDEVICEOBJECTREPLY_H #include +#include #include "zigbeedeviceprofile.h" #include "zigbeenetworkrequest.h" @@ -72,6 +73,8 @@ private: Error m_error = ErrorNoError; + QTimer m_timeoutTimer; + // Request information ZigbeeNetworkRequest m_request; quint8 m_transactionSequenceNumber = 0;