From 4e897686bb3ad6714489514158aaf15a203f13e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 25 May 2020 22:25:49 +0200 Subject: [PATCH] Implement basic cluster comands and commuication --- .../{ => backends}/deconz/interface/deconz.h | 0 .../interface/zigbeeinterfacedeconz.cpp | 0 .../deconz/interface/zigbeeinterfacedeconz.h | 0 .../interface/zigbeeinterfacedeconzreply.cpp | 0 .../interface/zigbeeinterfacedeconzreply.h | 0 .../deconz/zigbeebridgecontrollerdeconz.cpp | 0 .../deconz/zigbeebridgecontrollerdeconz.h | 0 .../deconz/zigbeenetworkdeconz.cpp | 78 ++- .../deconz/zigbeenetworkdeconz.h | 3 +- .../nxp/interface/zigbeeinterface.cpp | 0 .../nxp/interface/zigbeeinterface.h | 0 .../nxp/interface/zigbeeinterfacemessage.cpp | 0 .../nxp/interface/zigbeeinterfacemessage.h | 0 .../nxp/interface/zigbeeinterfacereply.cpp | 0 .../nxp/interface/zigbeeinterfacereply.h | 0 .../nxp/interface/zigbeeinterfacerequest.cpp | 0 .../nxp/interface/zigbeeinterfacerequest.h | 0 .../nxp/zigbeebridgecontrollernxp.cpp | 0 .../nxp/zigbeebridgecontrollernxp.h | 0 .../{ => backends}/nxp/zigbeenetworknxp.cpp | 0 .../{ => backends}/nxp/zigbeenetworknxp.h | 0 .../nxp/zigbeenodeendpointnxp.cpp | 0 .../nxp/zigbeenodeendpointnxp.h | 0 .../{ => backends}/nxp/zigbeenodenxp.cpp | 0 .../{ => backends}/nxp/zigbeenodenxp.h | 0 libnymea-zigbee/libnymea-zigbee.pro | 72 ++- libnymea-zigbee/loggingcategory.cpp | 1 + libnymea-zigbee/loggingcategory.h | 1 + .../zcl/general/zigbeeclusterbasic.cpp | 21 + .../zcl/{ => general}/zigbeeclusterbasic.h | 10 +- libnymea-zigbee/{ => zcl}/zigbeecluster.cpp | 132 ++++- libnymea-zigbee/zcl/zigbeecluster.h | 213 ++++++++ .../{ => zcl}/zigbeeclusterattribute.cpp | 0 .../{ => zcl}/zigbeeclusterattribute.h | 0 libnymea-zigbee/zcl/zigbeeclusterbasic.cpp | 7 - .../{ => zcl}/zigbeeclusterlibrary.cpp | 112 +++- .../{ => zcl}/zigbeeclusterlibrary.h | 33 +- libnymea-zigbee/zcl/zigbeeclusterreply.cpp | 40 +- libnymea-zigbee/zcl/zigbeeclusterreply.h | 48 +- libnymea-zigbee/zdo/zigbeedeviceobjectreply.h | 3 +- libnymea-zigbee/zigbeecluster.h | 234 --------- libnymea-zigbee/zigbeeclusterlibraryreply.cpp | 24 - libnymea-zigbee/zigbeeclusterlibraryreply.h | 35 -- libnymea-zigbee/zigbeedatatype.cpp | 480 ++++++++++++++++++ libnymea-zigbee/zigbeedatatype.h | 26 + libnymea-zigbee/zigbeenetwork.cpp | 4 +- libnymea-zigbee/zigbeenetworkmanager.cpp | 2 +- libnymea-zigbee/zigbeenode.cpp | 198 +++----- libnymea-zigbee/zigbeenode.h | 1 - libnymea-zigbee/zigbeenodeendpoint.cpp | 28 +- libnymea-zigbee/zigbeenodeendpoint.h | 30 +- libnymea-zigbee/zigbeeutils.cpp | 5 +- libnymea-zigbee/zigbeeutils.h | 2 +- 53 files changed, 1290 insertions(+), 553 deletions(-) rename libnymea-zigbee/{ => backends}/deconz/interface/deconz.h (100%) rename libnymea-zigbee/{ => backends}/deconz/interface/zigbeeinterfacedeconz.cpp (100%) rename libnymea-zigbee/{ => backends}/deconz/interface/zigbeeinterfacedeconz.h (100%) rename libnymea-zigbee/{ => backends}/deconz/interface/zigbeeinterfacedeconzreply.cpp (100%) rename libnymea-zigbee/{ => backends}/deconz/interface/zigbeeinterfacedeconzreply.h (100%) rename libnymea-zigbee/{ => backends}/deconz/zigbeebridgecontrollerdeconz.cpp (100%) rename libnymea-zigbee/{ => backends}/deconz/zigbeebridgecontrollerdeconz.h (100%) rename libnymea-zigbee/{ => backends}/deconz/zigbeenetworkdeconz.cpp (92%) rename libnymea-zigbee/{ => backends}/deconz/zigbeenetworkdeconz.h (96%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterface.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterface.h (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacemessage.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacemessage.h (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacereply.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacereply.h (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacerequest.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/interface/zigbeeinterfacerequest.h (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeebridgecontrollernxp.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeebridgecontrollernxp.h (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenetworknxp.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenetworknxp.h (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenodeendpointnxp.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenodeendpointnxp.h (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenodenxp.cpp (100%) rename libnymea-zigbee/{ => backends}/nxp/zigbeenodenxp.h (100%) create mode 100644 libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp rename libnymea-zigbee/zcl/{ => general}/zigbeeclusterbasic.h (87%) rename libnymea-zigbee/{ => zcl}/zigbeecluster.cpp (53%) create mode 100644 libnymea-zigbee/zcl/zigbeecluster.h rename libnymea-zigbee/{ => zcl}/zigbeeclusterattribute.cpp (100%) rename libnymea-zigbee/{ => zcl}/zigbeeclusterattribute.h (100%) delete mode 100644 libnymea-zigbee/zcl/zigbeeclusterbasic.cpp rename libnymea-zigbee/{ => zcl}/zigbeeclusterlibrary.cpp (52%) rename libnymea-zigbee/{ => zcl}/zigbeeclusterlibrary.h (80%) delete mode 100644 libnymea-zigbee/zigbeecluster.h delete mode 100644 libnymea-zigbee/zigbeeclusterlibraryreply.cpp delete mode 100644 libnymea-zigbee/zigbeeclusterlibraryreply.h create mode 100644 libnymea-zigbee/zigbeedatatype.cpp create mode 100644 libnymea-zigbee/zigbeedatatype.h diff --git a/libnymea-zigbee/deconz/interface/deconz.h b/libnymea-zigbee/backends/deconz/interface/deconz.h similarity index 100% rename from libnymea-zigbee/deconz/interface/deconz.h rename to libnymea-zigbee/backends/deconz/interface/deconz.h diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp similarity index 100% rename from libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp rename to libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.h b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.h similarity index 100% rename from libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.h rename to libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.h diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp similarity index 100% rename from libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp rename to libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h similarity index 100% rename from libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h rename to libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp similarity index 100% rename from libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp rename to libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h similarity index 100% rename from libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h rename to libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp similarity index 92% rename from libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp rename to libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp index cbc3d04..d4542c3 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp @@ -327,42 +327,70 @@ void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDat } node->deviceObject()->processApsDataIndication(indication.destinationEndpoint, indication.sourceEndpoint, indication.clusterId, indication.asdu, indication.lqi, indication.rssi); +} -// foreach (ZigbeeNetworkReply *reply, m_pendingReplies.values()) { -// // Check if this is a reply if for a ZDO request -// if (reply->request().profileId() == Zigbee::ZigbeeProfileDevice) { -// // We have a reply which is waiting for a ZDO response, lets check if they match -// // Check if this is the response to the sent request command -// if (indication.clusterId == (reply->request().clusterId() | 0x8000)) { -// // Now check if the id matches, if so set the ADPU as response to the reply, otherwise this is not the message for this reply -// ZigbeeDeviceProfile::Adpu deviceAdpu = ZigbeeDeviceProfile::parseAdpu(indication.asdu); -// if (deviceAdpu.transactionSequenceNumber == reply->request().requestId()) { -// // We found the correct reply +void ZigbeeNetworkDeconz::handleZigbeeLightLinkIndication(const DeconzApsDataIndication &indication) +{ + ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(indication.asdu); + //qCDebug(dcZigbeeNetwork()) << "ZCL ZLL" << indication << frame; -// // Set the response payload of the -// qCDebug(dcZigbeeNetwork()) << "Indication response for ZDO request received" -// << static_cast(reply->request().clusterId()) -// << "-->" -// << static_cast(indication.clusterId) -// << deviceAdpu; -// setReplyResponseData(reply, indication.asdu); -// return; -// } -// } -// } -// } + // Get the node + ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); + if (!node) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; + return; + } - //qCWarning(dcZigbeeNetwork()) << "FIXME: Unhandled ZDO indication" << indication; + // Get the endpoint + ZigbeeNodeEndpoint *endpoint = node->getEndpoint(indication.sourceEndpoint); + if (!endpoint) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized endpoint. There is no such endpoint on" << node << ". Ignoring indication" << indication; + return; + } + + // Get the cluster + ZigbeeCluster *cluster = endpoint->getOutputCluster(static_cast(indication.clusterId)); + if (!cluster) { + cluster = endpoint->getInputCluster(static_cast(indication.clusterId)); + if (!cluster) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized cluster. There is no such cluster on" << node << endpoint << "in the system. Ignoring indication" << indication; + return; + } + } + + cluster->processApsDataIndication(indication.asdu); } void ZigbeeNetworkDeconz::handleZigbeeHomeAutomationIndication(const DeconzApsDataIndication &indication) { - ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(static_cast(indication.clusterId), indication.asdu); - qCDebug(dcZigbeeNetwork()) << "ZCL HA" << indication << frame; + ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(indication.asdu); + //qCDebug(dcZigbeeNetwork()) << "ZCL HA" << indication << frame; + // Get the node + ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); + if (!node) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; + return; + } + // Get the endpoint + ZigbeeNodeEndpoint *endpoint = node->getEndpoint(indication.sourceEndpoint); + if (!endpoint) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized endpoint. There is no such endpoint on" << node << ". Ignoring indication" << indication; + return; + } + // Get the cluster + ZigbeeCluster *cluster = endpoint->getOutputCluster(static_cast(indication.clusterId)); + if (!cluster) { + cluster = endpoint->getInputCluster(static_cast(indication.clusterId)); + if (!cluster) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized cluster. There is no such cluster on" << node << endpoint << "in the system. Ignoring indication" << indication; + return; + } + } + cluster->processApsDataIndication(indication.asdu); } void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h similarity index 96% rename from libnymea-zigbee/deconz/zigbeenetworkdeconz.h rename to libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h index 27020c1..721f792 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h @@ -32,7 +32,7 @@ #include "zigbeenetwork.h" #include "zigbeechannelmask.h" -#include "zigbeeclusterlibrary.h" +#include "zcl/zigbeeclusterlibrary.h" #include "zigbeebridgecontrollerdeconz.h" class ZigbeeNetworkDeconz : public ZigbeeNetwork @@ -75,6 +75,7 @@ private: void handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication); // ZZL + void handleZigbeeLightLinkIndication(const DeconzApsDataIndication &indication); // HA void handleZigbeeHomeAutomationIndication(const DeconzApsDataIndication &indication); diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterface.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterface.cpp similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterface.cpp rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterface.cpp diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterface.h b/libnymea-zigbee/backends/nxp/interface/zigbeeinterface.h similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterface.h rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterface.h diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacemessage.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacemessage.cpp similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacemessage.cpp rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacemessage.cpp diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacemessage.h b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacemessage.h similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacemessage.h rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacemessage.h diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacereply.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacereply.cpp similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacereply.cpp rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacereply.cpp diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacereply.h b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacereply.h similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacereply.h rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacereply.h diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacerequest.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacerequest.cpp similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacerequest.cpp rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacerequest.cpp diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterfacerequest.h b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacerequest.h similarity index 100% rename from libnymea-zigbee/nxp/interface/zigbeeinterfacerequest.h rename to libnymea-zigbee/backends/nxp/interface/zigbeeinterfacerequest.h diff --git a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp similarity index 100% rename from libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp rename to libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp diff --git a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h similarity index 100% rename from libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h rename to libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp similarity index 100% rename from libnymea-zigbee/nxp/zigbeenetworknxp.cpp rename to libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.h b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h similarity index 100% rename from libnymea-zigbee/nxp/zigbeenetworknxp.h rename to libnymea-zigbee/backends/nxp/zigbeenetworknxp.h diff --git a/libnymea-zigbee/nxp/zigbeenodeendpointnxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenodeendpointnxp.cpp similarity index 100% rename from libnymea-zigbee/nxp/zigbeenodeendpointnxp.cpp rename to libnymea-zigbee/backends/nxp/zigbeenodeendpointnxp.cpp diff --git a/libnymea-zigbee/nxp/zigbeenodeendpointnxp.h b/libnymea-zigbee/backends/nxp/zigbeenodeendpointnxp.h similarity index 100% rename from libnymea-zigbee/nxp/zigbeenodeendpointnxp.h rename to libnymea-zigbee/backends/nxp/zigbeenodeendpointnxp.h diff --git a/libnymea-zigbee/nxp/zigbeenodenxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenodenxp.cpp similarity index 100% rename from libnymea-zigbee/nxp/zigbeenodenxp.cpp rename to libnymea-zigbee/backends/nxp/zigbeenodenxp.cpp diff --git a/libnymea-zigbee/nxp/zigbeenodenxp.h b/libnymea-zigbee/backends/nxp/zigbeenodenxp.h similarity index 100% rename from libnymea-zigbee/nxp/zigbeenodenxp.h rename to libnymea-zigbee/backends/nxp/zigbeenodenxp.h diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 95949c1..44c5cbc 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -4,30 +4,22 @@ TARGET = nymea-zigbee1 TEMPLATE = lib SOURCES += \ - deconz/interface/zigbeeinterfacedeconz.cpp \ - deconz/interface/zigbeeinterfacedeconzreply.cpp \ - deconz/zigbeebridgecontrollerdeconz.cpp \ - deconz/zigbeenetworkdeconz.cpp \ -# nxp/interface/zigbeeinterface.cpp \ -# nxp/interface/zigbeeinterfacemessage.cpp \ -# nxp/interface/zigbeeinterfacerequest.cpp \ -# nxp/interface/zigbeeinterfacereply.cpp \ -# nxp/zigbeenetworknxp.cpp \ -# nxp/zigbeebridgecontrollernxp.cpp \ -# nxp/zigbeenodeendpointnxp.cpp \ -# nxp/zigbeenodenxp.cpp \ - zcl/zigbeeclusterbasic.cpp \ + backends/deconz/interface/zigbeeinterfacedeconz.cpp \ + backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \ + backends/deconz/zigbeebridgecontrollerdeconz.cpp \ + backends/deconz/zigbeenetworkdeconz.cpp \ + zcl/zigbeecluster.cpp \ + zcl/zigbeeclusterattribute.cpp \ + zcl/zigbeeclusterlibrary.cpp \ zcl/zigbeeclusterreply.cpp \ + zcl/general/zigbeeclusterbasic.cpp \ zdo/zigbeedeviceobject.cpp \ zdo/zigbeedeviceobjectreply.cpp \ zdo/zigbeedeviceprofile.cpp \ zigbeeadpu.cpp \ zigbeebridgecontroller.cpp \ zigbeechannelmask.cpp \ - zigbeecluster.cpp \ - zigbeeclusterattribute.cpp \ - zigbeeclusterlibrary.cpp \ - zigbeeclusterlibraryreply.cpp \ + zigbeedatatype.cpp \ zigbeemanufacturer.cpp \ zigbeenetwork.cpp \ zigbeenetworkdatabase.cpp \ @@ -42,34 +34,33 @@ SOURCES += \ zigbeeutils.cpp \ zigbeenode.cpp \ zigbeeaddress.cpp \ - + # nxp/interface/zigbeeinterface.cpp \ + # nxp/interface/zigbeeinterfacemessage.cpp \ + # nxp/interface/zigbeeinterfacerequest.cpp \ + # nxp/interface/zigbeeinterfacereply.cpp \ + # nxp/zigbeenetworknxp.cpp \ + # nxp/zigbeebridgecontrollernxp.cpp \ + # nxp/zigbeenodeendpointnxp.cpp \ + # nxp/zigbeenodenxp.cpp \ HEADERS += \ - deconz/interface/deconz.h \ - deconz/interface/zigbeeinterfacedeconz.h \ - deconz/interface/zigbeeinterfacedeconzreply.h \ - deconz/zigbeebridgecontrollerdeconz.h \ - deconz/zigbeenetworkdeconz.h \ -# nxp/interface/zigbeeinterface.h \ -# nxp/interface/zigbeeinterfacemessage.h \ -# nxp/interface/zigbeeinterfacerequest.h \ -# nxp/interface/zigbeeinterfacereply.h \ -# nxp/zigbeenetworknxp.h \ -# nxp/zigbeebridgecontrollernxp.h \ -# nxp/zigbeenodeendpointnxp.h \ -# nxp/zigbeenodenxp.h \ - zcl/zigbeeclusterbasic.h \ + backends/deconz/interface/deconz.h \ + backends/deconz/interface/zigbeeinterfacedeconz.h \ + backends/deconz/interface/zigbeeinterfacedeconzreply.h \ + backends/deconz/zigbeebridgecontrollerdeconz.h \ + backends/deconz/zigbeenetworkdeconz.h \ + zcl/zigbeecluster.h \ + zcl/zigbeeclusterattribute.h \ + zcl/zigbeeclusterlibrary.h \ zcl/zigbeeclusterreply.h \ + zcl/general/zigbeeclusterbasic.h \ zdo/zigbeedeviceobject.h \ zdo/zigbeedeviceobjectreply.h \ zdo/zigbeedeviceprofile.h \ zigbeeadpu.h \ zigbeebridgecontroller.h \ zigbeechannelmask.h \ - zigbeecluster.h \ - zigbeeclusterattribute.h \ - zigbeeclusterlibrary.h \ - zigbeeclusterlibraryreply.h \ + zigbeedatatype.h \ zigbeemanufacturer.h \ zigbeenetwork.h \ zigbeenetworkdatabase.h \ @@ -84,7 +75,14 @@ HEADERS += \ zigbeeutils.h \ zigbeenode.h \ zigbeeaddress.h \ - + # nxp/interface/zigbeeinterface.h \ + # nxp/interface/zigbeeinterfacemessage.h \ + # nxp/interface/zigbeeinterfacerequest.h \ + # nxp/interface/zigbeeinterfacereply.h \ + # nxp/zigbeenetworknxp.h \ + # nxp/zigbeebridgecontrollernxp.h \ + # nxp/zigbeenodeendpointnxp.h \ + # nxp/zigbeenodenxp.h \ # install header file with relative subdirectory for (header, HEADERS) { diff --git a/libnymea-zigbee/loggingcategory.cpp b/libnymea-zigbee/loggingcategory.cpp index 092d9b4..c20bea5 100644 --- a/libnymea-zigbee/loggingcategory.cpp +++ b/libnymea-zigbee/loggingcategory.cpp @@ -34,5 +34,6 @@ Q_LOGGING_CATEGORY(dcZigbeeCluster, "ZigbeeCluster") Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") Q_LOGGING_CATEGORY(dcZigbeeDeviceObject, "ZigbeeDeviceObject") +Q_LOGGING_CATEGORY(dcZigbeeClusterLibrary, "ZigbeeClusterLibrary") Q_LOGGING_CATEGORY(dcZigbeeNetworkDatabase, "ZigbeeNetworkDatabase") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/libnymea-zigbee/loggingcategory.h b/libnymea-zigbee/loggingcategory.h index b24c6ca..5510b20 100644 --- a/libnymea-zigbee/loggingcategory.h +++ b/libnymea-zigbee/loggingcategory.h @@ -38,6 +38,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcZigbeeCluster) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeDeviceObject) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeClusterLibrary) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetworkDatabase) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp new file mode 100644 index 0000000..8eee12c --- /dev/null +++ b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp @@ -0,0 +1,21 @@ +#include "zigbeeclusterbasic.h" +#include "loggingcategory.h" + +ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : + ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdBasic, direction, parent) +{ + +} + +void ZigbeeClusterBasic::setAttribute(const ZigbeeClusterAttribute &attribute) +{ + if (hasAttribute(attribute.id())) { + qCDebug(dcZigbeeCluster()) << this << "update attribute" << static_cast(attribute.id()) << attribute.dataType() << attribute.data(); + m_attributes[attribute.id()] = attribute; + emit attributeChanged(attribute); + } else { + qCDebug(dcZigbeeCluster()) << this << "add attribute" << static_cast(attribute.id()) << attribute.dataType() << attribute.data(); + m_attributes.insert(attribute.id(), attribute); + emit attributeChanged(attribute); + } +} diff --git a/libnymea-zigbee/zcl/zigbeeclusterbasic.h b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h similarity index 87% rename from libnymea-zigbee/zcl/zigbeeclusterbasic.h rename to libnymea-zigbee/zcl/general/zigbeeclusterbasic.h index 1ed3849..a73d647 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterbasic.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h @@ -3,13 +3,16 @@ #include -#include "zigbeecluster.h" +#include "zcl/zigbeecluster.h" class ZigbeeClusterBasic : public ZigbeeCluster { Q_OBJECT public: + friend class ZigbeeNode; + friend class ZigbeeNetwork; + enum Attribute { AttributeZclVersion = 0x0000, // Mandatory AttributeAppVersion = 0x0001, @@ -28,7 +31,7 @@ public: }; Q_ENUM(Attribute) - // From attribute 0x0007 power source + // Enum for AttributePowerSource(0x0007) enum AttributePowerSourceValue { AttributePowerSourceValueUnknown = 0x00, AttributePowerSourceValueMainsSinglePhase = 0x01, @@ -40,9 +43,10 @@ public: }; Q_ENUM(AttributePowerSourceValue) - explicit ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); +private: + void setAttribute(const ZigbeeClusterAttribute &attribute) override; signals: diff --git a/libnymea-zigbee/zigbeecluster.cpp b/libnymea-zigbee/zcl/zigbeecluster.cpp similarity index 53% rename from libnymea-zigbee/zigbeecluster.cpp rename to libnymea-zigbee/zcl/zigbeecluster.cpp index 586eaac..f6311cc 100644 --- a/libnymea-zigbee/zigbeecluster.cpp +++ b/libnymea-zigbee/zcl/zigbeecluster.cpp @@ -74,14 +74,14 @@ bool ZigbeeCluster::hasAttribute(quint16 attributeId) const return m_attributes.keys().contains(attributeId); } -ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 id) +ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 attributeId) { - return m_attributes.value(id); + return m_attributes.value(attributeId); } void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute) { - if (hasAttribute(attribute.id())) { + if (hasAttribute(attribute.id())) { qCDebug(dcZigbeeCluster()) << this << "update attribute" << attribute; m_attributes[attribute.id()] = attribute; emit attributeChanged(attribute); @@ -92,28 +92,31 @@ void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute) } } -ZigbeeNetworkReply *ZigbeeCluster::readAttributes(QList attributes) +ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList attributes) { + qCDebug(dcZigbeeClusterLibrary()) << "Read attributes from" << m_node << m_endpoint << this << attributes; + // Build the request - ZigbeeNetworkRequest request; - request.setRequestId(m_network->generateSequenceNumber()); - request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress); - request.setDestinationShortAddress(static_cast(m_node->shortAddress())); - request.setProfileId(m_endpoint->profile()); - request.setClusterId(m_clusterId); - request.setSourceEndpoint(m_endpoint->endpointId()); - request.setRadius(10); + ZigbeeNetworkRequest request = createGeneralRequest(); // Build ZCL frame + + // Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1 ZigbeeClusterLibrary::FrameControl frameControl; - frameControl.frameType = ZigbeeClusterLibrary::FrameTypeGlobal; // Note: for general commands always use global + frameControl.frameType = ZigbeeClusterLibrary::FrameTypeGlobal; + frameControl.manufacturerSpecific = false; + if (m_direction == Direction::Input) { + frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer; + } else { + frameControl.direction = ZigbeeClusterLibrary::DirectionServerToClient; + } frameControl.disableDefaultResponse = true; // ZCL header ZigbeeClusterLibrary::Header header; header.frameControl = frameControl; header.command = ZigbeeClusterLibrary::CommandReadAttributes; - header.transactionSequenceNumber = m_network->generateTranactionSequenceNumber(); + header.transactionSequenceNumber = m_transactionSequenceNumber++; // ZCL payload QByteArray payload; @@ -125,15 +128,108 @@ ZigbeeNetworkReply *ZigbeeCluster::readAttributes(QList attributes) // Put them together ZigbeeClusterLibrary::Frame frame; - frame.clusterId = m_clusterId; frame.header = header; frame.payload = payload; request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission)); request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame)); - qCDebug(dcZigbeeCluster()) << "Send read attributes request" << m_node << m_endpoint << this << attributes; - return m_network->sendRequest(request); + ZigbeeClusterReply *zclReply = createClusterReply(request, frame); + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ + if (!verifyNetworkError(zclReply, networkReply)) { + qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request" + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZclReply(zclReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zclReply->isComplete()) { + finishZclReply(zclReply); + return; + } + }); + + return zclReply; +} + +ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame) +{ + ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this); + connect(zclReply, &ZigbeeClusterReply::finished, zclReply, &ZigbeeClusterReply::deleteLater); + zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber; + m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply); + return zclReply; +} + +ZigbeeNetworkRequest ZigbeeCluster::createGeneralRequest() +{ + // Build the request + ZigbeeNetworkRequest request; + request.setRequestId(m_network->generateSequenceNumber()); + request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress); + request.setDestinationShortAddress(m_node->shortAddress()); + request.setProfileId(Zigbee::ZigbeeProfileHomeAutomation); // Note: in Zigbee 3.0 this is the Application Profile (0x0104) + request.setClusterId(m_clusterId); + request.setSourceEndpoint(0x01); + request.setDestinationEndpoint(m_endpoint->endpointId()); + request.setRadius(10); + request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission)); + return request; +} + +bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply) +{ + bool success = false; + switch (networkReply->error()) { + case ZigbeeNetworkReply::ErrorNoError: + // The request has been transported successfully to he destination, now + // wait for the expected indication or check if we already recieved it + zclReply->m_apsConfirmReceived = true; + zclReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus(); + success = true; + break; + case ZigbeeNetworkReply::ErrorInterfaceError: + zclReply->m_error = ZigbeeClusterReply::ErrorInterfaceError; + break; + case ZigbeeNetworkReply::ErrorNetworkOffline: + zclReply->m_error = ZigbeeClusterReply::ErrorNetworkOffline; + break; + case ZigbeeNetworkReply::ErrorZigbeeApsStatusError: + zclReply->m_error = ZigbeeClusterReply::ErrorZigbeeApsStatusError; + zclReply->m_apsConfirmReceived = true; + zclReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus(); + break; + } + + return success; +} + +void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply) +{ + m_pendingReplies.remove(zclReply->transactionSequenceNumber()); + zclReply->finished(); +} + +void ZigbeeCluster::processApsDataIndication(QByteArray payload) +{ + ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(payload); + qCDebug(dcZigbeeClusterLibrary()) << this << "received data indication" << frame; + + if (m_pendingReplies.contains(frame.header.transactionSequenceNumber)) { + ZigbeeClusterReply *reply = m_pendingReplies.value(frame.header.transactionSequenceNumber); + reply->m_responseData = payload; + reply->m_responseFrame = frame; + reply->m_zclIndicationReceived = true; + + if (reply->isComplete()) + finishZclReply(reply); + } + + } QDebug operator<<(QDebug debug, ZigbeeCluster *cluster) @@ -143,7 +239,6 @@ QDebug operator<<(QDebug debug, ZigbeeCluster *cluster) << cluster->clusterName() << ", " << cluster->direction() << ")"; - return debug.space(); } @@ -159,3 +254,4 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeRep return debug.space(); } + diff --git a/libnymea-zigbee/zcl/zigbeecluster.h b/libnymea-zigbee/zcl/zigbeecluster.h new file mode 100644 index 0000000..af16c2d --- /dev/null +++ b/libnymea-zigbee/zcl/zigbeecluster.h @@ -0,0 +1,213 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEECLUSTER_H +#define ZIGBEECLUSTER_H + +#include + +#include "zigbee.h" +#include "zigbeeclusterreply.h" +#include "zigbeeclusterlibrary.h" +#include "zigbeeclusterattribute.h" + +struct ZigbeeClusterReportConfigurationRecord { + quint8 direction; + Zigbee::DataType dataType; + quint16 attributeId; + quint16 minInterval; + quint16 maxInterval; + quint16 timeout; + quint8 change; +}; + +typedef struct ZigbeeClusterAttributeReport { + quint16 sourceAddress; + quint8 endpointId; + Zigbee::ClusterId clusterId; + quint16 attributeId; + Zigbee::ZigbeeStatus attributeStatus; + Zigbee::DataType dataType; + QByteArray data; +} ZigbeeClusterAttributeReport; + +class ZigbeeNode; +class ZigbeeNetwork; +class ZigbeeNodeEndpoint; +class ZigbeeNetworkReply; + +class ZigbeeCluster : public QObject +{ + Q_OBJECT + + friend class ZigbeeNode; + friend class ZigbeeNetwork; + +public: + enum Direction { + Input, + Output + }; + Q_ENUM(Direction) + + +// // Power configuration cluster 0x0001 + +// enum PowerConfigurationAttribute { +// PowerConfigurationAttributeMainsInformation = 0x0000, +// PowerConfigurationAttributeMainsSettings = 0x0001, +// PowerConfigurationAttributeBatteryInformation = 0x0002, +// PowerConfigurationAttributeBatterySettings = 0x0003, +// PowerConfigurationAttributeBatterySource2Information = 0x0004, +// PowerConfigurationAttributeBattterySource2Settings = 0x0005, +// PowerConfigurationAttributeBatterySource3Information = 0x0006, +// PowerConfigurationAttributeBattterySource3Settings = 0x0007 +// }; +// Q_ENUM(PowerConfigurationAttribute) + +// // On Off Cluster 0x0006 + +// enum OnOffClusterAttribute { +// OnOffClusterAttributeOnOff = 0x0000, +// OnOffClusterAttributeGlobalSceneControl = 0x4000, +// OnOffClusterAttributeOnTime = 0x4001, +// OnOffClusterAttributeOffWaitTime = 0x4002 +// }; +// Q_ENUM(OnOffClusterAttribute) + +// enum OnOffClusterCommand { +// OnOffClusterCommandOff = 0x00, +// OnOffClusterCommandOn = 0x01, +// OnOffClusterCommandToggle = 0x02 +// }; +// Q_ENUM(OnOffClusterCommand) + + +// // Level cluster 0x0008 + +// enum LevelClusterAttribute { +// LevelClusterAttributeCurrentLevel = 0x0000, +// LevelClusterAttributeRemainingTime = 0x0001, +// LevelClusterAttributeOnOffTransitionTime = 0x0010, +// LevelClusterAttributeOnLevel = 0x0011, +// LevelClusterAttributeOnTransitionTime = 0x0012, +// LevelClusterAttributeOffTransitionTime = 0x0013, +// LevelClusterAttributeDefaultMoveRate = 0x0014 +// }; +// Q_ENUM(LevelClusterAttribute) + +// enum LevelClusterCommand { +// LevelClusterCommandMoveToLevel = 0x00, +// LevelClusterCommandMove = 0x01, +// LevelClusterCommandStep = 0x02, +// LevelClusterCommandStop = 0x03, +// LevelClusterCommandMoveToLevelWithOnOff = 0x04, +// LevelClusterCommandMoveWithOnOff = 0x05, +// LevelClusterCommandStepWithOnOff = 0x06, +// LevelClusterCommandStopWithOnOff = 0x07, +// }; +// Q_ENUM(LevelClusterCommand) + +// // Color cluster 0x0300 + +// enum ColorControlClusterAttribute { +// ColorControlClusterAttributeCurrentHue = 0x0000, +// ColorControlClusterAttributeCurrentSaturation = 0x0001, +// ColorControlClusterAttributeRemainingTime = 0x0002, +// ColorControlClusterAttributeCurrentX = 0x0003, +// ColorControlClusterAttributeCurrentY = 0x0004, +// ColorControlClusterAttributeDriftCompensation = 0x0005, +// ColorControlClusterAttributeCompensationText = 0x0006, +// ColorControlClusterAttributeColorTemperatureMireds = 0x0007, +// ColorControlClusterAttributeColorMode = 0x0008, +// ColorControlClusterAttributeEnhancedCurrentHue = 0x4000, +// ColorControlClusterAttributeEnhancedColorMode = 0x4001, +// ColorControlClusterAttributeColorLoopActive = 0x4002, +// ColorControlClusterAttributeColorLoopDirection = 0x4003, +// ColorControlClusterAttributeColorLoopTime = 0x4004, +// ColorControlClusterAttributeColorLoopStartEnhancedHue = 0x4005, +// ColorControlClusterAttributeColorLoopStoredEnhancedHue = 0x4006, +// ColorControlClusterAttributeColorCapabilities = 0x400a, +// ColorControlClusterAttributeColorTempPhysicalMinMireds = 0x400b, +// ColorControlClusterAttributeColorTempPhysicalMaxMireds = 0x400c +// }; +// Q_ENUM(ColorControlClusterAttribute) + +// enum ColorControlClusterColorMode { +// ColorControlClusterColorModeHueSaturation = 0x00, +// ColorControlClusterColorModeXY = 0x01, +// ColorControlClusterColorModeColorTemperatureMired = 0x02 +// }; +// Q_ENUM(ColorControlClusterColorMode) + + explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent = nullptr); + + Direction direction() const; + + Zigbee::ClusterId clusterId() const; + QString clusterName() const; + + QList attributes() const; + bool hasAttribute(quint16 attributeId) const; + ZigbeeClusterAttribute attribute(quint16 attributeId); + + // ZCL global commands + ZigbeeClusterReply *readAttributes(QList attributes); + +protected: + ZigbeeNetwork *m_network = nullptr; + ZigbeeNode *m_node = nullptr; + ZigbeeNodeEndpoint *m_endpoint= nullptr; + + Zigbee::ClusterId m_clusterId = Zigbee::ClusterIdUnknown; + Direction m_direction = Input; + QHash m_attributes; + + ZigbeeNetworkRequest createGeneralRequest(); + quint8 m_transactionSequenceNumber = 0; + QHash m_pendingReplies; + ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame); + + bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply); + void finishZclReply(ZigbeeClusterReply *zclReply); + +private: + virtual void setAttribute(const ZigbeeClusterAttribute &attribute); + +signals: + void attributeChanged(const ZigbeeClusterAttribute &attribute); + +public slots: + void processApsDataIndication(QByteArray payload); + + +}; + +QDebug operator<<(QDebug debug, ZigbeeCluster *cluster); +QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeReport); + +#endif // ZIGBEECLUSTER_H diff --git a/libnymea-zigbee/zigbeeclusterattribute.cpp b/libnymea-zigbee/zcl/zigbeeclusterattribute.cpp similarity index 100% rename from libnymea-zigbee/zigbeeclusterattribute.cpp rename to libnymea-zigbee/zcl/zigbeeclusterattribute.cpp diff --git a/libnymea-zigbee/zigbeeclusterattribute.h b/libnymea-zigbee/zcl/zigbeeclusterattribute.h similarity index 100% rename from libnymea-zigbee/zigbeeclusterattribute.h rename to libnymea-zigbee/zcl/zigbeeclusterattribute.h diff --git a/libnymea-zigbee/zcl/zigbeeclusterbasic.cpp b/libnymea-zigbee/zcl/zigbeeclusterbasic.cpp deleted file mode 100644 index ff5cf1f..0000000 --- a/libnymea-zigbee/zcl/zigbeeclusterbasic.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "zigbeeclusterbasic.h" - -ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : - ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdBasic, direction, parent) -{ - -} diff --git a/libnymea-zigbee/zigbeeclusterlibrary.cpp b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp similarity index 52% rename from libnymea-zigbee/zigbeeclusterlibrary.cpp rename to libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp index 9ae2b5a..586e964 100644 --- a/libnymea-zigbee/zigbeeclusterlibrary.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp @@ -26,6 +26,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeeclusterlibrary.h" +#include "loggingcategory.h" #include "zigbeeutils.h" #include @@ -35,7 +36,7 @@ quint8 ZigbeeClusterLibrary::buildFrameControlByte(const ZigbeeClusterLibrary::F quint8 byte = 0x00; // Bit 0-1 - byte |= FrameTypeClusterSpecific; + byte |= frameControl.frameType; // Bit 2 if (frameControl.manufacturerSpecific) @@ -93,7 +94,95 @@ QByteArray ZigbeeClusterLibrary::buildHeader(const ZigbeeClusterLibrary::Header return headerData; } -ZigbeeClusterLibrary::Frame ZigbeeClusterLibrary::parseFrameData(Zigbee::ClusterId clusterId, const QByteArray &frameData) +QList ZigbeeClusterLibrary::parseAttributeStatusRecords(const QByteArray &payload) +{ + // Read attribute status records + QList attributeStatusRecords; + + qCDebug(dcZigbeeClusterLibrary()) << "Parse attribute status records from" << ZigbeeUtils::convertByteArrayToHexString(payload); + + QDataStream stream(payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint16 attributeId; quint8 statusInt; quint8 dataTypeInt; quint16 numberOfElenemts; quint8 elementType; + QByteArray data; + + while (!stream.atEnd()) { + // Reset variables + attributeId = 0; statusInt = 0; dataTypeInt = 0; numberOfElenemts = 0; elementType = 0; + data.clear(); + + // Read attribute id and status + stream >> attributeId >> statusInt; + Zigbee::ZigbeeStatus status = static_cast(statusInt); + + qCDebug(dcZigbeeClusterLibrary()) << "Parse:" << ZigbeeUtils::convertUint16ToHexString(attributeId) << status; + + if (status != Zigbee::ZigbeeStatusSuccess) { + qCWarning(dcZigbeeCluster()) << "Attribute status record" << ZigbeeUtils::convertUint16ToHexString(attributeId) << "finished with error" << status; + // If not success, we are done and can continue with the next status record + continue; + } else { + stream >> dataTypeInt; + Zigbee::DataType dataType = static_cast(dataTypeInt); + + qCDebug(dcZigbeeClusterLibrary()) << "Parse:" << dataType; + + // Parse data depending on the type + if (dataType == Zigbee::Array || dataType == Zigbee::Set || dataType == Zigbee::Bag) { + stream >> elementType >> numberOfElenemts; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (array, set, bag): Element type" << ZigbeeUtils::convertByteToHexString(elementType) << "Number of elements:" << numberOfElenemts; + if (numberOfElenemts == 0xffff) { + qCWarning(dcZigbeeCluster()) << "ZigbeeStatusRecord contains invalid elements" << ZigbeeUtils::convertUint16ToHexString(attributeId) << dataType; + continue; + } else { + for (int i = 0; i < numberOfElenemts; i++) { + quint8 element = 0; + stream >> element; + data.append(element); + } + } + } else if (dataType == Zigbee::Structure) { + stream >> numberOfElenemts; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (structure)" << "Number of elements:" << numberOfElenemts; + if (numberOfElenemts == 0xffff) { + qCWarning(dcZigbeeCluster()) << "ZigbeeStatusRecord contains invalid elements" << ZigbeeUtils::convertUint16ToHexString(attributeId) << dataType; + continue; + } else { + stream >> elementType; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (structure)" << "Element type:" << ZigbeeUtils::convertByteToHexString(elementType); + for (int i = 0; i < numberOfElenemts; i++) { + quint8 element = 0; + stream >> element; + //qCDebug(dcZigbeeClusterLibrary()) << "Parse (structure)" << "Element value:" << ZigbeeUtils::convertByteToHexString(element); + data.append(element); + } + } + } else { + // Normal data type + quint8 length = 0; + stream >> length; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (normal data type)" << "Number of elements:" << length; + for (int i = 0; i < length; i++) { + quint8 element = 0; + stream >> element; + data.append(element); + } + } + + ReadAttributeStatusRecord attributeRecord; + attributeRecord.attributeId = attributeId; + attributeRecord.attributeStatus = status; + attributeRecord.dataType = dataType; + attributeRecord.data = data; + qCDebug(dcZigbeeClusterLibrary()) << attributeRecord; + attributeStatusRecords.append(attributeRecord); + } + } + + return attributeStatusRecords; +} + +ZigbeeClusterLibrary::Frame ZigbeeClusterLibrary::parseFrameData(const QByteArray &frameData) { QDataStream stream(frameData); stream.setByteOrder(QDataStream::LittleEndian); @@ -117,15 +206,12 @@ ZigbeeClusterLibrary::Frame ZigbeeClusterLibrary::parseFrameData(Zigbee::Cluster offset += 1; stream >> commandByte; - offset += 1; - header.command = static_cast(commandByte); offset += 1; Frame frame; - frame.clusterId = clusterId; frame.header = header; - frame.payload = frameData.right(frameData.length() - offset - 1); + frame.payload = frameData.right(frameData.length() - offset); return frame; } @@ -169,8 +255,20 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Header &header) QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame) { - debug.nospace() << "Zigbee Cluster Library Frame(" << frame.clusterId << ", "; + debug.nospace() << "Frame("; debug.nospace() << frame.header; debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(frame.payload) << ")"; return debug.space(); } + +QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord) +{ + debug.nospace().noquote() << "ReadAttributeStatusRecord(" + << ZigbeeUtils::convertUint16ToHexString(attributeStatusRecord.attributeId) << ", " + << attributeStatusRecord.attributeStatus << ", " + << attributeStatusRecord.dataType << ", " + << attributeStatusRecord.data + << ")"; + + return debug.space(); +} diff --git a/libnymea-zigbee/zigbeeclusterlibrary.h b/libnymea-zigbee/zcl/zigbeeclusterlibrary.h similarity index 80% rename from libnymea-zigbee/zigbeeclusterlibrary.h rename to libnymea-zigbee/zcl/zigbeeclusterlibrary.h index 37a9707..bb4971b 100644 --- a/libnymea-zigbee/zigbeeclusterlibrary.h +++ b/libnymea-zigbee/zcl/zigbeeclusterlibrary.h @@ -65,6 +65,18 @@ public: }; Q_ENUM(Command) + enum GlobalAttribute { + GlobalAttributeClusterRevision = 0xfffd, + GlobalAttributeAttributeReportingStatus = 0xfffe + }; + Q_ENUM(GlobalAttribute) + + enum AttributeReportingStatus { + AttributeReportingStatusPending = 0x00, + AttributeReportingStatusComplete = 0x01 + }; + Q_ENUM(AttributeReportingStatus) + // Frame control field enum FrameType { FrameTypeGlobal = 0x00, @@ -79,7 +91,7 @@ public: Q_ENUM(Direction) typedef struct FrameControl { - FrameType frameType = FrameTypeClusterSpecific; + FrameType frameType = FrameTypeGlobal; bool manufacturerSpecific = false; Direction direction = DirectionClientToServer; bool disableDefaultResponse = false; @@ -93,24 +105,39 @@ public: } ZclHeader; typedef struct Frame { - Zigbee::ClusterId clusterId; Header header; QByteArray payload; } Frame; + + // Read attribute + typedef struct ReadAttributeStatusRecord { + quint16 attributeId; + Zigbee::ZigbeeStatus attributeStatus; + Zigbee::DataType dataType; + QByteArray data; + } ReadAttributeStatusRecord; + + // General parse/build methods static quint8 buildFrameControlByte(const FrameControl &frameControl); static FrameControl parseFrameControlByte(quint8 frameControlByte); static QByteArray buildHeader(const Header &header); - static Frame parseFrameData(Zigbee::ClusterId clusterId, const QByteArray &frameData); + static QList parseAttributeStatusRecords(const QByteArray &payload); + + //static QByteArray readAttributeData(const QDataStream &stream, Zigbee::DataType dataType); + + + static Frame parseFrameData(const QByteArray &frameData); static QByteArray buildFrame(const Frame &frame); }; QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::FrameControl &frameControl); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Header &header); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame); +QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord); #endif // ZIGBEECLUSTERLIBRARY_H diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp index 42f863d..3fb9164 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp @@ -1,6 +1,44 @@ #include "zigbeeclusterreply.h" -ZigbeeClusterReply::ZigbeeClusterReply(QObject *parent) : QObject(parent) +ZigbeeClusterReply::Error ZigbeeClusterReply::error() const +{ + return m_error; +} + +ZigbeeNetworkRequest ZigbeeClusterReply::request() const +{ + return m_request; +} + +ZigbeeClusterLibrary::Frame ZigbeeClusterReply::requestFrame() const +{ + return m_requestFrame; +} + +quint8 ZigbeeClusterReply::transactionSequenceNumber() const +{ + return m_transactionSequenceNumber; +} + +QByteArray ZigbeeClusterReply::responseData() const +{ + return m_responseData; +} + +ZigbeeClusterLibrary::Frame ZigbeeClusterReply::responseFrame() const +{ + return m_responseFrame; +} + +bool ZigbeeClusterReply::isComplete() const +{ + return m_apsConfirmReceived && m_zclIndicationReceived; +} + +ZigbeeClusterReply::ZigbeeClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent) : + QObject(parent), + m_request(request), + m_requestFrame(requestFrame) { } diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.h b/libnymea-zigbee/zcl/zigbeeclusterreply.h index ebc4c1e..b035e1c 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.h +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.h @@ -3,13 +3,59 @@ #include +#include "zigbeenetworkrequest.h" +#include "zigbeeclusterlibrary.h" + class ZigbeeClusterReply : public QObject { Q_OBJECT + + friend class ZigbeeCluster; + public: - explicit ZigbeeClusterReply(QObject *parent = nullptr); + enum Error { + ErrorNoError, // All OK, no error occured, the message was transported successfully + ErrorTimeout, // The request timeouted + ErrorZigbeeApsStatusError, // An APS transport error occured. See zigbeeApsStatus() + ErrorInterfaceError, // A transport interface error occured. Could not communicate with the hardware. + ErrorNetworkOffline // The network is offline. Cannot send any requests + }; + Q_ENUM(Error) + + Error error() const; + + ZigbeeNetworkRequest request() const; + ZigbeeClusterLibrary::Frame requestFrame() const; + + quint8 transactionSequenceNumber() const; + + QByteArray responseData() const; + ZigbeeClusterLibrary::Frame responseFrame() const; + + bool isComplete() const; + +private: + explicit ZigbeeClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent = nullptr); + + Error m_error = ErrorNoError; + + // Request + quint8 m_transactionSequenceNumber = 0; + ZigbeeNetworkRequest m_request; + ZigbeeClusterLibrary::Frame m_requestFrame; + + // Response + bool m_apsConfirmReceived = false; + Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess; + + ZigbeeClusterLibrary::Command m_expectedResponse; + + bool m_zclIndicationReceived = false; + QByteArray m_responseData; + ZigbeeClusterLibrary::Frame m_responseFrame; signals: + void finished(); }; diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h index b7ff3e0..1117415 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h @@ -41,7 +41,7 @@ class ZigbeeDeviceObjectReply : public QObject public: enum Error { - ErrorNoError, // All OK, no error occured + ErrorNoError, // All OK, no error occured, the message was transported successfully ErrorTimeout, // The request timeouted ErrorZigbeeApsStatusError, // An APS transport error occured. See zigbeeApsStatus() ErrorInterfaceError, // A transport interface error occured. Could not communicate with the hardware. @@ -81,7 +81,6 @@ private: QByteArray m_responseData; ZigbeeDeviceProfile::Adpu m_responseAdpu; - signals: void finished(); diff --git a/libnymea-zigbee/zigbeecluster.h b/libnymea-zigbee/zigbeecluster.h deleted file mode 100644 index d18c308..0000000 --- a/libnymea-zigbee/zigbeecluster.h +++ /dev/null @@ -1,234 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea-zigbee. -* This project including source code and documentation is protected by copyright law, and -* remains the property of nymea GmbH. All rights, including reproduction, publication, -* editing and translation, are reserved. The use of this project is subject to the terms of a -* license agreement to be concluded with nymea GmbH in accordance with the terms -* of use of nymea GmbH, available under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the terms of the GNU -* Lesser General Public License as published by the Free Software Foundation; version 3. -* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License along with this project. -* If not, see . -* -* For any further details and any questions please contact us under contact@nymea.io -* or see our FAQ/Licensing Information on https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef ZIGBEECLUSTER_H -#define ZIGBEECLUSTER_H - -#include - -#include "zigbee.h" -#include "zigbeeclusterlibrary.h" -#include "zigbeeclusterattribute.h" - -struct ZigbeeClusterReportConfigurationRecord { - quint8 direction; - Zigbee::DataType dataType; - quint16 attributeId; - quint16 minInterval; - quint16 maxInterval; - quint16 timeout; - quint8 change; -}; - -typedef struct ZigbeeClusterAttributeReport { - quint16 sourceAddress; - quint8 endpointId; - Zigbee::ClusterId clusterId; - quint16 attributeId; - Zigbee::ZigbeeStatus attributeStatus; - Zigbee::DataType dataType; - QByteArray data; -} ZigbeeClusterAttributeReport; - - -class ZigbeeNode; -class ZigbeeNetwork; -class ZigbeeNodeEndpoint; -class ZigbeeNetworkReply; - -class ZigbeeCluster : public QObject -{ - Q_OBJECT - - friend class ZigbeeNode; - -public: - enum Direction { - Input, - Output - }; - Q_ENUM(Direction) - - // Basic clustr 0x0000 - - // Attributes from the basic cluster 0x0000 - enum BasicAttribute { - BasicAttributeZclVersion = 0x0000, // Mandatory - BasicAttributeAppVersion = 0x0001, - BasicAttributeStackVersion = 0x0002, - BasicAttributeHardwareVersion = 0x0003, - BasicAttributeManufacturerName = 0x0004, - BasicAttributeModelIdentifier = 0x0005, - BasicAttributeDateCode = 0x0006, // ISO 8601 YYYYMMDD - BasicAttributePowerSource = 0x0007, // Mandatory - BasicAttributeLocationDescription = 0x0010, - BasicAttributePhysicalEnvironment = 0x0011, - BasicAttributeDeviceEnabled = 0x0012, // 0: disabled, 1: enabled - BasicAttributeAlarmMask = 0x0013, - BasicAttributeDisableLocalConfig = 0x0014, - BasicAttributeSwBuildId = 0x4000 - }; - Q_ENUM(BasicAttribute) - - // From the Basic cluster attribute 0x0007 power source - enum BasicAttributePowerSourceValue { - BasicAttributePowerSourceValueUnknown = 0x00, - BasicAttributePowerSourceValueMainsSinglePhase = 0x01, - BasicAttributePowerSourceValueMainsThreePhase = 0x02, - BasicAttributePowerSourceValueBattery = 0x03, - BasicAttributePowerSourceValueDcSource = 0x04, - BasicAttributePowerSourceValueEmergencyMainsConstantlyPowered = 0x05, - BasicAttributePowerSourceValueEmergencyMainsTransferSwitch = 0x06 - }; - Q_ENUM(BasicAttributePowerSourceValue) - - // Power configuration cluster 0x0001 - - enum PowerConfigurationAttribute { - PowerConfigurationAttributeMainsInformation = 0x0000, - PowerConfigurationAttributeMainsSettings = 0x0001, - PowerConfigurationAttributeBatteryInformation = 0x0002, - PowerConfigurationAttributeBatterySettings = 0x0003, - PowerConfigurationAttributeBatterySource2Information = 0x0004, - PowerConfigurationAttributeBattterySource2Settings = 0x0005, - PowerConfigurationAttributeBatterySource3Information = 0x0006, - PowerConfigurationAttributeBattterySource3Settings = 0x0007 - }; - Q_ENUM(PowerConfigurationAttribute) - - // On Off Cluster 0x0006 - - enum OnOffClusterAttribute { - OnOffClusterAttributeOnOff = 0x0000, - OnOffClusterAttributeGlobalSceneControl = 0x4000, - OnOffClusterAttributeOnTime = 0x4001, - OnOffClusterAttributeOffWaitTime = 0x4002 - }; - Q_ENUM(OnOffClusterAttribute) - - enum OnOffClusterCommand { - OnOffClusterCommandOff = 0x00, - OnOffClusterCommandOn = 0x01, - OnOffClusterCommandToggle = 0x02 - }; - Q_ENUM(OnOffClusterCommand) - - - // Level cluster 0x0008 - - enum LevelClusterAttribute { - LevelClusterAttributeCurrentLevel = 0x0000, - LevelClusterAttributeRemainingTime = 0x0001, - LevelClusterAttributeOnOffTransitionTime = 0x0010, - LevelClusterAttributeOnLevel = 0x0011, - LevelClusterAttributeOnTransitionTime = 0x0012, - LevelClusterAttributeOffTransitionTime = 0x0013, - LevelClusterAttributeDefaultMoveRate = 0x0014 - }; - Q_ENUM(LevelClusterAttribute) - - enum LevelClusterCommand { - LevelClusterCommandMoveToLevel = 0x00, - LevelClusterCommandMove = 0x01, - LevelClusterCommandStep = 0x02, - LevelClusterCommandStop = 0x03, - LevelClusterCommandMoveToLevelWithOnOff = 0x04, - LevelClusterCommandMoveWithOnOff = 0x05, - LevelClusterCommandStepWithOnOff = 0x06, - LevelClusterCommandStopWithOnOff = 0x07, - }; - Q_ENUM(LevelClusterCommand) - - // Color cluster 0x0300 - - enum ColorControlClusterAttribute { - ColorControlClusterAttributeCurrentHue = 0x0000, - ColorControlClusterAttributeCurrentSaturation = 0x0001, - ColorControlClusterAttributeRemainingTime = 0x0002, - ColorControlClusterAttributeCurrentX = 0x0003, - ColorControlClusterAttributeCurrentY = 0x0004, - ColorControlClusterAttributeDriftCompensation = 0x0005, - ColorControlClusterAttributeCompensationText = 0x0006, - ColorControlClusterAttributeColorTemperatureMireds = 0x0007, - ColorControlClusterAttributeColorMode = 0x0008, - ColorControlClusterAttributeEnhancedCurrentHue = 0x4000, - ColorControlClusterAttributeEnhancedColorMode = 0x4001, - ColorControlClusterAttributeColorLoopActive = 0x4002, - ColorControlClusterAttributeColorLoopDirection = 0x4003, - ColorControlClusterAttributeColorLoopTime = 0x4004, - ColorControlClusterAttributeColorLoopStartEnhancedHue = 0x4005, - ColorControlClusterAttributeColorLoopStoredEnhancedHue = 0x4006, - ColorControlClusterAttributeColorCapabilities = 0x400a, - ColorControlClusterAttributeColorTempPhysicalMinMireds = 0x400b, - ColorControlClusterAttributeColorTempPhysicalMaxMireds = 0x400c - }; - Q_ENUM(ColorControlClusterAttribute) - - enum ColorControlClusterColorMode { - ColorControlClusterColorModeHueSaturation = 0x00, - ColorControlClusterColorModeXY = 0x01, - ColorControlClusterColorModeColorTemperatureMired = 0x02 - }; - Q_ENUM(ColorControlClusterColorMode) - - - explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent = nullptr); - - Direction direction() const; - - Zigbee::ClusterId clusterId() const; - QString clusterName() const; - - QList attributes() const; - bool hasAttribute(quint16 attributeId) const; - - ZigbeeClusterAttribute attribute(quint16 id); - - // FIXME: this should not be public - void setAttribute(const ZigbeeClusterAttribute &attribute); - - // ZCL global commands - ZigbeeNetworkReply *readAttributes(QList attributes); - -protected: - ZigbeeNetwork *m_network = nullptr; - ZigbeeNode *m_node = nullptr; - ZigbeeNodeEndpoint *m_endpoint= nullptr; - - Zigbee::ClusterId m_clusterId = Zigbee::ClusterIdUnknown; - Direction m_direction = Input; - QHash m_attributes; - -signals: - void attributeChanged(const ZigbeeClusterAttribute &attribute); - -}; - -QDebug operator<<(QDebug debug, ZigbeeCluster *cluster); -QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeReport); - -#endif // ZIGBEECLUSTER_H diff --git a/libnymea-zigbee/zigbeeclusterlibraryreply.cpp b/libnymea-zigbee/zigbeeclusterlibraryreply.cpp deleted file mode 100644 index e2fbdf6..0000000 --- a/libnymea-zigbee/zigbeeclusterlibraryreply.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "zigbeeclusterlibraryreply.h" - -ZigbeeNetworkRequest ZigbeeClusterLibraryReply::request() const -{ - return m_request; -} - -ZigbeeClusterLibrary::Frame ZigbeeClusterLibraryReply::requestFrame() const -{ - return m_requestFrame; -} - -quint8 ZigbeeClusterLibraryReply::transactionSequenceNumber() const -{ - return m_requestFrame.header.transactionSequenceNumber; -} - -ZigbeeClusterLibraryReply::ZigbeeClusterLibraryReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent) : - QObject(parent), - m_request(request), - m_requestFrame(requestFrame) -{ - -} diff --git a/libnymea-zigbee/zigbeeclusterlibraryreply.h b/libnymea-zigbee/zigbeeclusterlibraryreply.h deleted file mode 100644 index cbbac7c..0000000 --- a/libnymea-zigbee/zigbeeclusterlibraryreply.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ZIGBEECLUSTERLIBRARYREPLY_H -#define ZIGBEECLUSTERLIBRARYREPLY_H - -#include - -#include "zigbeenetworkrequest.h" -#include "zigbeeclusterlibrary.h" - -class ZigbeeClusterLibraryReply : public QObject -{ - Q_OBJECT - - friend class ZigbeeCluster; - -public: - ZigbeeNetworkRequest request() const; - ZigbeeClusterLibrary::Frame requestFrame() const; - - quint8 transactionSequenceNumber() const; - -private: - explicit ZigbeeClusterLibraryReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent = nullptr); - - ZigbeeNetworkRequest m_request; - ZigbeeClusterLibrary::Frame m_requestFrame; - ZigbeeClusterLibrary::Command m_expectedResponse; - - ZigbeeClusterLibrary::Frame m_responseFrame; - -signals: - void finished(); - -}; - -#endif // ZIGBEECLUSTERLIBRARYREPLY_H diff --git a/libnymea-zigbee/zigbeedatatype.cpp b/libnymea-zigbee/zigbeedatatype.cpp new file mode 100644 index 0000000..d161aee --- /dev/null +++ b/libnymea-zigbee/zigbeedatatype.cpp @@ -0,0 +1,480 @@ +#include "zigbeedatatype.h" + +ZigbeeDataType::ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data): + m_dataType(dataType), + m_data(data) +{ + switch (dataType) { + case Zigbee::NoData: + m_name = "No data"; + m_className = "Null"; + m_typeLength = typeLength(m_dataType); + m_data.clear(); + break; + case Zigbee::Data8: + m_name = "8-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data16: + m_name = "16-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data24: + m_name = "24-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data32: + m_name = "32-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data40: + m_name = "40-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data48: + m_name = "48-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data56: + m_name = "56-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Data64: + m_name = "64-bit data"; + m_className = "General data discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Bool: + m_name = "Bool"; + m_className = "Logical discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap8: + m_name = "8-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap16: + m_name = "16-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap24: + m_name = "24-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap32: + m_name = "32-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap40: + m_name = "40-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap48: + m_name = "48-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap56: + m_name = "56-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::BitMap64: + m_name = "64-bit bitmap"; + m_className = "Bitmap discrete"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Uint8: + m_name = "Unsigned 8-bit integer"; + m_className = "Unsigned integer analog"; + m_typeLength = typeLength(m_dataType); + break; + case Zigbee::Uint16: + break; + case Zigbee::Uint24: + break; + case Zigbee::Uint32: + break; + case Zigbee::Uint40: + break; + case Zigbee::Uint48: + break; + case Zigbee::Uint56: + break; + case Zigbee::Uint64: + break; + case Zigbee::Int8: + break; + case Zigbee::Int16: + break; + case Zigbee::Int24: + break; + case Zigbee::Int32: + break; + case Zigbee::Int40: + break; + case Zigbee::Int48: + break; + case Zigbee::Int56: + break; + case Zigbee::Int64: + break; + case Zigbee::Enum8: + break; + case Zigbee::Enum16: + break; + case Zigbee::FloatSemi: + break; + case Zigbee::FloatSingle: + break; + case Zigbee::FloatDouble: + break; + case Zigbee::OctetString: + break; + case Zigbee::CharString: + break; + case Zigbee::LongOctetString: + break; + case Zigbee::LongCharString: + break; + case Zigbee::Array: + break; + case Zigbee::Structure: + break; + case Zigbee::Set: + break; + case Zigbee::Bag: + break; + case Zigbee::TimeOfDay: + break; + case Zigbee::Date: + break; + case Zigbee::UtcTime: + break; + case Zigbee::Cluster: + break; + case Zigbee::Attribute: + break; + case Zigbee::BacnetId: + break; + case Zigbee::IeeeAddress: + break; + case Zigbee::BitKey128: + break; + case Zigbee::Unknown: + break; + } + + /* + switch (dataType) { + case Zigbee::NoData: + break; + case Zigbee::Data8: + break; + case Zigbee::Data16: + break; + case Zigbee::Data24: + break; + case Zigbee::Data32: + break; + case Zigbee::Data40: + break; + case Zigbee::Data48: + break; + case Zigbee::Data56: + break; + case Zigbee::Data64: + break; + case Zigbee::Bool: + break; + case Zigbee::BitMap8: + break; + case Zigbee::BitMap16: + break; + case Zigbee::BitMap24: + break; + case Zigbee::BitMap32: + break; + case Zigbee::BitMap40: + break; + case Zigbee::BitMap48: + break; + case Zigbee::BitMap56: + break; + case Zigbee::BitMap64: + break; + case Zigbee::Uint8: + break; + case Zigbee::Uint16: + break; + case Zigbee::Uint24: + break; + case Zigbee::Uint32: + break; + case Zigbee::Uint40: + break; + case Zigbee::Uint48: + break; + case Zigbee::Uint56: + break; + case Zigbee::Uint64: + break; + case Zigbee::Int8: + break; + case Zigbee::Int16: + break; + case Zigbee::Int24: + break; + case Zigbee::Int32: + break; + case Zigbee::Int40: + break; + case Zigbee::Int48: + break; + case Zigbee::Int56: + break; + case Zigbee::Int64: + break; + case Zigbee::Enum8: + break; + case Zigbee::Enum16: + break; + case Zigbee::FloatSemi: + break; + case Zigbee::FloatSingle: + break; + case Zigbee::FloatDouble: + break; + case Zigbee::OctetString: + break; + case Zigbee::CharString: + break; + case Zigbee::LongOctetString: + break; + case Zigbee::LongCharString: + break; + case Zigbee::Array: + break; + case Zigbee::Structure: + break; + case Zigbee::Set: + break; + case Zigbee::Bag: + break; + case Zigbee::TimeOfDay: + break; + case Zigbee::Date: + break; + case Zigbee::UtcTime: + break; + case Zigbee::Cluster: + break; + case Zigbee::Attribute: + break; + case Zigbee::BacnetId: + break; + case Zigbee::IeeeAddress: + break; + case Zigbee::BitKey128: + break; + case Zigbee::Unknown: + break; + } + */ + +} + +int ZigbeeDataType::typeLength(Zigbee::DataType dataType) +{ + int length = 0; + switch (dataType) { + case Zigbee::NoData: + break; + case Zigbee::Data8: + length = 1; + break; + case Zigbee::Data16: + length = 2; + break; + case Zigbee::Data24: + length = 3; + break; + case Zigbee::Data32: + length = 4; + break; + case Zigbee::Data40: + length = 5; + break; + case Zigbee::Data48: + length = 6; + break; + case Zigbee::Data56: + length = 7; + break; + case Zigbee::Data64: + length = 8; + break; + case Zigbee::Bool: + length = 1; + break; + case Zigbee::BitMap8: + length = 1; + break; + case Zigbee::BitMap16: + length = 2; + break; + case Zigbee::BitMap24: + length = 3; + break; + case Zigbee::BitMap32: + length = 4; + break; + case Zigbee::BitMap40: + length = 5; + break; + case Zigbee::BitMap48: + length = 6; + break; + case Zigbee::BitMap56: + length = 7; + break; + case Zigbee::BitMap64: + length = 8; + break; + case Zigbee::Uint8: + length = 1; + break; + case Zigbee::Uint16: + length = 2; + break; + case Zigbee::Uint24: + length = 3; + break; + case Zigbee::Uint32: + length = 4; + break; + case Zigbee::Uint40: + length = 5; + break; + case Zigbee::Uint48: + length = 6; + break; + case Zigbee::Uint56: + length = 7; + break; + case Zigbee::Uint64: + length = 8; + break; + case Zigbee::Int8: + length = 1; + break; + case Zigbee::Int16: + length = 2; + break; + case Zigbee::Int24: + length = 3; + break; + case Zigbee::Int32: + length = 4; + break; + case Zigbee::Int40: + length = 5; + break; + case Zigbee::Int48: + length = 6; + break; + case Zigbee::Int56: + length = 7; + break; + case Zigbee::Int64: + length = 8; + break; + case Zigbee::Enum8: + length = 1; + break; + case Zigbee::Enum16: + length = 2; + break; + case Zigbee::FloatSemi: + length = 2; + break; + case Zigbee::FloatSingle: + length = 4; + break; + case Zigbee::FloatDouble: + length = 8; + break; + case Zigbee::OctetString: + // first byte is length + length = -1; + break; + case Zigbee::CharString: + // first byte is length + length = -1; + break; + case Zigbee::LongOctetString: + // first 2 byte is length + length = -1; + break; + case Zigbee::LongCharString: + // first 2 byte is length + length = -1; + break; + case Zigbee::Array: + // 2 + sum of lengths of content + length = -1; + break; + case Zigbee::Structure: + // 2 + sum of lengths of content + length = -1; + break; + case Zigbee::Set: + // 2 + sum of lengths of content + length = -1; + break; + case Zigbee::Bag: + // 2 + sum of lengths of content + length = -1; + break; + case Zigbee::TimeOfDay: + length = 4; + break; + case Zigbee::Date: + length = 4; + break; + case Zigbee::UtcTime: + length = 4; + break; + case Zigbee::Cluster: + length = 2; + break; + case Zigbee::Attribute: + length = 2; + break; + case Zigbee::BacnetId: + length = 4; + break; + case Zigbee::IeeeAddress: + length = 8; + break; + case Zigbee::BitKey128: + length = 16; + break; + case Zigbee::Unknown: + break; + } + + return length; +} diff --git a/libnymea-zigbee/zigbeedatatype.h b/libnymea-zigbee/zigbeedatatype.h new file mode 100644 index 0000000..0724abe --- /dev/null +++ b/libnymea-zigbee/zigbeedatatype.h @@ -0,0 +1,26 @@ +#ifndef ZIGBEEDATATYPE_H +#define ZIGBEEDATATYPE_H + +#include "zigbee.h" + +class ZigbeeDataType +{ +public: + ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data = QByteArray()); + + Zigbee::DataType dataType() const; + QString name() const; + QString className() const; + QByteArray data() const; + + static int typeLength(Zigbee::DataType dataType); + +private: + Zigbee::DataType m_dataType = Zigbee::NoData; + QByteArray m_data; + QString m_name = "Unknown"; + QString m_className = "Null"; + int m_typeLength = 0; +}; + +#endif // ZIGBEEDATATYPE_H diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 2a307ab..0eb6d61 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -351,7 +351,7 @@ void ZigbeeNetwork::loadNetwork() for (int n = 0; n < inputClustersCount; n ++) { settings.setArrayIndex(n); Zigbee::ClusterId clusterId = static_cast(settings.value("clusterId", 0).toUInt()); - ZigbeeCluster *cluster = new ZigbeeCluster(this, node, endpoint, clusterId, ZigbeeCluster::Input, endpoint); + ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Input); //qCDebug(dcZigbeeNetwork()) << "Created" << cluster; endpoint->m_inputClusters.insert(clusterId, cluster); } @@ -361,7 +361,7 @@ void ZigbeeNetwork::loadNetwork() for (int n = 0; n < outputClustersCount; n ++) { settings.setArrayIndex(n); Zigbee::ClusterId clusterId = static_cast(settings.value("clusterId", 0).toUInt()); - ZigbeeCluster *cluster = new ZigbeeCluster(this, node, endpoint, clusterId, ZigbeeCluster::Output, endpoint); + ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Output); //qCDebug(dcZigbeeNetwork()) << "Created" << cluster; endpoint->m_outputClusters.insert(clusterId, cluster); } diff --git a/libnymea-zigbee/zigbeenetworkmanager.cpp b/libnymea-zigbee/zigbeenetworkmanager.cpp index 04d73c3..3de7077 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.cpp +++ b/libnymea-zigbee/zigbeenetworkmanager.cpp @@ -28,7 +28,7 @@ #include "zigbeenetworkmanager.h" #include "loggingcategory.h" -#include "deconz/zigbeenetworkdeconz.h" +#include "backends/deconz/zigbeenetworkdeconz.h" #include diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index c5a5f17..9aa15c4 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -257,91 +257,6 @@ void ZigbeeNode::setExtendedAddress(const ZigbeeAddress &extendedAddress) m_extendedAddress = extendedAddress; } -//void ZigbeeNode::setNodeDescriptorRawData(const QByteArray nodeDescriptorRawData) -//{ -// m_nodeDescriptorRawData = nodeDescriptorRawData; - -// // Parse the raw data -// quint8 sequenceNumber = 0; -// quint8 status = 0; -// quint16 shortAddress = 0; -// quint16 manufacturerCode = 0; -// quint16 maximalRxSize = 0; -// quint16 maximalTxSize = 0; -// quint16 serverMask = 0; -// quint8 descriptorFlag = 0; -// quint8 macFlags = 0; -// quint8 maxBufferSize = 0; -// quint16 bitField = 0; - -// QDataStream stream(&m_nodeDescriptorRawData, QIODevice::ReadOnly); -// stream >> sequenceNumber; -// stream >> status; -// stream >> shortAddress; -// stream >> manufacturerCode; -// stream >> maximalRxSize; -// stream >> maximalTxSize; -// stream >> serverMask; -// stream >> descriptorFlag; -// stream >> macFlags; -// stream >> maxBufferSize; -// stream >> bitField; - -// // Set node data -// m_manufacturerCode = manufacturerCode; -// m_maximumRxSize = maximalRxSize; -// m_maximumTxSize = maximalTxSize; -// m_maximumBufferSize = maxBufferSize; - -// setServerMask(serverMask); -// setMacCapabilitiesFlag(macFlags); -// setDescriptorFlag(descriptorFlag); - -// // Parse bit field -// // 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device -// if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { -// m_nodeType = NodeTypeCoordinator; -// } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) { -// m_nodeType = NodeTypeRouter; -// } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { -// m_nodeType = NodeTypeEndDevice; -// } - -// m_complexDescriptorAvailable = (bitField >> 3) & 0x0001; -// m_userDescriptorAvailable = (bitField >> 4) & 0x0001; - -// qCDebug(dcZigbeeNode()) << "Node descriptor:"; -// qCDebug(dcZigbeeNode()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); -// qCDebug(dcZigbeeNode()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); -// qCDebug(dcZigbeeNode()) << " Node type:" << nodeType(); -// qCDebug(dcZigbeeNode()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); -// qCDebug(dcZigbeeNode()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode); -// qCDebug(dcZigbeeNode()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximumRxSize()); -// qCDebug(dcZigbeeNode()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(maximumTxSize()); -// qCDebug(dcZigbeeNode()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maximumBufferSize()); -// qCDebug(dcZigbeeNode()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask); -// qCDebug(dcZigbeeNode()) << " Primary Trust center:" << isPrimaryTrustCenter(); -// qCDebug(dcZigbeeNode()) << " Backup Trust center:" << isBackupTrustCenter(); -// qCDebug(dcZigbeeNode()) << " Primary Binding cache:" << isPrimaryBindingCache(); -// qCDebug(dcZigbeeNode()) << " Backup Binding cache:" << isBackupBindingCache(); -// qCDebug(dcZigbeeNode()) << " Primary Discovery cache:" << isPrimaryDiscoveryCache(); -// qCDebug(dcZigbeeNode()) << " Backup Discovery cache:" << isBackupDiscoveryCache(); -// qCDebug(dcZigbeeNode()) << " Network Manager:" << isNetworkManager(); -// qCDebug(dcZigbeeNode()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag); -// qCDebug(dcZigbeeNode()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable(); -// qCDebug(dcZigbeeNode()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable(); -// qCDebug(dcZigbeeNode()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags); -// qCDebug(dcZigbeeNode()) << " Alternate PAN coordinator:" << alternatePanCoordinator(); -// qCDebug(dcZigbeeNode()) << " Device type:" << deviceType(); -// qCDebug(dcZigbeeNode()) << " Power source flag main power:" << powerSourceFlagMainPower(); -// qCDebug(dcZigbeeNode()) << " Receiver on when idle:" << receiverOnWhenIdle(); -// qCDebug(dcZigbeeNode()) << " Security capability:" << securityCapability(); -// qCDebug(dcZigbeeNode()) << " Allocate address:" << allocateAddress(); -// qCDebug(dcZigbeeNode()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField); -// qCDebug(dcZigbeeNode()) << " Complex desciptor available:" << complexDescriptorAvailable(); -// qCDebug(dcZigbeeNode()) << " User desciptor available:" << userDescriptorAvailable(); -//} - quint16 ZigbeeNode::serverMask() const { return m_serverMask; @@ -704,11 +619,11 @@ void ZigbeeNode::initEndpoint(quint8 endpointId) quint16 clusterId = 0; stream >> clusterId; if (!endpoint->hasInputCluster(static_cast(clusterId))) { - endpoint->addInputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Input, endpoint)); + endpoint->addInputCluster(endpoint->createCluster(static_cast(clusterId), ZigbeeCluster::Input)); } qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); - } + stream >> outputClusterCount; qCDebug(dcZigbeeNode()) << " Output clusters: (" << outputClusterCount << ")"; @@ -716,7 +631,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId) quint16 clusterId = 0; stream >> clusterId; if (!endpoint->hasOutputCluster(static_cast(clusterId))) { - endpoint->addOutputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Output, endpoint)); + endpoint->addOutputCluster(endpoint->createCluster(static_cast(clusterId), ZigbeeCluster::Output)); } qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); } @@ -725,19 +640,81 @@ void ZigbeeNode::initEndpoint(quint8 endpointId) if (m_uninitializedEndpoints.isEmpty()) { - //if (m_shortAddress == 0) { - setState(StateInitialized); - return; - //} + if (m_shortAddress == 0) { + setState(StateInitialized); + return; + } // Continue with the basic cluster attributes - //initBasicCluster(); + initBasicCluster(); } }); } void ZigbeeNode::initBasicCluster() { + ZigbeeClusterBasic *basicCluster = m_endpoints.first()->inputCluster(Zigbee::ClusterIdBasic); + + if (!basicCluster) { + qCWarning(dcZigbeeNode()) << this << "could not find basic server cluster"; + setState(StateInitialized); + return; + } + + ZigbeeClusterBasic::Attribute attributeId = ZigbeeClusterBasic::AttributeManufacturerName; + qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId; + ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast(attributeId)}); + connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); + } else { + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); + m_endpoints.first()->m_manufacturerName = QString::fromUtf8(attributeStatusRecords.first().data); + } + } + + ZigbeeClusterBasic::Attribute attributeId = ZigbeeClusterBasic::AttributeModelIdentifier; + qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId; + ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast(attributeId)}); + connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); + } else { + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); + m_endpoints.first()->m_modelIdentifier = QString::fromUtf8(attributeStatusRecords.first().data); + } + } + + + ZigbeeClusterBasic::Attribute attributeId = ZigbeeClusterBasic::AttributeSwBuildId; + qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId; + ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast(attributeId)}); + connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); + } else { + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); + m_endpoints.first()->m_softwareBuildId = QString::fromUtf8(attributeStatusRecords.first().data); + } + } + + // Finished with reading basic cluster, the node is initialized. TODO: read other cluster information + setState(StateInitialized); + }); + }); + }); } @@ -748,41 +725,6 @@ void ZigbeeNode::onClusterAttributeChanged(const ZigbeeClusterAttribute &attribu emit clusterAttributeChanged(cluster, attribute); } -//void ZigbeeNode::onRequestUserDescriptorFinished() -//{ -// ZigbeeInterfaceReply *reply = static_cast(sender()); -// reply->deleteLater(); - -// if (reply->status() != ZigbeeInterfaceReply::Success) { -// qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); -// return; -// } - -// qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; -// qCDebug(dcZigbeeController()) << reply->additionalMessage(); - -// quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); -// quint8 status = static_cast(reply->additionalMessage().data().at(1)); - -// quint16 nwkAddress = static_cast(reply->additionalMessage().data().at(2)); -// nwkAddress <<= 8; -// nwkAddress |= reply->additionalMessage().data().at(3); - -// quint8 length = static_cast(reply->additionalMessage().data().at(4)); - -// QByteArray data; -// if (length > 0) { -// data = reply->additionalMessage().data().mid(5, length); -// } - -// qCDebug(dcZigbeeNode()) << "User descriptor:"; -// qCDebug(dcZigbeeNode()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); -// qCDebug(dcZigbeeNode()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); -// qCDebug(dcZigbeeNode()) << " Attribute address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); -// qCDebug(dcZigbeeNode()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); -// qCDebug(dcZigbeeNode()) << " Data:" << data; -//} - QDebug operator<<(QDebug debug, ZigbeeNode *node) { debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()); diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 3b8c932..9702df2 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -284,7 +284,6 @@ private: QList m_uninitializedEndpoints; QList m_uninitalizedBasicClusterAttributes; - signals: void stateChanged(State state); void connectedChanged(bool connected); diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index 1cdb72c..e6e3994 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -30,6 +30,8 @@ #include "zigbeenode.h" #include "loggingcategory.h" +#include "zcl/general/zigbeeclusterbasic.h" + quint8 ZigbeeNodeEndpoint::endpointId() const { return m_endpointId; @@ -146,6 +148,17 @@ void ZigbeeNodeEndpoint::setSoftwareBuildId(const QString &softwareBuildId) emit softwareBuildIdChanged(m_softwareBuildId); } +ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction) +{ + switch (clusterId) { + case Zigbee::ClusterIdBasic: + return new ZigbeeClusterBasic(m_network, m_node, this, direction, this); + break; + default: + return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this); + } +} + void ZigbeeNodeEndpoint::addInputCluster(ZigbeeCluster *cluster) { m_inputClusters.insert(cluster->clusterId(), cluster); @@ -156,21 +169,6 @@ void ZigbeeNodeEndpoint::addOutputCluster(ZigbeeCluster *cluster) m_outputClusters.insert(cluster->clusterId(), cluster); } -ZigbeeNetworkReply *ZigbeeNodeEndpoint::createNetworkReply(const ZigbeeNetworkRequest &request) -{ - ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this); - // Make sure the reply will be deleted - connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater); - return reply; -} - -void ZigbeeNodeEndpoint::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeApsStatus zigbeeApsStatus) -{ - reply->m_error = error; - reply->m_zigbeeApsStatus = zigbeeApsStatus; - reply->finished(); -} - ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const { return m_outputClusters.value(clusterId); diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index 32b86b1..52fef6a 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -32,9 +32,11 @@ #include "zigbee.h" #include "zigbeeaddress.h" -#include "zigbeecluster.h" #include "zigbeenetworkreply.h" +#include "zcl/zigbeecluster.h" +#include "zcl/general/zigbeeclusterbasic.h" + class ZigbeeNode; class ZigbeeNetwork; @@ -74,6 +76,24 @@ public: ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const; bool hasOutputCluster(Zigbee::ClusterId clusterId) const; + template + inline T* inputCluster(Zigbee::ClusterId clusterId) + { + if (!hasInputCluster(clusterId)) + return nullptr; + + return qobject_cast(getInputCluster(clusterId)); + } + + template + inline T* outputCluster(Zigbee::ClusterId clusterId) + { + if (!hasOutputCluster(clusterId)) + return nullptr; + + return qobject_cast(getOutputCluster(clusterId)); + } + private: explicit ZigbeeNodeEndpoint(ZigbeeNetwork *network, ZigbeeNode *node, quint8 endpointId, QObject *parent = nullptr); @@ -84,7 +104,6 @@ private: quint16 m_deviceId = 0; quint8 m_deviceVersion = 0; - QHash m_inputClusters; QHash m_outputClusters; @@ -99,15 +118,14 @@ private: // Cluster commands //virtual void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute()) = 0; + ZigbeeCluster *createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction); + void addInputCluster(ZigbeeCluster *cluster); void addOutputCluster(ZigbeeCluster *cluster); - // Network reply methods - ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); - void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess); - signals: void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute); + void manufacturerNameChanged(const QString &manufacturerName); void modelIdentifierChanged(const QString &modelIdentifier); void softwareBuildIdChanged(const QString &softwareBuildId); diff --git a/libnymea-zigbee/zigbeeutils.cpp b/libnymea-zigbee/zigbeeutils.cpp index 0d9e293..7837a11 100644 --- a/libnymea-zigbee/zigbeeutils.cpp +++ b/libnymea-zigbee/zigbeeutils.cpp @@ -276,8 +276,11 @@ QString ZigbeeUtils::clusterIdToString(const Zigbee::ClusterId &clusterId) QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ClusterId")); QString enumString = metaEnum.valueToKey(clusterId); + QString clusterName = enumString.remove("Zigbee::ClusterId(ClusterId").remove(")").append(QString("(%1)").arg(ZigbeeUtils::convertUint16ToHexString(clusterId))); + if (clusterName.isEmpty()) + clusterName = "Unknown"; - return enumString.remove("Zigbee::ClusterId(ClusterId").remove(")").append(QString("(%1)").arg(ZigbeeUtils::convertUint16ToHexString(clusterId))); + return clusterName; } QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId) diff --git a/libnymea-zigbee/zigbeeutils.h b/libnymea-zigbee/zigbeeutils.h index 5b91126..2dfbf9d 100644 --- a/libnymea-zigbee/zigbeeutils.h +++ b/libnymea-zigbee/zigbeeutils.h @@ -36,7 +36,7 @@ #include #include "zigbee.h" -#include "zigbeecluster.h" +#include "zcl/zigbeecluster.h" class ZigbeeUtils