Add on off cluster and use zigbedatatype for atributes

This commit is contained in:
Simon Stürz 2020-05-27 21:56:41 +02:00
parent ab560a9c55
commit 7e5643a1cf
20 changed files with 607 additions and 148 deletions

View File

@ -250,7 +250,7 @@ bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate)
connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError))); connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError)));
if (!m_serialPort->open(QSerialPort::ReadWrite)) { 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(); m_reconnectTimer->start();
return false; return false;
} }

View File

@ -8,6 +8,7 @@ SOURCES += \
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \ backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
backends/deconz/zigbeebridgecontrollerdeconz.cpp \ backends/deconz/zigbeebridgecontrollerdeconz.cpp \
backends/deconz/zigbeenetworkdeconz.cpp \ backends/deconz/zigbeenetworkdeconz.cpp \
zcl/general/zigbeeclusteronoff.cpp \
zcl/zigbeecluster.cpp \ zcl/zigbeecluster.cpp \
zcl/zigbeeclusterattribute.cpp \ zcl/zigbeeclusterattribute.cpp \
zcl/zigbeeclusterlibrary.cpp \ zcl/zigbeeclusterlibrary.cpp \
@ -49,6 +50,7 @@ HEADERS += \
backends/deconz/interface/zigbeeinterfacedeconzreply.h \ backends/deconz/interface/zigbeeinterfacedeconzreply.h \
backends/deconz/zigbeebridgecontrollerdeconz.h \ backends/deconz/zigbeebridgecontrollerdeconz.h \
backends/deconz/zigbeenetworkdeconz.h \ backends/deconz/zigbeenetworkdeconz.h \
zcl/general/zigbeeclusteronoff.h \
zcl/zigbeecluster.h \ zcl/zigbeecluster.h \
zcl/zigbeeclusterattribute.h \ zcl/zigbeeclusterattribute.h \
zcl/zigbeeclusterlibrary.h \ zcl/zigbeeclusterlibrary.h \

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 "zigbeeclusterbasic.h"
#include "loggingcategory.h" #include "loggingcategory.h"
@ -10,11 +37,11 @@ ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node,
void ZigbeeClusterBasic::setAttribute(const ZigbeeClusterAttribute &attribute) void ZigbeeClusterBasic::setAttribute(const ZigbeeClusterAttribute &attribute)
{ {
if (hasAttribute(attribute.id())) { if (hasAttribute(attribute.id())) {
qCDebug(dcZigbeeCluster()) << this << "update attribute" << static_cast<Attribute>(attribute.id()) << attribute.dataType() << attribute.data(); qCDebug(dcZigbeeCluster()) << "Update attribute" << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
m_attributes[attribute.id()] = attribute; m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute); emit attributeChanged(attribute);
} else { } else {
qCDebug(dcZigbeeCluster()) << this << "add attribute" << static_cast<Attribute>(attribute.id()) << attribute.dataType() << attribute.data(); qCDebug(dcZigbeeCluster()) << "Add attribute" << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
m_attributes.insert(attribute.id(), attribute); m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute); emit attributeChanged(attribute);
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 #ifndef ZIGBEECLUSTERBASIC_H
#define ZIGBEECLUSTERBASIC_H #define ZIGBEECLUSTERBASIC_H
@ -172,13 +199,9 @@ public:
explicit ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); explicit ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
private: private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override; void setAttribute(const ZigbeeClusterAttribute &attribute) override;
signals:
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterBasic::AlarmMasks) Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterBasic::AlarmMasks)

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QDataStream>
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>(attribute.id()) << attribute.dataType();
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
} else {
qCDebug(dcZigbeeCluster()) << "Add attribute" << this << static_cast<Attribute>(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;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#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

View File

@ -82,11 +82,11 @@ ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 attributeId)
void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute) void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute)
{ {
if (hasAttribute(attribute.id())) { if (hasAttribute(attribute.id())) {
qCDebug(dcZigbeeCluster()) << this << "update attribute" << attribute; qCDebug(dcZigbeeCluster()) << "Update attribute" << this << attribute;
m_attributes[attribute.id()] = attribute; m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute); emit attributeChanged(attribute);
} else { } else {
qCDebug(dcZigbeeCluster()) << this << "add attribute" << attribute; qCDebug(dcZigbeeCluster()) << "Add attribute" << this << attribute;
m_attributes.insert(attribute.id(), attribute); m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute); emit attributeChanged(attribute);
} }
@ -94,7 +94,7 @@ void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute)
ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes) ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> 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 // Build the request
ZigbeeNetworkRequest request = createGeneralRequest(); ZigbeeNetworkRequest request = createGeneralRequest();
@ -139,7 +139,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request" qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error() << m_node << m_endpoint << this << networkReply->error()
<< networkReply->zigbeeApsStatus(); << networkReply->zigbeeApsStatus();
finishZclReply(zclReply); finishZclReply(zclReply);
return; return;
@ -211,14 +211,23 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply) void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply)
{ {
m_pendingReplies.remove(zclReply->transactionSequenceNumber()); m_pendingReplies.remove(zclReply->transactionSequenceNumber());
qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame();
zclReply->finished(); 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) void ZigbeeCluster::processApsDataIndication(QByteArray payload)
{ {
ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(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)) { if (m_pendingReplies.contains(frame.header.transactionSequenceNumber)) {
ZigbeeClusterReply *reply = m_pendingReplies.value(frame.header.transactionSequenceNumber); ZigbeeClusterReply *reply = m_pendingReplies.value(frame.header.transactionSequenceNumber);
reply->m_responseData = payload; reply->m_responseData = payload;
@ -231,8 +240,8 @@ void ZigbeeCluster::processApsDataIndication(QByteArray payload)
return; return;
} }
// FIXME: increase transaction sequence number // Not for a reply, process the indication
qCWarning(dcZigbeeNode()) << m_node << m_endpoint << this << "Unhandled ZCL indication" << ZigbeeUtils::convertByteArrayToHexString(payload); processDataIndication(frame);
} }
QDebug operator<<(QDebug debug, ZigbeeCluster *cluster) QDebug operator<<(QDebug debug, ZigbeeCluster *cluster)
@ -252,7 +261,7 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeRep
<< attributeReport.attributeId << ", " << attributeReport.attributeId << ", "
<< attributeReport.attributeStatus << ", " << attributeReport.attributeStatus << ", "
<< attributeReport.dataType << ", " << attributeReport.dataType << ", "
<< attributeReport.data << ", " << ZigbeeUtils::convertByteArrayToHexString(attributeReport.data)
<< ")"; << ")";
return debug.space(); return debug.space();

View File

@ -89,23 +89,6 @@ public:
// }; // };
// Q_ENUM(PowerConfigurationAttribute) // 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 // // Level cluster 0x0008
@ -195,6 +178,8 @@ protected:
bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply); bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply);
void finishZclReply(ZigbeeClusterReply *zclReply); void finishZclReply(ZigbeeClusterReply *zclReply);
virtual void processDataIndication(ZigbeeClusterLibrary::Frame frame);
private: private:
virtual void setAttribute(const ZigbeeClusterAttribute &attribute); virtual void setAttribute(const ZigbeeClusterAttribute &attribute);
@ -204,7 +189,6 @@ signals:
public slots: public slots:
void processApsDataIndication(QByteArray payload); void processApsDataIndication(QByteArray payload);
}; };
QDebug operator<<(QDebug debug, ZigbeeCluster *cluster); QDebug operator<<(QDebug debug, ZigbeeCluster *cluster);

View File

@ -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_id(id),
m_dataType(dataType), m_dataType(dataType)
m_data(data)
{ {
} }
@ -45,7 +44,6 @@ ZigbeeClusterAttribute::ZigbeeClusterAttribute(const ZigbeeClusterAttribute &oth
{ {
m_id = other.id(); m_id = other.id();
m_dataType = other.dataType(); m_dataType = other.dataType();
m_data = other.data();
} }
quint16 ZigbeeClusterAttribute::id() const quint16 ZigbeeClusterAttribute::id() const
@ -53,29 +51,21 @@ quint16 ZigbeeClusterAttribute::id() const
return m_id; return m_id;
} }
Zigbee::DataType ZigbeeClusterAttribute::dataType() const ZigbeeDataType ZigbeeClusterAttribute::dataType() const
{ {
return m_dataType; return m_dataType;
} }
QByteArray ZigbeeClusterAttribute::data() const
{
return m_data;
}
ZigbeeClusterAttribute &ZigbeeClusterAttribute::operator=(const ZigbeeClusterAttribute &other) ZigbeeClusterAttribute &ZigbeeClusterAttribute::operator=(const ZigbeeClusterAttribute &other)
{ {
m_id = other.id(); m_id = other.id();
m_dataType = other.dataType(); m_dataType = other.dataType();
m_data = other.data();
return *this; return *this;
} }
bool ZigbeeClusterAttribute::operator==(const ZigbeeClusterAttribute &other) const bool ZigbeeClusterAttribute::operator==(const ZigbeeClusterAttribute &other) const
{ {
return m_id == other.id() && return m_id == other.id() && m_dataType == other.dataType();
m_dataType == other.dataType() &&
m_data == other.data();
} }
bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) const bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) const
@ -85,16 +75,14 @@ bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) con
bool ZigbeeClusterAttribute::isValid() const bool ZigbeeClusterAttribute::isValid() const
{ {
return m_id != 0 || return m_id != 0xffff && m_dataType.isValid();
m_dataType != Zigbee::NoData ||
!m_data.isNull();
} }
QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute) QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute)
{ {
debug.nospace().noquote() << "ZigbeeClusterAttribute(" debug.nospace().noquote() << "ZigbeeClusterAttribute("
<< ZigbeeUtils::convertUint16ToHexString(attribute.id()) << ", " << ZigbeeUtils::convertUint16ToHexString(attribute.id()) << ", "
<< attribute.dataType() << ", " << attribute.dataType()
<< ZigbeeUtils::convertByteArrayToHexString(attribute.data()) << ")"; << ")";
return debug.space(); return debug.space();
} }

View File

@ -31,17 +31,17 @@
#include <QDebug> #include <QDebug>
#include "zigbee.h" #include "zigbee.h"
#include "zigbeedatatype.h"
class ZigbeeClusterAttribute class ZigbeeClusterAttribute
{ {
public: public:
ZigbeeClusterAttribute(); ZigbeeClusterAttribute();
ZigbeeClusterAttribute(quint16 id, Zigbee::DataType dataType, QByteArray data); ZigbeeClusterAttribute(quint16 id, const ZigbeeDataType &dataType);
ZigbeeClusterAttribute(const ZigbeeClusterAttribute &other); ZigbeeClusterAttribute(const ZigbeeClusterAttribute &other);
quint16 id() const; quint16 id() const;
Zigbee::DataType dataType() const; ZigbeeDataType dataType() const;
QByteArray data() const;
ZigbeeClusterAttribute &operator=(const ZigbeeClusterAttribute &other); ZigbeeClusterAttribute &operator=(const ZigbeeClusterAttribute &other);
bool operator==(const ZigbeeClusterAttribute &other) const; bool operator==(const ZigbeeClusterAttribute &other) const;
@ -50,9 +50,8 @@ public:
bool isValid() const; bool isValid() const;
private: private:
quint16 m_id = 0; quint16 m_id = 0xffff;
Zigbee::DataType m_dataType = Zigbee::NoData; ZigbeeDataType m_dataType;
QByteArray m_data;
}; };
QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute); QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute);

View File

@ -104,13 +104,11 @@ QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> ZigbeeClusterLibrary::par
QDataStream stream(payload); QDataStream stream(payload);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 attributeId; quint8 statusInt; quint8 dataTypeInt; quint16 numberOfElenemts; quint8 elementType; quint16 attributeId; quint8 statusInt; quint8 dataTypeInt;
QByteArray data;
while (!stream.atEnd()) { while (!stream.atEnd()) {
// Reset variables // Reset variables
attributeId = 0; statusInt = 0; dataTypeInt = 0; numberOfElenemts = 0; elementType = 0; attributeId = 0; statusInt = 0; dataTypeInt = 0;
data.clear();
// Read attribute id and status // Read attribute id and status
stream >> attributeId >> statusInt; stream >> attributeId >> statusInt;
@ -126,72 +124,15 @@ QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> ZigbeeClusterLibrary::par
stream >> dataTypeInt; stream >> dataTypeInt;
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(dataTypeInt); Zigbee::DataType dataType = static_cast<Zigbee::DataType>(dataTypeInt);
qCDebug(dcZigbeeClusterLibrary()) << "Parse:" << dataType; qCDebug(dcZigbeeClusterLibrary()) << "Parse data type:" << dataType;
ZigbeeDataType type = readDataType(&stream, dataType);
// Parse data depending on the type if (!type.isValid())
if (dataType == Zigbee::Array || dataType == Zigbee::Set || dataType == Zigbee::Bag) { continue;
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);
}
}
ReadAttributeStatusRecord attributeRecord; ReadAttributeStatusRecord attributeRecord;
attributeRecord.attributeId = attributeId; attributeRecord.attributeId = attributeId;
attributeRecord.attributeStatus = status; attributeRecord.attributeStatus = status;
attributeRecord.dataType = dataType; attributeRecord.dataType = type;
attributeRecord.data = data;
qCDebug(dcZigbeeClusterLibrary()) << attributeRecord; qCDebug(dcZigbeeClusterLibrary()) << attributeRecord;
attributeStatusRecords.append(attributeRecord); attributeStatusRecords.append(attributeRecord);
} }
@ -200,6 +141,82 @@ QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> ZigbeeClusterLibrary::par
return attributeStatusRecords; 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) ZigbeeClusterLibrary::Frame ZigbeeClusterLibrary::parseFrameData(const QByteArray &frameData)
{ {
QDataStream stream(frameData); QDataStream stream(frameData);
@ -281,12 +298,11 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame)
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord) QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord)
{ {
debug.nospace().noquote() << "ReadAttributeStatusRecord(" debug.nospace() << "ReadAttributeStatusRecord("
<< ZigbeeUtils::convertUint16ToHexString(attributeStatusRecord.attributeId) << ", " << ZigbeeUtils::convertUint16ToHexString(attributeStatusRecord.attributeId) << ", "
<< attributeStatusRecord.attributeStatus << ", " << attributeStatusRecord.attributeStatus << ", "
<< attributeStatusRecord.dataType << ", " << attributeStatusRecord.dataType
<< attributeStatusRecord.data << ")";
<< ")";
return debug.space(); return debug.space();
} }

View File

@ -32,6 +32,7 @@
#include <QDebug> #include <QDebug>
#include "zigbee.h" #include "zigbee.h"
#include "zigbeedatatype.h"
class ZigbeeClusterLibrary class ZigbeeClusterLibrary
{ {
@ -101,7 +102,7 @@ public:
FrameControl frameControl; FrameControl frameControl;
quint16 manufacturerCode = 0; quint16 manufacturerCode = 0;
quint8 transactionSequenceNumber = 0; quint8 transactionSequenceNumber = 0;
Command command; quint8 command;
} ZclHeader; } ZclHeader;
typedef struct Frame { typedef struct Frame {
@ -114,8 +115,7 @@ public:
typedef struct ReadAttributeStatusRecord { typedef struct ReadAttributeStatusRecord {
quint16 attributeId; quint16 attributeId;
Zigbee::ZigbeeStatus attributeStatus; Zigbee::ZigbeeStatus attributeStatus;
Zigbee::DataType dataType; ZigbeeDataType dataType;
QByteArray data;
} ReadAttributeStatusRecord; } ReadAttributeStatusRecord;
@ -128,7 +128,7 @@ public:
static QList<ReadAttributeStatusRecord> parseAttributeStatusRecords(const QByteArray &payload); static QList<ReadAttributeStatusRecord> parseAttributeStatusRecords(const QByteArray &payload);
//static QByteArray readAttributeData(const QDataStream &stream, Zigbee::DataType dataType); //static QByteArray readAttributeData(const QDataStream &stream, Zigbee::DataType dataType);
static ZigbeeDataType readDataType(QDataStream *stream, Zigbee::DataType dataType);
static Frame parseFrameData(const QByteArray &frameData); static Frame parseFrameData(const QByteArray &frameData);
static QByteArray buildFrame(const Frame &frame); static QByteArray buildFrame(const Frame &frame);

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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" #include "zigbeeclusterreply.h"
ZigbeeClusterReply::Error ZigbeeClusterReply::error() const ZigbeeClusterReply::Error ZigbeeClusterReply::error() const

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 #ifndef ZIGBEECLUSTERREPLY_H
#define ZIGBEECLUSTERREPLY_H #define ZIGBEECLUSTERREPLY_H

View File

@ -356,5 +356,5 @@ void ZigbeeDeviceObject::processApsDataIndication(quint8 destinationEndpoint, qu
return; return;
} }
qCWarning(dcZigbeeDeviceObject()) << m_node << "unhandled ZDO indication"; qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << asdu;
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 "zigbeedatatype.h"
#include "zigbeeutils.h" #include "zigbeeutils.h"
#include <QtGlobal> #include <QtGlobal>
#include <QDataStream> #include <QDataStream>
ZigbeeDataType::ZigbeeDataType()
{
setDataType(Zigbee::NoData);
}
ZigbeeDataType::ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data): ZigbeeDataType::ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data):
m_data(data) m_data(data)
{ {
setDataType(dataType); setDataType(dataType);
// TODO: verify data length and consistency // TODO: verify data length and consistency
@ -414,6 +444,12 @@ int ZigbeeDataType::dataLength() const
return typeLength(m_dataType); 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 ZigbeeDataType::typeLength(Zigbee::DataType dataType)
{ {
int length = 0; int length = 0;
@ -597,6 +633,23 @@ int ZigbeeDataType::typeLength(Zigbee::DataType dataType)
return length; 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) void ZigbeeDataType::setDataType(Zigbee::DataType dataType)
{ {
m_dataType = dataType; m_dataType = dataType;
@ -885,6 +938,7 @@ void ZigbeeDataType::setDataType(Zigbee::DataType dataType)
QDebug operator<<(QDebug debug, const ZigbeeDataType &dataType) QDebug operator<<(QDebug debug, const ZigbeeDataType &dataType)
{ {
// FIXME: print data depending on the datatype
debug.nospace() << "ZigbeeDataType(" << dataType.name(); debug.nospace() << "ZigbeeDataType(" << dataType.name();
debug.nospace() << ", " << ZigbeeUtils::convertByteArrayToHexString(dataType.data()); debug.nospace() << ", " << ZigbeeUtils::convertByteArrayToHexString(dataType.data());
debug.nospace() << ")"; debug.nospace() << ")";

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 #ifndef ZIGBEEDATATYPE_H
#define ZIGBEEDATATYPE_H #define ZIGBEEDATATYPE_H
@ -7,6 +34,7 @@
class ZigbeeDataType class ZigbeeDataType
{ {
public: public:
ZigbeeDataType();
ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data = QByteArray()); ZigbeeDataType(Zigbee::DataType dataType, const QByteArray &data = QByteArray());
ZigbeeDataType(quint8 value, Zigbee::DataType dataType = Zigbee::Uint8); ZigbeeDataType(quint8 value, Zigbee::DataType dataType = Zigbee::Uint8);
@ -32,8 +60,14 @@ public:
QByteArray data() const; QByteArray data() const;
int dataLength() const; int dataLength() const;
bool isValid() const;
static int typeLength(Zigbee::DataType dataType); static int typeLength(Zigbee::DataType dataType);
ZigbeeDataType &operator=(const ZigbeeDataType &other);
bool operator==(const ZigbeeDataType &other) const;
bool operator!=(const ZigbeeDataType &other) const;
private: private:
Zigbee::DataType m_dataType = Zigbee::NoData; Zigbee::DataType m_dataType = Zigbee::NoData;
QByteArray m_data; QByteArray m_data;

View File

@ -671,9 +671,16 @@ void ZigbeeNode::initBasicCluster()
qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully";
QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload);
if (!attributeStatusRecords.isEmpty()) { if (!attributeStatusRecords.isEmpty()) {
qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first();
basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); qCDebug(dcZigbeeNode()) << attributeStatusRecord;
m_endpoints.first()->m_manufacturerName = QString::fromUtf8(attributeStatusRecords.first().data); basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(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"; qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully";
QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload);
if (!attributeStatusRecords.isEmpty()) { if (!attributeStatusRecords.isEmpty()) {
qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first();
basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); qCDebug(dcZigbeeNode()) << attributeStatusRecord;
m_endpoints.first()->m_modelIdentifier = QString::fromUtf8(attributeStatusRecords.first().data); basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(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; ZigbeeClusterBasic::Attribute attributeId = ZigbeeClusterBasic::AttributeSwBuildId;
qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId; qCDebug(dcZigbeeNode()) << "Reading attribute" << attributeId;
ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast<quint16>(attributeId)}); ZigbeeClusterReply *reply = basicCluster->readAttributes({static_cast<quint16>(attributeId)});
@ -704,9 +717,16 @@ void ZigbeeNode::initBasicCluster()
qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully";
QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload);
if (!attributeStatusRecords.isEmpty()) { if (!attributeStatusRecords.isEmpty()) {
qCDebug(dcZigbeeNode()) << attributeStatusRecords.first(); ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first();
basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(attributeId), attributeStatusRecords.first().dataType, attributeStatusRecords.first().data)); qCDebug(dcZigbeeNode()) << attributeStatusRecord;
m_endpoints.first()->m_softwareBuildId = QString::fromUtf8(attributeStatusRecords.first().data); basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast<quint16>(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) void ZigbeeNode::onClusterAttributeChanged(const ZigbeeClusterAttribute &attribute)

View File

@ -154,6 +154,9 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi
case Zigbee::ClusterIdBasic: case Zigbee::ClusterIdBasic:
return new ZigbeeClusterBasic(m_network, m_node, this, direction, this); return new ZigbeeClusterBasic(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdOnOff:
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
break;
default: default:
return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this); return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this);
} }

View File

@ -36,6 +36,7 @@
#include "zcl/zigbeecluster.h" #include "zcl/zigbeecluster.h"
#include "zcl/general/zigbeeclusterbasic.h" #include "zcl/general/zigbeeclusterbasic.h"
#include "zcl/general/zigbeeclusteronoff.h"
class ZigbeeNode; class ZigbeeNode;
class ZigbeeNetwork; class ZigbeeNetwork;