diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp index 50e428b..cb18849 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp @@ -250,7 +250,7 @@ bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate) connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError))); if (!m_serialPort->open(QSerialPort::ReadWrite)) { - qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort << baudrate; + qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort << baudrate << m_serialPort->errorString(); m_reconnectTimer->start(); return false; } diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 44c5cbc..a760db5 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -8,6 +8,7 @@ SOURCES += \ backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \ backends/deconz/zigbeebridgecontrollerdeconz.cpp \ backends/deconz/zigbeenetworkdeconz.cpp \ + zcl/general/zigbeeclusteronoff.cpp \ zcl/zigbeecluster.cpp \ zcl/zigbeeclusterattribute.cpp \ zcl/zigbeeclusterlibrary.cpp \ @@ -49,6 +50,7 @@ HEADERS += \ backends/deconz/interface/zigbeeinterfacedeconzreply.h \ backends/deconz/zigbeebridgecontrollerdeconz.h \ backends/deconz/zigbeenetworkdeconz.h \ + zcl/general/zigbeeclusteronoff.h \ zcl/zigbeecluster.h \ zcl/zigbeeclusterattribute.h \ zcl/zigbeeclusterlibrary.h \ diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp index 8eee12c..4dc59af 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.cpp @@ -1,3 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "zigbeeclusterbasic.h" #include "loggingcategory.h" @@ -10,11 +37,11 @@ ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, void ZigbeeClusterBasic::setAttribute(const ZigbeeClusterAttribute &attribute) { if (hasAttribute(attribute.id())) { - qCDebug(dcZigbeeCluster()) << this << "update attribute" << static_cast(attribute.id()) << attribute.dataType() << attribute.data(); + qCDebug(dcZigbeeCluster()) << "Update attribute" << this << static_cast(attribute.id()) << attribute.dataType(); m_attributes[attribute.id()] = attribute; emit attributeChanged(attribute); } else { - qCDebug(dcZigbeeCluster()) << this << "add attribute" << static_cast(attribute.id()) << attribute.dataType() << attribute.data(); + qCDebug(dcZigbeeCluster()) << "Add attribute" << this << static_cast(attribute.id()) << attribute.dataType(); m_attributes.insert(attribute.id(), attribute); emit attributeChanged(attribute); } diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h index 777a1ea..270244b 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterbasic.h @@ -1,3 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEECLUSTERBASIC_H #define ZIGBEECLUSTERBASIC_H @@ -172,13 +199,9 @@ public: explicit ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); - - private: void setAttribute(const ZigbeeClusterAttribute &attribute) override; -signals: - }; Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterBasic::AlarmMasks) diff --git a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp new file mode 100644 index 0000000..33a0bf9 --- /dev/null +++ b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp @@ -0,0 +1,159 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeeclusteronoff.h" +#include "zigbeenetworkreply.h" +#include "loggingcategory.h" +#include "zigbeenetwork.h" + +#include + +ZigbeeClusterOnOff::ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : + ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdOnOff, direction, parent) +{ + +} + +ZigbeeClusterReply *ZigbeeClusterOnOff::commandOff() +{ + 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::FrameTypeClusterSpecific; + frameControl.manufacturerSpecific = false; + frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer; + frameControl.disableDefaultResponse = false; + + // ZCL header + ZigbeeClusterLibrary::Header header; + header.frameControl = frameControl; + header.command = ZigbeeClusterOnOff::CommandOff; + header.transactionSequenceNumber = m_transactionSequenceNumber++; + + // there is no ZCL payload + + // Put them together + ZigbeeClusterLibrary::Frame frame; + frame.header = header; + + request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission)); + request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame)); + + 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 *ZigbeeClusterOnOff::commandOn() +{ + 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::FrameTypeClusterSpecific; + frameControl.manufacturerSpecific = false; + frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer; + frameControl.disableDefaultResponse = false; + + // ZCL header + ZigbeeClusterLibrary::Header header; + header.frameControl = frameControl; + header.command = ZigbeeClusterOnOff::CommandOn; + header.transactionSequenceNumber = m_transactionSequenceNumber++; + + // There is no ZCL payload + + // Put them together + ZigbeeClusterLibrary::Frame frame; + frame.header = header; + + request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission)); + request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame)); + + 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; +} + +void ZigbeeClusterOnOff::setAttribute(const ZigbeeClusterAttribute &attribute) +{ + if (hasAttribute(attribute.id())) { + qCDebug(dcZigbeeCluster()) << "Update attribute" << this << static_cast(attribute.id()) << attribute.dataType(); + m_attributes[attribute.id()] = attribute; + emit attributeChanged(attribute); + } else { + qCDebug(dcZigbeeCluster()) << "Add attribute" << this << static_cast(attribute.id()) << attribute.dataType(); + m_attributes.insert(attribute.id(), attribute); + emit attributeChanged(attribute); + } +} + +void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame) +{ + // Increase the tsn for continuouse id increasing on both sides + m_transactionSequenceNumber = frame.header.transactionSequenceNumber; + qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; +} diff --git a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h new file mode 100644 index 0000000..4bb571c --- /dev/null +++ b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h @@ -0,0 +1,87 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEECLUSTERONOFF_H +#define ZIGBEECLUSTERONOFF_H + +#include + +#include "zcl/zigbeecluster.h" +#include "zcl/zigbeeclusterreply.h" + +class ZigbeeNode; +class ZigbeeNetwork; +class ZigbeeNodeEndpoint; +class ZigbeeNetworkReply; + +class ZigbeeClusterOnOff : public ZigbeeCluster +{ + Q_OBJECT + + friend class ZigbeeNode; + friend class ZigbeeNetwork; + +public: + enum Attribute { + AttributeOnOff = 0x0000, + AttributeGlobalSceneControl = 0x4000, + AttributeOnTime = 0x4001, + AttributeOffTime = 0x4002 + }; + Q_ENUM(Attribute) + + enum Command { + CommandOff = 0x00, + CommandOn = 0x01, + CommandToggle = 0x02, + CommandOffWithEffect = 0x40, + CommandOnWithRecallGlobalScene = 0x41, + CommandOnWithTimedOff = 0x42 + }; + Q_ENUM(Command) + + explicit ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); + + ZigbeeClusterReply *commandOff(); + ZigbeeClusterReply *commandOn(); +// ZigbeeClusterReply *commandToggle(); +// ZigbeeClusterReply *commandOffWithEffect(); +// ZigbeeClusterReply *commandOnWithRecallGlobalScene(); +// ZigbeeClusterReply *commandOnWithTimedOff(); + +private: + void setAttribute(const ZigbeeClusterAttribute &attribute) override; + +protected: + void processDataIndication(ZigbeeClusterLibrary::Frame frame) override; + + +signals: + +}; + +#endif // ZIGBEECLUSTERONOFF_H diff --git a/libnymea-zigbee/zcl/zigbeecluster.cpp b/libnymea-zigbee/zcl/zigbeecluster.cpp index 29ff6fc..09f48a0 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.cpp +++ b/libnymea-zigbee/zcl/zigbeecluster.cpp @@ -82,11 +82,11 @@ ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 attributeId) void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute) { if (hasAttribute(attribute.id())) { - qCDebug(dcZigbeeCluster()) << this << "update attribute" << attribute; + qCDebug(dcZigbeeCluster()) << "Update attribute" << this << attribute; m_attributes[attribute.id()] = attribute; emit attributeChanged(attribute); } else { - qCDebug(dcZigbeeCluster()) << this << "add attribute" << attribute; + qCDebug(dcZigbeeCluster()) << "Add attribute" << this << attribute; m_attributes.insert(attribute.id(), attribute); emit attributeChanged(attribute); } @@ -94,7 +94,7 @@ void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute) ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList attributes) { - qCDebug(dcZigbeeClusterLibrary()) << "Read attributes from" << m_node << m_endpoint << this << attributes; + qCDebug(dcZigbeeCluster()) << "Read attributes from" << m_node << m_endpoint << this << attributes; // Build the request ZigbeeNetworkRequest request = createGeneralRequest(); @@ -139,7 +139,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList attributes) connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ if (!verifyNetworkError(zclReply, networkReply)) { qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request" - << m_node << networkReply->error() + << m_node << m_endpoint << this << networkReply->error() << networkReply->zigbeeApsStatus(); finishZclReply(zclReply); return; @@ -211,14 +211,23 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply) { m_pendingReplies.remove(zclReply->transactionSequenceNumber()); + qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame(); zclReply->finished(); } +void ZigbeeCluster::processDataIndication(ZigbeeClusterLibrary::Frame frame) +{ + // Increase the tsn for continuouse id increasing on both sides + m_transactionSequenceNumber = frame.header.transactionSequenceNumber; + qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; +} + void ZigbeeCluster::processApsDataIndication(QByteArray payload) { ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(payload); - qCDebug(dcZigbeeClusterLibrary()) << this << "received data indication" << frame; + qCDebug(dcZigbeeCluster()) << "Received data indication" << this << frame; + // Check if this indication is for a pending reply if (m_pendingReplies.contains(frame.header.transactionSequenceNumber)) { ZigbeeClusterReply *reply = m_pendingReplies.value(frame.header.transactionSequenceNumber); reply->m_responseData = payload; @@ -231,8 +240,8 @@ void ZigbeeCluster::processApsDataIndication(QByteArray payload) return; } - // FIXME: increase transaction sequence number - qCWarning(dcZigbeeNode()) << m_node << m_endpoint << this << "Unhandled ZCL indication" << ZigbeeUtils::convertByteArrayToHexString(payload); + // Not for a reply, process the indication + processDataIndication(frame); } QDebug operator<<(QDebug debug, ZigbeeCluster *cluster) @@ -252,7 +261,7 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeRep << attributeReport.attributeId << ", " << attributeReport.attributeStatus << ", " << attributeReport.dataType << ", " - << attributeReport.data << ", " + << ZigbeeUtils::convertByteArrayToHexString(attributeReport.data) << ")"; return debug.space(); diff --git a/libnymea-zigbee/zcl/zigbeecluster.h b/libnymea-zigbee/zcl/zigbeecluster.h index af16c2d..bf59bdb 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.h +++ b/libnymea-zigbee/zcl/zigbeecluster.h @@ -89,23 +89,6 @@ public: // }; // 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 @@ -195,6 +178,8 @@ protected: bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply); void finishZclReply(ZigbeeClusterReply *zclReply); + virtual void processDataIndication(ZigbeeClusterLibrary::Frame frame); + private: virtual void setAttribute(const ZigbeeClusterAttribute &attribute); @@ -204,7 +189,6 @@ signals: public slots: void processApsDataIndication(QByteArray payload); - }; QDebug operator<<(QDebug debug, ZigbeeCluster *cluster); diff --git a/libnymea-zigbee/zcl/zigbeeclusterattribute.cpp b/libnymea-zigbee/zcl/zigbeeclusterattribute.cpp index 9a8bb1d..2ae659b 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterattribute.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterattribute.cpp @@ -33,10 +33,9 @@ ZigbeeClusterAttribute::ZigbeeClusterAttribute() } -ZigbeeClusterAttribute::ZigbeeClusterAttribute(quint16 id, Zigbee::DataType dataType, QByteArray data): +ZigbeeClusterAttribute::ZigbeeClusterAttribute(quint16 id, const ZigbeeDataType &dataType): m_id(id), - m_dataType(dataType), - m_data(data) + m_dataType(dataType) { } @@ -45,7 +44,6 @@ ZigbeeClusterAttribute::ZigbeeClusterAttribute(const ZigbeeClusterAttribute &oth { m_id = other.id(); m_dataType = other.dataType(); - m_data = other.data(); } quint16 ZigbeeClusterAttribute::id() const @@ -53,29 +51,21 @@ quint16 ZigbeeClusterAttribute::id() const return m_id; } -Zigbee::DataType ZigbeeClusterAttribute::dataType() const +ZigbeeDataType ZigbeeClusterAttribute::dataType() const { return m_dataType; } -QByteArray ZigbeeClusterAttribute::data() const -{ - return m_data; -} - ZigbeeClusterAttribute &ZigbeeClusterAttribute::operator=(const ZigbeeClusterAttribute &other) { m_id = other.id(); m_dataType = other.dataType(); - m_data = other.data(); return *this; } bool ZigbeeClusterAttribute::operator==(const ZigbeeClusterAttribute &other) const { - return m_id == other.id() && - m_dataType == other.dataType() && - m_data == other.data(); + return m_id == other.id() && m_dataType == other.dataType(); } bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) const @@ -85,16 +75,14 @@ bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) con bool ZigbeeClusterAttribute::isValid() const { - return m_id != 0 || - m_dataType != Zigbee::NoData || - !m_data.isNull(); + return m_id != 0xffff && m_dataType.isValid(); } QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute) { debug.nospace().noquote() << "ZigbeeClusterAttribute(" << ZigbeeUtils::convertUint16ToHexString(attribute.id()) << ", " - << attribute.dataType() << ", " - << ZigbeeUtils::convertByteArrayToHexString(attribute.data()) << ")"; + << attribute.dataType() + << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zcl/zigbeeclusterattribute.h b/libnymea-zigbee/zcl/zigbeeclusterattribute.h index 7ef4ce1..6e021e5 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterattribute.h +++ b/libnymea-zigbee/zcl/zigbeeclusterattribute.h @@ -31,17 +31,17 @@ #include #include "zigbee.h" +#include "zigbeedatatype.h" class ZigbeeClusterAttribute { public: ZigbeeClusterAttribute(); - ZigbeeClusterAttribute(quint16 id, Zigbee::DataType dataType, QByteArray data); + ZigbeeClusterAttribute(quint16 id, const ZigbeeDataType &dataType); ZigbeeClusterAttribute(const ZigbeeClusterAttribute &other); quint16 id() const; - Zigbee::DataType dataType() const; - QByteArray data() const; + ZigbeeDataType dataType() const; ZigbeeClusterAttribute &operator=(const ZigbeeClusterAttribute &other); bool operator==(const ZigbeeClusterAttribute &other) const; @@ -50,9 +50,8 @@ public: bool isValid() const; private: - quint16 m_id = 0; - Zigbee::DataType m_dataType = Zigbee::NoData; - QByteArray m_data; + quint16 m_id = 0xffff; + ZigbeeDataType m_dataType; }; QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute); diff --git a/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp index 807d73b..984ae86 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp @@ -104,13 +104,11 @@ QList ZigbeeClusterLibrary::par QDataStream stream(payload); stream.setByteOrder(QDataStream::LittleEndian); - quint16 attributeId; quint8 statusInt; quint8 dataTypeInt; quint16 numberOfElenemts; quint8 elementType; - QByteArray data; + quint16 attributeId; quint8 statusInt; quint8 dataTypeInt; while (!stream.atEnd()) { // Reset variables - attributeId = 0; statusInt = 0; dataTypeInt = 0; numberOfElenemts = 0; elementType = 0; - data.clear(); + attributeId = 0; statusInt = 0; dataTypeInt = 0; // Read attribute id and status stream >> attributeId >> statusInt; @@ -126,72 +124,15 @@ QList ZigbeeClusterLibrary::par 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 if (dataType == Zigbee::OctetString || dataType == Zigbee::CharString) { - quint8 length = 0; - stream >> length; - qCDebug(dcZigbeeClusterLibrary()) << "Parse (octet string, character string)" << "Length:" << length; - for (int i = 0; i < length; i++) { - quint8 element = 0; - stream >> element; - data.append(element); - } - } else if (dataType == Zigbee::LongOctetString || dataType == Zigbee::LongCharString) { - quint16 length = 0; - stream >> length; - qCDebug(dcZigbeeClusterLibrary()) << "Parse (long octet string, long character string)" << "Length:" << length; - for (int i = 0; i < length; i++) { - quint8 element = 0; - stream >> element; - data.append(element); - } - } else { - // Normal data type - int length = ZigbeeDataType::typeLength(dataType); - 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); - } - } + qCDebug(dcZigbeeClusterLibrary()) << "Parse data type:" << dataType; + ZigbeeDataType type = readDataType(&stream, dataType); + if (!type.isValid()) + continue; ReadAttributeStatusRecord attributeRecord; attributeRecord.attributeId = attributeId; attributeRecord.attributeStatus = status; - attributeRecord.dataType = dataType; - attributeRecord.data = data; + attributeRecord.dataType = type; qCDebug(dcZigbeeClusterLibrary()) << attributeRecord; attributeStatusRecords.append(attributeRecord); } @@ -200,6 +141,82 @@ QList ZigbeeClusterLibrary::par return attributeStatusRecords; } +ZigbeeDataType ZigbeeClusterLibrary::readDataType(QDataStream *stream, Zigbee::DataType dataType) +{ + + QByteArray data; quint16 numberOfElenemts = 0; quint8 elementType = 0; + QDataStream dataStream(&data, QIODevice::WriteOnly); + dataStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data depending on the type + if (dataType == Zigbee::Array || dataType == Zigbee::Set || dataType == Zigbee::Bag) { + *stream >> elementType >> numberOfElenemts; + dataStream << elementType << numberOfElenemts; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (array, set, bag): Element type" << ZigbeeUtils::convertByteToHexString(elementType) << "Number of elements:" << numberOfElenemts; + if (numberOfElenemts == 0xffff) { + qCWarning(dcZigbeeClusterLibrary()) << "ZigbeeStatusRecord contains invalid data elements" << dataType; + return ZigbeeDataType(dataType); + } else { + for (int i = 0; i < numberOfElenemts; i++) { + quint8 element = 0; + *stream >> element; + dataStream << element; + } + } + } else if (dataType == Zigbee::Structure) { + *stream >> numberOfElenemts; + dataStream << numberOfElenemts; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (structure)" << "Number of elements:" << numberOfElenemts; + if (numberOfElenemts == 0xffff) { + qCWarning(dcZigbeeClusterLibrary()) << "ZigbeeStatusRecord contains invalid data elements" << dataType; + return ZigbeeDataType(dataType); + } 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); + dataStream << element; + } + } + } else if (dataType == Zigbee::OctetString || dataType == Zigbee::CharString) { + quint8 length = 0; + *stream >> length; + dataStream << length; + qCDebug(dcZigbeeClusterLibrary()) << "Parse (octet string, character string)" << "Length:" << length; + for (int i = 0; i < length; i++) { + quint8 element = 0; + *stream >> element; + dataStream << element; + } + } else if (dataType == Zigbee::LongOctetString || dataType == Zigbee::LongCharString) { + quint16 length = 0; + *stream >> length; + dataStream << length; + + qCDebug(dcZigbeeClusterLibrary()) << "Parse (long octet string, long character string)" << "Length:" << length; + for (int i = 0; i < length; i++) { + quint8 element = 0; + *stream >> element; + data.append(element); + dataStream << element; + } + } else { + // Normal data type + int length = ZigbeeDataType::typeLength(dataType); + qCDebug(dcZigbeeClusterLibrary()) << "Parse (normal data type)" << "Number of elements:" << length; + for (int i = 0; i < length; i++) { + quint8 element = 0; + *stream >> element; + dataStream << element; + } + } + + qCDebug(dcZigbeeClusterLibrary()) << "Parsed data:" << ZigbeeUtils::convertByteArrayToHexString(data); + return ZigbeeDataType(dataType, data); +} + ZigbeeClusterLibrary::Frame ZigbeeClusterLibrary::parseFrameData(const QByteArray &frameData) { QDataStream stream(frameData); @@ -281,12 +298,11 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame) QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord) { - debug.nospace().noquote() << "ReadAttributeStatusRecord(" - << ZigbeeUtils::convertUint16ToHexString(attributeStatusRecord.attributeId) << ", " - << attributeStatusRecord.attributeStatus << ", " - << attributeStatusRecord.dataType << ", " - << attributeStatusRecord.data - << ")"; + debug.nospace() << "ReadAttributeStatusRecord(" + << ZigbeeUtils::convertUint16ToHexString(attributeStatusRecord.attributeId) << ", " + << attributeStatusRecord.attributeStatus << ", " + << attributeStatusRecord.dataType + << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zcl/zigbeeclusterlibrary.h b/libnymea-zigbee/zcl/zigbeeclusterlibrary.h index bb4971b..246190f 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterlibrary.h +++ b/libnymea-zigbee/zcl/zigbeeclusterlibrary.h @@ -32,6 +32,7 @@ #include #include "zigbee.h" +#include "zigbeedatatype.h" class ZigbeeClusterLibrary { @@ -101,7 +102,7 @@ public: FrameControl frameControl; quint16 manufacturerCode = 0; quint8 transactionSequenceNumber = 0; - Command command; + quint8 command; } ZclHeader; typedef struct Frame { @@ -114,8 +115,7 @@ public: typedef struct ReadAttributeStatusRecord { quint16 attributeId; Zigbee::ZigbeeStatus attributeStatus; - Zigbee::DataType dataType; - QByteArray data; + ZigbeeDataType dataType; } ReadAttributeStatusRecord; @@ -128,7 +128,7 @@ public: static QList parseAttributeStatusRecords(const QByteArray &payload); //static QByteArray readAttributeData(const QDataStream &stream, Zigbee::DataType dataType); - + static ZigbeeDataType readDataType(QDataStream *stream, Zigbee::DataType dataType); static Frame parseFrameData(const QByteArray &frameData); static QByteArray buildFrame(const Frame &frame); diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp index 3fb9164..e0f18fe 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp @@ -1,3 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "zigbeeclusterreply.h" ZigbeeClusterReply::Error ZigbeeClusterReply::error() const diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.h b/libnymea-zigbee/zcl/zigbeeclusterreply.h index b035e1c..0135967 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.h +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.h @@ -1,3 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEECLUSTERREPLY_H #define ZIGBEECLUSTERREPLY_H diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp index 51bb29e..46fba7b 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp @@ -356,5 +356,5 @@ void ZigbeeDeviceObject::processApsDataIndication(quint8 destinationEndpoint, qu return; } - qCWarning(dcZigbeeDeviceObject()) << m_node << "unhandled ZDO indication"; + qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << asdu; } diff --git a/libnymea-zigbee/zigbeedatatype.cpp b/libnymea-zigbee/zigbeedatatype.cpp index fd06eb1..6ecac1b 100644 --- a/libnymea-zigbee/zigbeedatatype.cpp +++ b/libnymea-zigbee/zigbeedatatype.cpp @@ -1,16 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "zigbeedatatype.h" #include "zigbeeutils.h" #include #include +ZigbeeDataType::ZigbeeDataType() +{ + setDataType(Zigbee::NoData); +} + ZigbeeDataType::ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data): m_data(data) { setDataType(dataType); - - // TODO: verify data length and consistency @@ -414,6 +444,12 @@ int ZigbeeDataType::dataLength() const return typeLength(m_dataType); } +bool ZigbeeDataType::isValid() const +{ + // FIXME: implement validate data depending on the type + return m_dataType != Zigbee::NoData && !m_data.isNull(); +} + int ZigbeeDataType::typeLength(Zigbee::DataType dataType) { int length = 0; @@ -597,6 +633,23 @@ int ZigbeeDataType::typeLength(Zigbee::DataType dataType) return length; } +ZigbeeDataType &ZigbeeDataType::operator=(const ZigbeeDataType &other) +{ + setDataType(other.dataType()); + m_data = other.data(); + return *this; +} + +bool ZigbeeDataType::operator==(const ZigbeeDataType &other) const +{ + return m_dataType == other.dataType() && m_data == other.data(); +} + +bool ZigbeeDataType::operator!=(const ZigbeeDataType &other) const +{ + return !operator==(other); +} + void ZigbeeDataType::setDataType(Zigbee::DataType dataType) { m_dataType = dataType; @@ -885,6 +938,7 @@ void ZigbeeDataType::setDataType(Zigbee::DataType dataType) QDebug operator<<(QDebug debug, const ZigbeeDataType &dataType) { + // FIXME: print data depending on the datatype debug.nospace() << "ZigbeeDataType(" << dataType.name(); debug.nospace() << ", " << ZigbeeUtils::convertByteArrayToHexString(dataType.data()); debug.nospace() << ")"; diff --git a/libnymea-zigbee/zigbeedatatype.h b/libnymea-zigbee/zigbeedatatype.h index 67ec436..fe856f7 100644 --- a/libnymea-zigbee/zigbeedatatype.h +++ b/libnymea-zigbee/zigbeedatatype.h @@ -1,3 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEEDATATYPE_H #define ZIGBEEDATATYPE_H @@ -7,6 +34,7 @@ class ZigbeeDataType { public: + ZigbeeDataType(); ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data = QByteArray()); ZigbeeDataType(quint8 value, Zigbee::DataType dataType = Zigbee::Uint8); @@ -32,8 +60,14 @@ public: QByteArray data() const; int dataLength() const; + bool isValid() const; + static int typeLength(Zigbee::DataType dataType); + ZigbeeDataType &operator=(const ZigbeeDataType &other); + bool operator==(const ZigbeeDataType &other) const; + bool operator!=(const ZigbeeDataType &other) const; + private: Zigbee::DataType m_dataType = Zigbee::NoData; QByteArray m_data; diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index 9aa15c4..ab28612 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -671,9 +671,16 @@ void ZigbeeNode::initBasicCluster() 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); + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + m_endpoints.first()->m_manufacturerName = manufacturerName; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType; + } } } @@ -687,13 +694,19 @@ void ZigbeeNode::initBasicCluster() 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); + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + m_endpoints.first()->m_modelIdentifier = modelIdentifier; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType; + } } } - ZigbeeClusterBasic::Attribute attributeId = ZigbeeClusterBasic::AttributeSwBuildId; qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId; ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast(attributeId)}); @@ -704,9 +717,16 @@ void ZigbeeNode::initBasicCluster() 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); + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + m_endpoints.first()->m_softwareBuildId = softwareBuildId; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType; + } } } @@ -715,7 +735,6 @@ void ZigbeeNode::initBasicCluster() }); }); }); - } void ZigbeeNode::onClusterAttributeChanged(const ZigbeeClusterAttribute &attribute) diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index e6e3994..e0c2053 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -154,6 +154,9 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi case Zigbee::ClusterIdBasic: return new ZigbeeClusterBasic(m_network, m_node, this, direction, this); break; + case Zigbee::ClusterIdOnOff: + return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this); + break; default: return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this); } diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index 52fef6a..652a41d 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -36,6 +36,7 @@ #include "zcl/zigbeecluster.h" #include "zcl/general/zigbeeclusterbasic.h" +#include "zcl/general/zigbeeclusteronoff.h" class ZigbeeNode; class ZigbeeNetwork;