Implement power configuration cluster

This commit is contained in:
Simon Stürz 2020-06-13 21:18:01 +02:00
parent 0992028a8a
commit cdd7a1a1aa
33 changed files with 620 additions and 67375 deletions

View File

@ -9,8 +9,10 @@ Depending on your available hardware following gateway modules are supported
## NXP ## NXP
* JN5168 (SoM) > Note: the firmware erquires an entire rework and implement the APS layer
* JN5169 (USB Stick)
* ~~JN5168 (SoM)~~
* ~~JN5169 (USB Stick)~~
## deCONZ ## deCONZ
@ -20,15 +22,11 @@ Depending on your available hardware following gateway modules are supported
* RaspBee II * RaspBee II
## Structure ## Hidden base groups
Each sensor/remote cluster will be bound automatically to the sensors group in order to receive commands from the device. The lights group can be used to switch all lights within the network with one command.
- Sensors: `0xfff0`
- Light: `0xfff1`
ZigbeeNetwork
- ZDO handler
- ZCL handler
- ZHA handler
- ZLL handler
- GP handler
- [ZigbeeNode]
- [ZigbeeNodeEndpoints]
- Profile

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@ SOURCES += \
zcl/general/zigbeeclusteridentify.cpp \ zcl/general/zigbeeclusteridentify.cpp \
zcl/general/zigbeeclusterlevelcontrol.cpp \ zcl/general/zigbeeclusterlevelcontrol.cpp \
zcl/general/zigbeeclusteronoff.cpp \ zcl/general/zigbeeclusteronoff.cpp \
zcl/general/zigbeeclusterpowerconfiguration.cpp \
zcl/lighting/zigbeeclustercolorcontrol.cpp \ zcl/lighting/zigbeeclustercolorcontrol.cpp \
zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \ zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \
zcl/measurement/zigbeeclusteroccupancysensing.cpp \ zcl/measurement/zigbeeclusteroccupancysensing.cpp \
@ -61,6 +62,7 @@ HEADERS += \
zcl/general/zigbeeclusteridentify.h \ zcl/general/zigbeeclusteridentify.h \
zcl/general/zigbeeclusterlevelcontrol.h \ zcl/general/zigbeeclusterlevelcontrol.h \
zcl/general/zigbeeclusteronoff.h \ zcl/general/zigbeeclusteronoff.h \
zcl/general/zigbeeclusterpowerconfiguration.h \
zcl/lighting/zigbeeclustercolorcontrol.h \ zcl/lighting/zigbeeclustercolorcontrol.h \
zcl/measurement/zigbeeclusterilluminancemeasurment.h \ zcl/measurement/zigbeeclusterilluminancemeasurment.h \
zcl/measurement/zigbeeclusteroccupancysensing.h \ zcl/measurement/zigbeeclusteroccupancysensing.h \

View File

@ -31,7 +31,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterBasic::ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdBasic, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdBasic, direction, parent)
{ {
} }

View File

@ -33,7 +33,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterIdentify::ZigbeeClusterIdentify(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : ZigbeeClusterIdentify::ZigbeeClusterIdentify(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdIdentify, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdIdentify, direction, parent)
{ {
} }

View File

@ -33,7 +33,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterLevelControl::ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : ZigbeeClusterLevelControl::ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdLevelControl, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdLevelControl, direction, parent)
{ {
} }

View File

@ -33,7 +33,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterOnOff::ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterOnOff::ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdOnOff, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdOnOff, direction, parent)
{ {
} }

View File

@ -0,0 +1,60 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "zigbeeclusterpowerconfiguration.h"
#include "loggingcategory.h"
#include <QDataStream>
ZigbeeClusterPowerConfiguration::ZigbeeClusterPowerConfiguration(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdPowerConfiguration, direction, parent)
{
}
void ZigbeeClusterPowerConfiguration::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
if (hasAttribute(attribute.id())) {
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
} else {
m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute);
}
if (attribute.id() == AttributeBatteryPercentageRemaining) {
bool valueOk = false;
quint8 value = attribute.dataType().toUInt8(&valueOk);
if (valueOk) {
qCDebug(dcZigbeeCluster()) << "PowerConfiguration attribute changed on" << m_node << m_endpoint << this << value;
emit batteryPercentageChanged(value / 2.0);
} else {
qCWarning(dcZigbeeCluster()) << "Failed to parse attribute data" << m_node << m_endpoint << this << attribute;
}
}
}

View File

@ -0,0 +1,101 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 ZIGBEECLUSTERPOWERCONFIGURATION_H
#define ZIGBEECLUSTERPOWERCONFIGURATION_H
#include <QObject>
#include "zcl/zigbeecluster.h"
class ZigbeeNode;
class ZigbeeNetwork;
class ZigbeeNodeEndpoint;
class ZigbeeNetworkReply;
class ZigbeeClusterPowerConfiguration : public ZigbeeCluster
{
Q_OBJECT
friend class ZigbeeNode;
friend class ZigbeeNetwork;
public:
enum Attribute {
// Mains information
AttributeMainsVoltage = 0x0000,
AttributeMainsFrequency = 0x0001,
// Mains settings
AttributeMainsAlarmMask = 0x0010,
AttributeMainsVoltageMinThreshold = 0x0011,
AttributeMainsVoltageMaxThreshold = 0x0012,
AttributeMainsVoltageDwellTripPoint = 0x0013,
// Battery information
AttributeBatteryVoltage = 0x0020,
AttributeBatteryPercentageRemaining = 0x0021,
// Battery settings
AttributeBatteryManufacturer = 0x0030,
AttributeBatterySize = 0x0031,
AttributeBatteryAHrRating = 0x0032,
AttributeBatteryQuality = 0x0033,
AttributeBatteryRatedVoltage = 0x0034,
AttributeBatteryAlarmMask = 0x0035,
AttributeBatteryVoltageMinThreshold = 0x0036,
AttributeBatteryVoltageThreshold1 = 0x0037,
AttributeBatteryVoltageThreshold2 = 0x0038,
AttributeBatteryVoltageThreshold3 = 0x0039,
AttributeBatteryPercentageMinThreshold = 0x003a,
AttributeBatteryPercentageThreshold1 = 0x003b,
AttributeBatteryPercentageThreshold2 = 0x003c,
AttributeBatteryPercentageThreshold3 = 0x003d,
AttributeBatteryAlarmState = 0x003e
};
Q_ENUM(Attribute)
enum MainsAlarmMask {
MainsAlarmMaskMainVoltageToLow = 0x01,
MainsAlarmMaskMainVoltageToHigh = 0x02,
MainsAlarmMaskMainPowerSupplyLost = 0x04
};
Q_ENUM(MainsAlarmMask)
Q_DECLARE_FLAGS(MainsAlarmMaskFlag, MainsAlarmMask)
explicit ZigbeeClusterPowerConfiguration(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
signals:
void batteryPercentageChanged(double percentage);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterPowerConfiguration::MainsAlarmMaskFlag)
#endif // ZIGBEECLUSTERPOWERCONFIGURATION_H

View File

@ -33,7 +33,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterColorControl::ZigbeeClusterColorControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : ZigbeeClusterColorControl::ZigbeeClusterColorControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdColorControl, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdColorControl, direction, parent)
{ {
} }
@ -105,6 +105,7 @@ ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToHueAndSaturation(qui
ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColor(quint16 colorX, quint16 colorY, quint16 transitionTime) ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColor(quint16 colorX, quint16 colorY, quint16 transitionTime)
{ {
qCDebug(dcZigbeeCluster()) << "Move to color" << colorX << colorY << transitionTime << "1/10 s";
QByteArray payload; QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly); QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
@ -132,6 +133,8 @@ ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepColor(quint16 stepX, q
ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColorTemperature(quint16 colorTemperatureMireds, quint16 transitionTime) ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColorTemperature(quint16 colorTemperatureMireds, quint16 transitionTime)
{ {
qCDebug(dcZigbeeCluster()) << "Move to color temperature" << colorTemperatureMireds << transitionTime << "1/10 s";
QByteArray payload; QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly); QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);

View File

@ -31,7 +31,7 @@
#include "zigbeenetwork.h" #include "zigbeenetwork.h"
ZigbeeClusterIlluminanceMeasurment::ZigbeeClusterIlluminanceMeasurment(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterIlluminanceMeasurment::ZigbeeClusterIlluminanceMeasurment(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdIlluminanceMeasurement, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement, direction, parent)
{ {
} }

View File

@ -31,7 +31,7 @@
#include "zigbeenetwork.h" #include "zigbeenetwork.h"
ZigbeeClusterOccupancySensing::ZigbeeClusterOccupancySensing(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterOccupancySensing::ZigbeeClusterOccupancySensing(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdOccupancySensing, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdOccupancySensing, direction, parent)
{ {
} }

View File

@ -31,7 +31,7 @@
#include "zigbeenetwork.h" #include "zigbeenetwork.h"
ZigbeeClusterRelativeHumidityMeasurement::ZigbeeClusterRelativeHumidityMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterRelativeHumidityMeasurement::ZigbeeClusterRelativeHumidityMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdRelativeHumidityMeasurement, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement, direction, parent)
{ {
} }

View File

@ -31,7 +31,7 @@
#include "zigbeenetwork.h" #include "zigbeenetwork.h"
ZigbeeClusterTemperatureMeasurement::ZigbeeClusterTemperatureMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) : ZigbeeClusterTemperatureMeasurement::ZigbeeClusterTemperatureMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdTemperatureMeasurement, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement, direction, parent)
{ {
} }

View File

@ -34,7 +34,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeClusterIasZone::ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : ZigbeeClusterIasZone::ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdIasZone, direction, parent) ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdIasZone, direction, parent)
{ {
} }

View File

@ -35,7 +35,7 @@
#include <QDataStream> #include <QDataStream>
ZigbeeCluster::ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent) : ZigbeeCluster::ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeClusterLibrary::ClusterId clusterId, Direction direction, QObject *parent) :
QObject(parent), QObject(parent),
m_network(network), m_network(network),
m_node(node), m_node(node),
@ -61,14 +61,14 @@ ZigbeeCluster::Direction ZigbeeCluster::direction() const
return m_direction; return m_direction;
} }
Zigbee::ClusterId ZigbeeCluster::clusterId() const ZigbeeClusterLibrary::ClusterId ZigbeeCluster::clusterId() const
{ {
return m_clusterId; return m_clusterId;
} }
QString ZigbeeCluster::clusterName() const QString ZigbeeCluster::clusterName() const
{ {
return ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(m_clusterId)); return ZigbeeUtils::clusterIdToString(static_cast<ZigbeeClusterLibrary::ClusterId>(m_clusterId));
} }
QList<ZigbeeClusterAttribute> ZigbeeCluster::attributes() const QList<ZigbeeClusterAttribute> ZigbeeCluster::attributes() const
@ -105,6 +105,32 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
{ {
qCDebug(dcZigbeeCluster()) << "Read attributes from" << m_node << m_endpoint << this << attributes; qCDebug(dcZigbeeCluster()) << "Read attributes from" << m_node << m_endpoint << this << attributes;
// ZCL payload
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
foreach (quint16 attribute, attributes) {
stream << attribute;
}
return executeGlobalCommand(ZigbeeClusterLibrary::CommandReadAttributes, payload);
}
ZigbeeClusterReply *ZigbeeCluster::configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations)
{
qCDebug(dcZigbeeCluster()) << "Configure reporting on" << m_node << m_endpoint << this << reportingConfigurations;
QByteArray payload;
foreach (const ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfiguration, reportingConfigurations) {
payload += ZigbeeClusterLibrary::buildAttributeReportingConfiguration(reportingConfiguration);
}
return executeGlobalCommand(ZigbeeClusterLibrary::CommandConfigureReporting, payload);
}
ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QByteArray &payload)
{
// Build the request // Build the request
ZigbeeNetworkRequest request = createGeneralRequest(); ZigbeeNetworkRequest request = createGeneralRequest();
@ -124,17 +150,9 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
// ZCL header // ZCL header
ZigbeeClusterLibrary::Header header; ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl; header.frameControl = frameControl;
header.command = ZigbeeClusterLibrary::CommandReadAttributes; header.command = command;
header.transactionSequenceNumber = m_transactionSequenceNumber++; header.transactionSequenceNumber = m_transactionSequenceNumber++;
// ZCL payload
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
foreach (quint16 attribute, attributes) {
stream << attribute;
}
// Put them together // Put them together
ZigbeeClusterLibrary::Frame frame; ZigbeeClusterLibrary::Frame frame;
frame.header = header; frame.header = header;
@ -163,6 +181,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
return zclReply; return zclReply;
} }
ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame) ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame)
{ {
ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this); ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this);
@ -198,6 +217,7 @@ ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const Q
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame)); request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame); ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
qCDebug(dcZigbeeCluster()) << "Executing command" << ZigbeeUtils::convertByteToHexString(command) << ZigbeeUtils::convertByteArrayToHexString(payload);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {

View File

@ -48,9 +48,9 @@ struct ZigbeeClusterReportConfigurationRecord {
typedef struct ZigbeeClusterAttributeReport { typedef struct ZigbeeClusterAttributeReport {
quint16 sourceAddress; quint16 sourceAddress;
quint8 endpointId; quint8 endpointId;
Zigbee::ClusterId clusterId; ZigbeeClusterLibrary::ClusterId clusterId;
quint16 attributeId; quint16 attributeId;
Zigbee::ZigbeeStatus attributeStatus; ZigbeeClusterLibrary::Status attributeStatus;
Zigbee::DataType dataType; Zigbee::DataType dataType;
QByteArray data; QByteArray data;
} ZigbeeClusterAttributeReport; } ZigbeeClusterAttributeReport;
@ -75,29 +75,14 @@ public:
}; };
Q_ENUM(Direction) Q_ENUM(Direction)
explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeClusterLibrary::ClusterId clusterId, Direction direction, QObject *parent = nullptr);
// // Power configuration cluster 0x0001
// enum PowerConfigurationAttribute {
// PowerConfigurationAttributeMainsInformation = 0x0000,
// PowerConfigurationAttributeMainsSettings = 0x0001,
// PowerConfigurationAttributeBatteryInformation = 0x0002,
// PowerConfigurationAttributeBatterySettings = 0x0003,
// PowerConfigurationAttributeBatterySource2Information = 0x0004,
// PowerConfigurationAttributeBattterySource2Settings = 0x0005,
// PowerConfigurationAttributeBatterySource3Information = 0x0006,
// PowerConfigurationAttributeBattterySource3Settings = 0x0007
// };
// Q_ENUM(PowerConfigurationAttribute)
explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent = nullptr);
ZigbeeNode *node() const; ZigbeeNode *node() const;
ZigbeeNodeEndpoint *endpoint() const; ZigbeeNodeEndpoint *endpoint() const;
Direction direction() const; Direction direction() const;
Zigbee::ClusterId clusterId() const; ZigbeeClusterLibrary::ClusterId clusterId() const;
QString clusterName() const; QString clusterName() const;
QList<ZigbeeClusterAttribute> attributes() const; QList<ZigbeeClusterAttribute> attributes() const;
@ -106,13 +91,17 @@ public:
// ZCL global commands // ZCL global commands
ZigbeeClusterReply *readAttributes(QList<quint16> attributes); ZigbeeClusterReply *readAttributes(QList<quint16> attributes);
ZigbeeClusterReply *configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations);
protected: protected:
ZigbeeNetwork *m_network = nullptr; ZigbeeNetwork *m_network = nullptr;
ZigbeeNode *m_node = nullptr; ZigbeeNode *m_node = nullptr;
ZigbeeNodeEndpoint *m_endpoint= nullptr; ZigbeeNodeEndpoint *m_endpoint= nullptr;
Zigbee::ClusterId m_clusterId = Zigbee::ClusterIdUnknown; ZigbeeClusterLibrary::ClusterId m_clusterId = ZigbeeClusterLibrary::ClusterIdUnknown;
Direction m_direction = Server; Direction m_direction = Server;
QHash<quint16, ZigbeeClusterAttribute> m_attributes; QHash<quint16, ZigbeeClusterAttribute> m_attributes;
@ -120,6 +109,12 @@ protected:
ZigbeeNetworkRequest createGeneralRequest(); ZigbeeNetworkRequest createGeneralRequest();
quint8 m_transactionSequenceNumber = 0; quint8 m_transactionSequenceNumber = 0;
QHash<quint8, ZigbeeClusterReply *> m_pendingReplies; QHash<quint8, ZigbeeClusterReply *> m_pendingReplies;
// Global commands
ZigbeeClusterReply *executeGlobalCommand(quint8 command, const QByteArray &payload = QByteArray());
// Cluster specific
ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame); ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame);
ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray()); ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray());
bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply); bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply);

View File

@ -112,11 +112,11 @@ QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> ZigbeeClusterLibrary::par
// Read attribute id and status // Read attribute id and status
stream >> attributeId >> statusInt; stream >> attributeId >> statusInt;
Zigbee::ZigbeeStatus status = static_cast<Zigbee::ZigbeeStatus>(statusInt); ZigbeeClusterLibrary::Status status = static_cast<ZigbeeClusterLibrary::Status>(statusInt);
qCDebug(dcZigbeeClusterLibrary()) << "Parse:" << ZigbeeUtils::convertUint16ToHexString(attributeId) << status; qCDebug(dcZigbeeClusterLibrary()) << "Parse:" << ZigbeeUtils::convertUint16ToHexString(attributeId) << status;
if (status != Zigbee::ZigbeeStatusSuccess) { if (status != ZigbeeClusterLibrary::StatusSuccess) {
qCWarning(dcZigbeeCluster()) << "Attribute status record" << ZigbeeUtils::convertUint16ToHexString(attributeId) << "finished with error" << status; qCWarning(dcZigbeeCluster()) << "Attribute status record" << ZigbeeUtils::convertUint16ToHexString(attributeId) << "finished with error" << status;
// If not success, we are done and can continue with the next status record // If not success, we are done and can continue with the next status record
continue; continue;
@ -254,6 +254,45 @@ QByteArray ZigbeeClusterLibrary::buildFrame(const ZigbeeClusterLibrary::Frame &f
return buildHeader(frame.header) + frame.payload; return buildHeader(frame.header) + frame.payload;
} }
QByteArray ZigbeeClusterLibrary::buildAttributeReportingConfiguration(const ZigbeeClusterLibrary::AttributeReportingConfiguration &reportingConfiguration)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(reportingConfiguration.direction);
stream << reportingConfiguration.attributeId;
stream << static_cast<quint8>(reportingConfiguration.dataType);
stream << reportingConfiguration.minReportingInterval;
stream << reportingConfiguration.maxReportingInterval;
for (int i = 0; i < reportingConfiguration.reportableChange.count(); i++) {
stream << static_cast<quint8>(reportingConfiguration.reportableChange.at(i));
}
// Note: for reporting the timeoutPeriod is omitted
if (reportingConfiguration.direction == ReportingDirectionReceiving) {
stream << reportingConfiguration.timeoutPeriod;
}
return payload;
}
QList<ZigbeeClusterLibrary::AttributeReportingStatusRecord> ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(const QByteArray &payload)
{
QList<ZigbeeClusterLibrary::AttributeReportingStatusRecord> statusRecords;
QDataStream stream(payload);
stream.setByteOrder(QDataStream::LittleEndian);
while (!stream.atEnd()) {
ZigbeeClusterLibrary::AttributeReportingStatusRecord statusRecord;
quint8 status; quint8 direction = 0;
stream >> status >> direction >> statusRecord.attributeId;
statusRecord.direction = static_cast<ReportingDirection>(direction);
statusRecord.status = static_cast<ZigbeeClusterLibrary::Status>(status);
statusRecords.append(statusRecord);
}
return statusRecords;
}
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::FrameControl &frameControl) QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::FrameControl &frameControl)
{ {
debug.nospace() << "FrameControl("; debug.nospace() << "FrameControl(";
@ -305,3 +344,28 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusR
return debug.space(); return debug.space();
} }
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::AttributeReportingConfiguration &attributeReportingConfiguration)
{
debug.nospace() << "AttributeReportingConfiguration("
<< attributeReportingConfiguration.direction << ", "
<< ZigbeeUtils::convertUint16ToHexString(attributeReportingConfiguration.attributeId) << ", "
<< attributeReportingConfiguration.dataType << ", "
<< "Min interval: " << attributeReportingConfiguration.minReportingInterval << "[s], "
<< "Max interval: " << attributeReportingConfiguration.maxReportingInterval << "[s], "
<< "Change: " << ZigbeeUtils::convertByteArrayToHexString(attributeReportingConfiguration.reportableChange) << ", "
<< "Timeout period: " << attributeReportingConfiguration.timeoutPeriod << "[s]"
<< ")";
return debug.space();
}
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::AttributeReportingStatusRecord &attributeReportingStatusRecord)
{
debug.nospace() << "AttributeReportingConfiguration("
<< attributeReportingStatusRecord.status << ", "
<< attributeReportingStatusRecord.attributeId << ", "
<< attributeReportingStatusRecord.direction
<< ")";
return debug.space();
}

View File

@ -66,6 +66,133 @@ public:
}; };
Q_ENUM(Command) Q_ENUM(Command)
enum Status {
StatusSuccess = 0x00,
StatusFailure = 0x01,
StatusNotAuthorized = 0x7e,
StatusReservedFieldNotZero = 0x7f,
StatusMalformedCommand = 0x80,
StatusUnsupportedClusterCommand = 0x81,
StatusUnsupportedGeneralCommand = 0x82,
StatusUnsupportedManufacturerClusterCommand = 0x83,
StatusUnsupportedManufacturerGeneralCommand = 0x84,
StatusInvalidField = 0x85,
StatusUnsupportedAttribute = 0x86,
StatusInvalidValue = 0x87,
StatusReadOnly = 0x88,
StatusInsufficientSpace = 0x89,
StatusDuplicateExists = 0x8a,
StatusNotFound = 0x8b,
StatusUnreportableAttribute = 0x8c,
StatusInvalidDataType = 0x8d,
StatusInvalidSector = 0x8e,
StatusWriteOnly = 0x8f,
StatusInconsistentStartupState = 0x90,
StatusDefinedOutOfBand = 0x91,
StatusInconsistent = 0x92,
StatusActionDenied = 0x93,
StatusTimeout = 0x94,
StatusAbort = 0x95,
StatusInvalidImage = 0x96,
StatusWaitForData = 0x97,
StatusNoImageAvailable = 0x98,
StatusRequireMoreImage = 0x99,
StatusNotificationPending = 0x9a,
StatusHardwareFailure = 0xc0,
StatusSoftwareFailure = 0xc1,
StatusCalibrationError = 0xc2,
StatusUnsupportedCluster = 0xc3
};
Q_ENUM(Status)
enum ClusterId {
// Basics
ClusterIdUnknown = 0xffff,
ClusterIdBasic = 0x0000,
ClusterIdPowerConfiguration = 0x0001,
ClusterIdDeviceTemperature = 0x0002,
ClusterIdIdentify = 0x0003,
ClusterIdGroups = 0x0004,
ClusterIdScenes = 0x0005,
ClusterIdOnOff = 0x0006,
ClusterIdOnOffCOnfiguration = 0x0007,
ClusterIdLevelControl = 0x0008,
ClusterIdAlarms = 0x0009,
ClusterIdTime = 0x000A,
ClusterIdRssiLocation = 0x000B,
ClusterIdAnalogInputBasic = 0x000C,
ClusterIdAnalogOutputBasic = 0x000D,
ClusterIdValueBasic = 0x000E,
ClusterIdBinaryInputBasic = 0x000F,
ClusterIdBinaryOutputBasic = 0x0010,
ClusterIdBinaryValueBasic = 0x0011,
ClusterIdMultiStateInputBasic = 0x0012,
ClusterIdMultiStateOutputBasic = 0x0013,
ClusterIdMultiStateValueBasic = 0x0014,
ClusterIdCommissoning = 0x0015,
// Over the air uppgrade (OTA)
ClusterIdOtaUpgrade = 0x0019,
// Poll controll
ClusterIdPollControl = 0x0020,
// Closures
ClusterIdShadeConfiguration = 0x0100,
// Door Lock
ClusterIdDoorLock = 0x0101,
// Heating, Ventilation and Air-Conditioning (HVAC)
ClusterIdPumpConfigurationControl = 0x0200,
ClusterIdThermostat = 0x0201,
ClusterIdFanControll = 0x0202,
ClusterIdDehumiditationControll = 0x0203,
ClusterIdThermostatUserControll = 0x0204,
// Lighting
ClusterIdColorControl = 0x0300,
ClusterIdBallastConfiguration = 0x0301,
// Sensing
ClusterIdIlluminanceMeasurement = 0x0400,
ClusterIdIlluminanceLevelSensing = 0x0401,
ClusterIdTemperatureMeasurement = 0x0402,
ClusterIdPressureMeasurement = 0x0403,
ClusterIdFlowMeasurement = 0x0404,
ClusterIdRelativeHumidityMeasurement = 0x0405,
ClusterIdOccupancySensing = 0x0406,
// Security and Safty
ClusterIdIasZone = 0x0500,
ClusterIdIasAce = 0x0501,
ClusterIdIasWd = 0x0502,
// Smart energy
ClusterIdPrice = 0x0700,
ClusterIdLoadControl = 0x0701,
ClusterIdSimpleMetering = 0x0702,
// ZLL
ClusterIdTouchlinkCommissioning = 0x1000,
// NXP Appliances
ClusterIdApplianceControl = 0x001B,
ClusterIdApplianceIdentification = 0x0B00,
ClusterIdApplianceEventsAlerts = 0x0B02,
ClusterIdApplianceStatistics = 0x0B03,
// Electrical Measurement
ClusterIdElectricalMeasurement = 0x0B04,
ClusterIdDiagnostics = 0x0B05,
// Zigbee green power
ClusterIdGreenPower = 0x0021
};
Q_ENUM(ClusterId)
enum GlobalAttribute { enum GlobalAttribute {
GlobalAttributeClusterRevision = 0xfffd, GlobalAttributeClusterRevision = 0xfffd,
GlobalAttributeAttributeReportingStatus = 0xfffe GlobalAttributeAttributeReportingStatus = 0xfffe
@ -91,6 +218,12 @@ public:
}; };
Q_ENUM(Direction) Q_ENUM(Direction)
enum ReportingDirection {
ReportingDirectionReporting = 0x00,
ReportingDirectionReceiving = 0x01
};
Q_ENUM(ReportingDirection)
typedef struct FrameControl { typedef struct FrameControl {
FrameType frameType = FrameTypeGlobal; FrameType frameType = FrameTypeGlobal;
bool manufacturerSpecific = false; bool manufacturerSpecific = false;
@ -114,10 +247,28 @@ public:
// Read attribute // Read attribute
typedef struct ReadAttributeStatusRecord { typedef struct ReadAttributeStatusRecord {
quint16 attributeId; quint16 attributeId;
Zigbee::ZigbeeStatus attributeStatus; ZigbeeClusterLibrary::Status attributeStatus;
ZigbeeDataType dataType; ZigbeeDataType dataType;
} ReadAttributeStatusRecord; } ReadAttributeStatusRecord;
// Reporting attributes
typedef struct AttributeReportingConfiguration {
ReportingDirection direction = ReportingDirectionReporting;
quint16 attributeId = 0x0000;
Zigbee::DataType dataType = Zigbee::NoData;
quint16 minReportingInterval = 0x0000; // seconds
quint16 maxReportingInterval = 0x0000; // seconds
QByteArray reportableChange; // Data depending on the dataType
quint16 timeoutPeriod = 0x0000; // seconds, only used for direction receiving
} AttributeReportingConfiguration;
// Response of reporting configuration
typedef struct AttributeReportingStatusRecord {
ZigbeeClusterLibrary::Status status;
ReportingDirection direction = ReportingDirectionReporting;
quint16 attributeId = 0x0000;
} AttributeReportingStatusRecord;
// General parse/build methods // General parse/build methods
static quint8 buildFrameControlByte(const FrameControl &frameControl); static quint8 buildFrameControlByte(const FrameControl &frameControl);
@ -132,12 +283,21 @@ public:
static Frame parseFrameData(const QByteArray &frameData); static Frame parseFrameData(const QByteArray &frameData);
static QByteArray buildFrame(const Frame &frame); static QByteArray buildFrame(const Frame &frame);
// AttributeReportingConfiguration
static QByteArray buildAttributeReportingConfiguration(const AttributeReportingConfiguration &reportingConfiguration);
// TODO: parseAttributeReportingConfiguration
static QList<AttributeReportingStatusRecord> parseAttributeReportingStatusRecords(const QByteArray &payload);
}; };
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::FrameControl &frameControl); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::FrameControl &frameControl);
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Header &header); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Header &header);
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame);
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord); QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord);
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::AttributeReportingConfiguration &attributeReportingConfiguration);
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::AttributeReportingStatusRecord &attributeReportingStatusRecord);
#endif // ZIGBEECLUSTERLIBRARY_H #endif // ZIGBEECLUSTERLIBRARY_H

View File

@ -45,7 +45,7 @@ QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataConfirm &confirm)
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(confirm.destinationEndpoint) << ", "; debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(confirm.destinationEndpoint) << ", ";
debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(confirm.sourceEndpoint) << ", "; debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(confirm.sourceEndpoint) << ", ";
debug.nospace() << static_cast<Zigbee::ZigbeeStatus>(confirm.zigbeeStatusCode); debug.nospace() << static_cast<ZigbeeClusterLibrary::Status>(confirm.zigbeeStatusCode);
debug.nospace() << ")"; debug.nospace() << ")";
return debug.space(); return debug.space();
@ -76,7 +76,7 @@ QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataIndication &indication)
if (indication.profileId == static_cast<quint16>(Zigbee::ZigbeeProfileDevice)) { if (indication.profileId == static_cast<quint16>(Zigbee::ZigbeeProfileDevice)) {
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(indication.clusterId) << ", "; debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(indication.clusterId) << ", ";
} else { } else {
debug.nospace() << static_cast<Zigbee::ClusterId>(indication.clusterId) << ", "; debug.nospace() << static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId) << ", ";
} }
debug.nospace() << "ASDU: " << ZigbeeUtils::convertByteArrayToHexString(indication.asdu) << ", "; debug.nospace() << "ASDU: " << ZigbeeUtils::convertByteArrayToHexString(indication.asdu) << ", ";

View File

@ -74,113 +74,6 @@ public:
Q_ENUM(ZigbeeChannel) Q_ENUM(ZigbeeChannel)
Q_DECLARE_FLAGS(ZigbeeChannels, ZigbeeChannel) Q_DECLARE_FLAGS(ZigbeeChannels, ZigbeeChannel)
enum ClusterId {
// Basics
ClusterIdUnknown = 0xffff,
ClusterIdBasic = 0x0000,
ClusterIdPower = 0x0001,
ClusterIdDeviceTemperature = 0x0002,
ClusterIdIdentify = 0x0003,
ClusterIdGroups = 0x0004,
ClusterIdScenes = 0x0005,
ClusterIdOnOff = 0x0006,
ClusterIdOnOffCOnfiguration = 0x0007,
ClusterIdLevelControl = 0x0008,
ClusterIdAlarms = 0x0009,
ClusterIdTime = 0x000A,
ClusterIdRssiLocation = 0x000B,
ClusterIdAnalogInputBasic = 0x000C,
ClusterIdAnalogOutputBasic = 0x000D,
ClusterIdValueBasic = 0x000E,
ClusterIdBinaryInputBasic = 0x000F,
ClusterIdBinaryOutputBasic = 0x0010,
ClusterIdBinaryValueBasic = 0x0011,
ClusterIdMultiStateInputBasic = 0x0012,
ClusterIdMultiStateOutputBasic = 0x0013,
ClusterIdMultiStateValueBasic = 0x0014,
ClusterIdCommissoning = 0x0015,
// Over the air uppgrade (OTA)
ClusterIdOtaUpgrade = 0x0019,
// Poll controll
ClusterIdPollControl = 0x0020,
// Closures
ClusterIdShadeConfiguration = 0x0100,
// Door Lock
ClusterIdDoorLock = 0x0101,
// Heating, Ventilation and Air-Conditioning (HVAC)
ClusterIdPumpConfigurationControl = 0x0200,
ClusterIdThermostat = 0x0201,
ClusterIdFanControll = 0x0202,
ClusterIdDehumiditationControll = 0x0203,
ClusterIdThermostatUserControll = 0x0204,
// Lighting
ClusterIdColorControl = 0x0300,
ClusterIdBallastConfiguration = 0x0301,
// Sensing
ClusterIdIlluminanceMeasurement = 0x0400,
ClusterIdIlluminanceLevelSensing = 0x0401,
ClusterIdTemperatureMeasurement = 0x0402,
ClusterIdPressureMeasurement = 0x0403,
ClusterIdFlowMeasurement = 0x0404,
ClusterIdRelativeHumidityMeasurement = 0x0405,
ClusterIdOccupancySensing = 0x0406,
// Security and Safty
ClusterIdIasZone = 0x0500,
ClusterIdIasAce = 0x0501,
ClusterIdIasWd = 0x0502,
// Smart energy
ClusterIdPrice = 0x0700,
ClusterIdLoadControl = 0x0701,
ClusterIdSimpleMetering = 0x0702,
// ZLL
ClusterIdTouchlinkCommissioning = 0x1000,
// NXP Appliances
ClusterIdApplianceControl = 0x001B,
ClusterIdApplianceIdentification = 0x0B00,
ClusterIdApplianceEventsAlerts = 0x0B02,
ClusterIdApplianceStatistics = 0x0B03,
// Electrical Measurement
ClusterIdElectricalMeasurement = 0x0B04,
ClusterIdDiagnostics = 0x0B05,
// Zigbee green power
ClusterIdGreenPower = 0x0021
};
Q_ENUM(ClusterId)
enum ClusterAttributeBasic {
ClusterAttributeBasicZclVersion = 0x0000,
ClusterAttributeBasicApplicationVersion = 0x0001,
ClusterAttributeBasicStackVersion = 0x0002,
ClusterAttributeBasicHardwareVersion = 0x0003,
ClusterAttributeBasicManufacturerName = 0x0004,
ClusterAttributeBasicModelIdentifier = 0x0005,
ClusterAttributeBasicDataCode = 0x0006,
ClusterAttributeBasicPowerSource = 0x0007,
ClusterAttributeBasicLocationDescription = 0x0010,
ClusterAttributeBasicPhysicalEnvironment = 0x0011,
ClusterAttributeBasicDeviceEnabled = 0x0012,
ClusterAttributeBasicAlarmMask = 0x0013,
ClusterAttributeBasicDisableLocalConfig = 0x0014,
ClusterAttributeBasicSoftwareBuildId = 0x4000
};
Q_ENUM(ClusterAttributeBasic)
enum LightLinkDevice { enum LightLinkDevice {
// Lightning devices // Lightning devices
LightLinkDeviceOnOffLight = 0x0000, LightLinkDeviceOnOffLight = 0x0000,
@ -350,17 +243,6 @@ public:
}; };
Q_ENUM(SourceAddressMode) Q_ENUM(SourceAddressMode)
enum ZigbeeZclStatus {
};
Q_ENUM(ZigbeeZclStatus)
enum ZigbeeZdpStatus {
};
Q_ENUM(ZigbeeZdpStatus)
enum ZigbeeTxOption { enum ZigbeeTxOption {
ZigbeeTxOptionSecurityEnabled = 0x01, ZigbeeTxOptionSecurityEnabled = 0x01,
ZigbeeTxOptionUseNetworkKey = 0x02, ZigbeeTxOptionUseNetworkKey = 0x02,
@ -434,45 +316,6 @@ public:
}; };
Q_ENUM(ZigbeeApsStatus) Q_ENUM(ZigbeeApsStatus)
enum ZigbeeStatus {
ZigbeeStatusSuccess = 0x00,
ZigbeeStatusFailure = 0x01,
ZigbeeStatusNotAuthorized = 0x7e,
ZigbeeStatusReservedFieldNotZero = 0x7f,
ZigbeeStatusMalformedCommand = 0x80,
ZigbeeStatusUnsupportedClusterCommand = 0x81,
ZigbeeStatusUnsupportedGeneralCommand = 0x82,
ZigbeeStatusUnsupportedManufacturerClusterCommand = 0x83,
ZigbeeStatusUnsupportedManufacturerGeneralCommand = 0x84,
ZigbeeStatusInvalidField = 0x85,
ZigbeeStatusUnsupportedAttribute = 0x86,
ZigbeeStatusInvalidValue = 0x87,
ZigbeeStatusReadOnly = 0x88,
ZigbeeStatusInsufficientSpace = 0x89,
ZigbeeStatusDuplicateExists = 0x8a,
ZigbeeStatusNotFound = 0x8b,
ZigbeeStatusUnreportableAttribute = 0x8c,
ZigbeeStatusInvalidDataType = 0x8d,
ZigbeeStatusInvalidSector = 0x8e,
ZigbeeStatusWriteOnly = 0x8f,
ZigbeeStatusInconsistentStartupState = 0x90,
ZigbeeStatusDefinedOutOfBand = 0x91,
ZigbeeStatusInconsistent = 0x92,
ZigbeeStatusActionDenied = 0x93,
ZigbeeStatusTimeout = 0x94,
ZigbeeStatusAbort = 0x95,
ZigbeeStatusInvalidImage = 0x96,
ZigbeeStatusWaitForData = 0x97,
ZigbeeStatusNoImageAvailable = 0x98,
ZigbeeStatusRequireMoreImage = 0x99,
ZigbeeStatusNotificationPending = 0x9a,
ZigbeeStatusHardwareFailure = 0xc0,
ZigbeeStatusSoftwareFailure = 0xc1,
ZigbeeStatusCalibrationError = 0xc2,
ZigbeeStatusUnsupportedCluster = 0xc3
};
Q_ENUM(ZigbeeStatus)
// Basic struct for interface data. // Basic struct for interface data.
typedef struct ApsdeDataConfirm { typedef struct ApsdeDataConfirm {
quint8 requestId = 0; quint8 requestId = 0;

View File

@ -303,7 +303,7 @@ void ZigbeeNetwork::saveNetwork()
{ {
qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName; qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName;
QSettings settings(m_settingsFileName, QSettings::IniFormat, this); QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Network"); settings.beginGroup("ZigbeeNetwork");
settings.setValue("panId", panId()); settings.setValue("panId", panId());
settings.setValue("channel", channel()); settings.setValue("channel", channel());
settings.setValue("networkKey", securityConfiguration().networkKey().toString()); settings.setValue("networkKey", securityConfiguration().networkKey().toString());
@ -321,7 +321,7 @@ void ZigbeeNetwork::loadNetwork()
} }
QSettings settings(m_settingsFileName, QSettings::IniFormat, this); QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Network"); settings.beginGroup("ZigbeeNetwork");
quint16 panId = static_cast<quint16>(settings.value("panId", 0).toUInt()); quint16 panId = static_cast<quint16>(settings.value("panId", 0).toUInt());
setPanId(panId); setPanId(panId);
setChannel(settings.value("channel", 0).toUInt()); setChannel(settings.value("channel", 0).toUInt());
@ -535,6 +535,7 @@ void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state)
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender()); ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());
if (state == ZigbeeNode::StateInitialized && m_uninitializedNodes.contains(node)) { if (state == ZigbeeNode::StateInitialized && m_uninitializedNodes.contains(node)) {
m_uninitializedNodes.removeAll(node); m_uninitializedNodes.removeAll(node);
// Disconnect this slot since we don't need it any more
disconnect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged); disconnect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
addNode(node); addNode(node);
} }

View File

@ -55,6 +55,14 @@ ZigbeeNetworkDatabase::ZigbeeNetworkDatabase(ZigbeeNetwork *network, const QStri
} }
} }
ZigbeeNetworkDatabase::~ZigbeeNetworkDatabase()
{
if (m_db.isOpen()) {
qCDebug(dcZigbeeNetworkDatabase()) << "Closing database" << m_db.databaseName();
m_db.close();
}
}
QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes() QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
{ {
qCDebug(dcZigbeeNetworkDatabase()) << "Loading nodes from database" << m_db.databaseName(); qCDebug(dcZigbeeNetworkDatabase()) << "Loading nodes from database" << m_db.databaseName();
@ -93,7 +101,7 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
.arg(endpointId); .arg(endpointId);
QSqlQuery inputClustersQuery = m_db.exec(query); QSqlQuery inputClustersQuery = m_db.exec(query);
while (inputClustersQuery.next()) { while (inputClustersQuery.next()) {
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(inputClustersQuery.value("clusterId").toUInt()); ZigbeeClusterLibrary::ClusterId clusterId = static_cast<ZigbeeClusterLibrary::ClusterId>(inputClustersQuery.value("clusterId").toUInt());
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Server); ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Server);
endpoint->addInputCluster(cluster); endpoint->addInputCluster(cluster);
@ -122,8 +130,8 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
} }
// Set the basic cluster attributes if present // Set the basic cluster attributes if present
if (endpoint->hasInputCluster(Zigbee::ClusterIdBasic)) { if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic); ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeManufacturerName)) if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeManufacturerName))
endpoint->m_manufacturerName = basicCluster->attribute(ZigbeeClusterBasic::AttributeManufacturerName).dataType().toString(); endpoint->m_manufacturerName = basicCluster->attribute(ZigbeeClusterBasic::AttributeManufacturerName).dataType().toString();
@ -142,7 +150,7 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
.arg(endpointId); .arg(endpointId);
QSqlQuery outputClustersQuery = m_db.exec(query); QSqlQuery outputClustersQuery = m_db.exec(query);
while (outputClustersQuery.next()) { while (outputClustersQuery.next()) {
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(outputClustersQuery.value("clusterId").toUInt()); ZigbeeClusterLibrary::ClusterId clusterId = static_cast<ZigbeeClusterLibrary::ClusterId>(outputClustersQuery.value("clusterId").toUInt());
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Client); ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Client);
qCDebug(dcZigbeeNetworkDatabase()) << "Loaded" << cluster; qCDebug(dcZigbeeNetworkDatabase()) << "Loaded" << cluster;
endpoint->addOutputCluster(cluster); endpoint->addOutputCluster(cluster);
@ -178,70 +186,89 @@ bool ZigbeeNetworkDatabase::initDatabase()
return false; return false;
} }
// Write pragmas
m_db.exec("PRAGMA foreign_keys = ON;");
// FIXME: check schema version // FIXME: check schema version fro compatibility or migration
qCDebug(dcZigbeeNetworkDatabase()) << "Tables" << m_db.tables();
if (m_db.tables().isEmpty()) {
// Write pragmas
m_db.exec("PRAGMA foreign_keys = ON;");
m_db.exec(QString("PRAGMA schema_version = %1;").arg(DB_VERSION));
m_db.exec(QString("PRAGMA user_version = %1;").arg(DB_VERSION));
}
// Create nodes table // Create nodes table
createTable("nodes", if (!m_db.tables().contains("nodes")) {
"(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string createTable("nodes",
"shortAddress INTEGER NOT NULL, " // uint16 "(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string
"nodeDescriptor BLOB NOT NULL, " // bytes as received from the node "shortAddress INTEGER NOT NULL, " // uint16
"powerDescriptor INTEGER NOT NULL)"); // uint16 "nodeDescriptor BLOB NOT NULL, " // bytes as received from the node
createIndices("ieeeAddressIndex", "nodes", "ieeeAddress"); "powerDescriptor INTEGER NOT NULL)"); // uint16
createIndices("ieeeAddressIndex", "nodes", "ieeeAddress");
}
// Create endpoints table // Create endpoints table
createTable("endpoints", if (!m_db.tables().contains("endpoints")) {
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation createTable("endpoints",
"ieeeAddress INTEGER NOT NULL, " // // reference to nodes.ieeeAddress "(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
"endpointId INTEGER NOT NULL, " // uint8 "ieeeAddress INTEGER NOT NULL, " // // reference to nodes.ieeeAddress
"profileId INTEGER NOT NULL, " // uint16 "endpointId INTEGER NOT NULL, " // uint8
"deviceId INTEGER NOT NULL, " // uint16 "profileId INTEGER NOT NULL, " // uint16
"deviceVersion INTEGER, " // uint8 "deviceId INTEGER NOT NULL, " // uint16
"CONSTRAINT fk_ieeeAddress FOREIGN KEY(ieeeAddress) REFERENCES nodes(ieeeAddress) ON DELETE CASCADE)"); "deviceVersion INTEGER, " // uint8
createIndices("endpointIndex", "endpoints", "ieeeAddress, endpointId"); "CONSTRAINT fk_ieeeAddress FOREIGN KEY(ieeeAddress) REFERENCES nodes(ieeeAddress) ON DELETE CASCADE)");
createIndices("endpointIndex", "endpoints", "ieeeAddress, endpointId");
}
// Create server cluster table // Create server cluster table
createTable("serverClusters", if (!m_db.tables().contains("serverClusters")) {
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation createTable("serverClusters",
"endpointId INTEGER NOT NULL, " // reference to endpoint.id "(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
"clusterId INTEGER NOT NULL, " // uint16 "endpointId INTEGER NOT NULL, " // reference to endpoint.id
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)"); "clusterId INTEGER NOT NULL, " // uint16
createIndices("serverClusterIndex", "serverClusters", "endpointId, clusterId"); "CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
createIndices("serverClusterIndex", "serverClusters", "endpointId, clusterId");
}
// Create client cluster table // Create client cluster table
createTable("clientClusters", if (!m_db.tables().contains("clientClusters")) {
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation createTable("clientClusters",
"endpointId INTEGER NOT NULL, " // reference to endpoint.id "(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
"clusterId INTEGER NOT NULL, " // uint16 "endpointId INTEGER NOT NULL, " // reference to endpoint.id
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)"); "clusterId INTEGER NOT NULL, " // uint16
createIndices("clientClusterIndex", "clientClusters", "endpointId, clusterId"); "CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
createIndices("clientClusterIndex", "clientClusters", "endpointId, clusterId");
}
// Create cluster attributes table // Create cluster attributes table
createTable("attributes", if (!m_db.tables().contains("attributes")) {
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation createTable("attributes",
"clusterId INTEGER NOT NULL, " // reference to serverClusters.id "(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
"attributeId INTEGER NOT NULL, " // uint16 "clusterId INTEGER NOT NULL, " // reference to serverClusters.id
"dataType INTEGER NOT NULL, " // uint8 "attributeId INTEGER NOT NULL, " // uint16
"data BLOB NOT NULL, " // raw data from attribute "dataType INTEGER NOT NULL, " // uint8
"CONSTRAINT fk_cluster FOREIGN KEY(clusterId) REFERENCES serverClusters(id) ON DELETE CASCADE)"); "data BLOB NOT NULL, " // raw data from attribute
createIndices("attributesIndex", "attributes", "clusterId, attributeId"); "CONSTRAINT fk_cluster FOREIGN KEY(clusterId) REFERENCES serverClusters(id) ON DELETE CASCADE)");
createIndices("attributesIndex", "attributes", "clusterId, attributeId");
}
return true; return true;
} }
void ZigbeeNetworkDatabase::createTable(const QString &tableName, const QString &schema) void ZigbeeNetworkDatabase::createTable(const QString &tableName, const QString &schema)
{ {
m_db.exec(QString("CREATE TABLE IF NOT EXISTS %1 %2;").arg(tableName).arg(schema)); qCDebug(dcZigbeeNetworkDatabase()) << "Creating table" << tableName << schema;
m_db.exec(QString("PRAGMA schema_version = %1;").arg(DB_VERSION)); QString query = QString("CREATE TABLE IF NOT EXISTS %1 %2;").arg(tableName).arg(schema);
m_db.exec(QString("PRAGMA user_version = %1;").arg(DB_VERSION)); m_db.exec(query);
if (m_db.lastError().type() != QSqlError::NoError) {
qCWarning(dcZigbeeNetworkDatabase()) << "Could not create table in database." << query << m_db.lastError().databaseText() << m_db.lastError().driverText();
return;
}
} }
void ZigbeeNetworkDatabase::createIndices(const QString &indexName, const QString &tableName, const QString &columns) void ZigbeeNetworkDatabase::createIndices(const QString &indexName, const QString &tableName, const QString &columns)
{ {
qCDebug(dcZigbeeNetworkDatabase()) << "Creating table indices" << indexName << tableName << columns;
m_db.exec(QString("CREATE UNIQUE INDEX IF NOT EXISTS %1 ON %2(%3);").arg(indexName).arg(tableName).arg(columns)); m_db.exec(QString("CREATE UNIQUE INDEX IF NOT EXISTS %1 ON %2(%3);").arg(indexName).arg(tableName).arg(columns));
} }
@ -256,9 +283,10 @@ bool ZigbeeNetworkDatabase::saveNodeEndpoint(ZigbeeNodeEndpoint *endpoint)
.arg(static_cast<quint16>(endpoint->deviceId())) .arg(static_cast<quint16>(endpoint->deviceId()))
.arg(static_cast<quint8>(endpoint->deviceVersion())); .arg(static_cast<quint8>(endpoint->deviceVersion()));
qCDebug(dcZigbeeNetworkDatabase()) << queryString;
m_db.exec(queryString); m_db.exec(queryString);
if (m_db.lastError().type() != QSqlError::NoError) { if (m_db.lastError().type() != QSqlError::NoError) {
qCWarning(dcZigbeeNetworkDatabase()) << "Could not save node into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); qCWarning(dcZigbeeNetworkDatabase()) << "Could not save endpoint into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText();
return false; return false;
} }
@ -378,7 +406,7 @@ bool ZigbeeNetworkDatabase::removeNode(ZigbeeNode *node)
{ {
qCDebug(dcZigbeeNetworkDatabase()) << "Remove" << node; qCDebug(dcZigbeeNetworkDatabase()) << "Remove" << node;
// Note: cascade delete will clean up all other tables // Note: cascade delete will clean up all other tables
QString queryString = QString("DELETE FROM nodes WHERE ieeeAddress = %1;").arg(node->extendedAddress().toString()); QString queryString = QString("DELETE FROM nodes WHERE ieeeAddress = \"%1\";").arg(node->extendedAddress().toString());
m_db.exec(queryString); m_db.exec(queryString);
if (m_db.lastError().type() != QSqlError::NoError) { if (m_db.lastError().type() != QSqlError::NoError) {
qCWarning(dcZigbeeNetworkDatabase()) << "Could not remove node from database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); qCWarning(dcZigbeeNetworkDatabase()) << "Could not remove node from database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText();

View File

@ -44,6 +44,7 @@ class ZigbeeNetworkDatabase : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ZigbeeNetworkDatabase(ZigbeeNetwork *network, const QString &databaseName, QObject *parent = nullptr); explicit ZigbeeNetworkDatabase(ZigbeeNetwork *network, const QString &databaseName, QObject *parent = nullptr);
~ZigbeeNetworkDatabase();
QList<ZigbeeNode *> loadNodes(); QList<ZigbeeNode *> loadNodes();
bool wipeDatabase(); bool wipeDatabase();

View File

@ -32,6 +32,11 @@
#include <QDateTime> #include <QDateTime>
QStringList ZigbeeNetworkManager::availableBackendTypes()
{
return {"deCONZ"};
}
ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::BackendType backend, QObject *parent) ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::BackendType backend, QObject *parent)
{ {
// Note: required for generating random PAN ID // Note: required for generating random PAN ID

View File

@ -25,8 +25,8 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEEMANAGER_H #ifndef ZIGBEENETWORKMANAGER_H
#define ZIGBEEMANAGER_H #define ZIGBEENETWORKMANAGER_H
#include <QObject> #include <QObject>
@ -39,7 +39,9 @@ public:
BackendTypeDeconz BackendTypeDeconz
}; };
static QStringList availableBackendTypes();
static ZigbeeNetwork *createZigbeeNetwork(BackendType backend, QObject *parent = nullptr); static ZigbeeNetwork *createZigbeeNetwork(BackendType backend, QObject *parent = nullptr);
}; };
#endif // ZIGBEEMANAGER_H #endif // ZIGBEENETWORKMANAGER_H

View File

@ -151,7 +151,7 @@ QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request)
if (request.profileId() == Zigbee::ZigbeeProfileDevice) { if (request.profileId() == Zigbee::ZigbeeProfileDevice) {
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(request.clusterId()) << ", "; debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(request.clusterId()) << ", ";
} else { } else {
debug.nospace() << static_cast<Zigbee::ClusterId>(request.clusterId()) << ", "; debug.nospace() << static_cast<ZigbeeClusterLibrary::ClusterId>(request.clusterId()) << ", ";
} }
if (request.destinationAddressMode() == Zigbee::DestinationAddressModeGroup) if (request.destinationAddressMode() == Zigbee::DestinationAddressModeGroup)

View File

@ -280,7 +280,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
if (m_requestRetry < 3) { if (m_requestRetry < 3) {
m_requestRetry++; m_requestRetry++;
qCDebug(dcZigbeeNode()) << "Retry to request simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << m_requestRetry << "/" << "3 attempts."; qCDebug(dcZigbeeNode()) << "Retry to request simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << m_requestRetry << "/" << "3 attempts.";
initEndpoints(); initEndpoint(endpointId);
} else { } else {
qCWarning(dcZigbeeNode()) << "Failed to read simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << "after 3 attempts. Giving up."; qCWarning(dcZigbeeNode()) << "Failed to read simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << "after 3 attempts. Giving up.";
m_requestRetry = 0; m_requestRetry = 0;
@ -338,10 +338,10 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
for (int i = 0; i < inputClusterCount; i++) { for (int i = 0; i < inputClusterCount; i++) {
quint16 clusterId = 0; quint16 clusterId = 0;
stream >> clusterId; stream >> clusterId;
if (!endpoint->hasInputCluster(static_cast<Zigbee::ClusterId>(clusterId))) { if (!endpoint->hasInputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId))) {
endpoint->addInputCluster(endpoint->createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Server)); endpoint->addInputCluster(endpoint->createCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId), ZigbeeCluster::Server));
} }
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId)); qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId));
} }
// Parse and add client clusters // Parse and add client clusters
@ -350,10 +350,10 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
for (int i = 0; i < outputClusterCount; i++) { for (int i = 0; i < outputClusterCount; i++) {
quint16 clusterId = 0; quint16 clusterId = 0;
stream >> clusterId; stream >> clusterId;
if (!endpoint->hasOutputCluster(static_cast<Zigbee::ClusterId>(clusterId))) { if (!endpoint->hasOutputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId))) {
endpoint->addOutputCluster(endpoint->createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Client)); endpoint->addOutputCluster(endpoint->createCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId), ZigbeeCluster::Client));
} }
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId)); qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId));
} }
m_uninitializedEndpoints.removeAll(endpointId); m_uninitializedEndpoints.removeAll(endpointId);
@ -380,7 +380,7 @@ void ZigbeeNode::initBasicCluster()
// Get the first endpoint which implements the basic cluster // Get the first endpoint which implements the basic cluster
ZigbeeNodeEndpoint *endpoint = nullptr; ZigbeeNodeEndpoint *endpoint = nullptr;
foreach (ZigbeeNodeEndpoint *ep, endpoints()) { foreach (ZigbeeNodeEndpoint *ep, endpoints()) {
if (ep->hasInputCluster(Zigbee::ClusterIdBasic)) { if (ep->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
endpoint = ep; endpoint = ep;
break; break;
} }
@ -392,7 +392,7 @@ void ZigbeeNode::initBasicCluster()
return; return;
} }
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic); ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
if (!basicCluster) { if (!basicCluster) {
qCWarning(dcZigbeeNode()) << "Could not find basic cluster on" << this << "Set the node to initialized anyways."; qCWarning(dcZigbeeNode()) << "Could not find basic cluster on" << this << "Set the node to initialized anyways.";
// Set the device initialized any ways since this ist just for convinience // Set the device initialized any ways since this ist just for convinience
@ -527,6 +527,11 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster)
// Finished with reading basic cluster, the node is initialized. // Finished with reading basic cluster, the node is initialized.
// TODO: read other interesting cluster information // TODO: read other interesting cluster information
// Bind client clusters to the sensor group
// Configure reporting
setState(StateInitialized); setState(StateInitialized);
}); });
} }

View File

@ -114,6 +114,9 @@ private:
void readModelIdentifier(ZigbeeClusterBasic *basicCluster); void readModelIdentifier(ZigbeeClusterBasic *basicCluster);
void readSoftwareBuildId(ZigbeeClusterBasic *basicCluster); void readSoftwareBuildId(ZigbeeClusterBasic *basicCluster);
signals: signals:
void nodeInitializationFailed(); void nodeInitializationFailed();
void stateChanged(State state); void stateChanged(State state);

View File

@ -97,12 +97,12 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::inputClusters() const
return m_inputClusters.values(); return m_inputClusters.values();
} }
ZigbeeCluster *ZigbeeNodeEndpoint::getInputCluster(Zigbee::ClusterId clusterId) const ZigbeeCluster *ZigbeeNodeEndpoint::getInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
{ {
return m_inputClusters.value(clusterId); return m_inputClusters.value(clusterId);
} }
bool ZigbeeNodeEndpoint::hasInputCluster(Zigbee::ClusterId clusterId) const bool ZigbeeNodeEndpoint::hasInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
{ {
return m_inputClusters.keys().contains(clusterId); return m_inputClusters.keys().contains(clusterId);
} }
@ -112,12 +112,12 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::outputClusters() const
return m_outputClusters.values(); return m_outputClusters.values();
} }
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
{ {
return m_outputClusters.value(clusterId); return m_outputClusters.value(clusterId);
} }
bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const bool ZigbeeNodeEndpoint::hasOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
{ {
return m_outputClusters.keys().contains(clusterId); return m_outputClusters.keys().contains(clusterId);
} }
@ -163,48 +163,52 @@ void ZigbeeNodeEndpoint::setSoftwareBuildId(const QString &softwareBuildId)
emit softwareBuildIdChanged(m_softwareBuildId); emit softwareBuildIdChanged(m_softwareBuildId);
} }
ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction) ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(ZigbeeClusterLibrary::ClusterId clusterId, ZigbeeCluster::Direction direction)
{ {
switch (clusterId) { switch (clusterId) {
// General // General
case Zigbee::ClusterIdBasic: case ZigbeeClusterLibrary::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: case ZigbeeClusterLibrary::ClusterIdPowerConfiguration:
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this); return new ZigbeeClusterPowerConfiguration(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdIdentify: case ZigbeeClusterLibrary::ClusterIdIdentify:
return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this); return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdLevelControl: case ZigbeeClusterLibrary::ClusterIdOnOff:
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
break;
case ZigbeeClusterLibrary::ClusterIdLevelControl:
return new ZigbeeClusterLevelControl(m_network, m_node, this, direction, this); return new ZigbeeClusterLevelControl(m_network, m_node, this, direction, this);
break; break;
// Measurement // Measurement
case Zigbee::ClusterIdTemperatureMeasurement: case ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement:
return new ZigbeeClusterIlluminanceMeasurment(m_network, m_node, this, direction, this);
break;
case ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement:
return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this); return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdRelativeHumidityMeasurement: case ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement:
return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this); return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdOccupancySensing: case ZigbeeClusterLibrary::ClusterIdOccupancySensing:
return new ZigbeeClusterOccupancySensing(m_network, m_node, this, direction, this); return new ZigbeeClusterOccupancySensing(m_network, m_node, this, direction, this);
break; break;
case Zigbee::ClusterIdIlluminanceMeasurement:
return new ZigbeeClusterIlluminanceMeasurment(m_network, m_node, this, direction, this);
break;
// Lighting // Lighting
case Zigbee::ClusterIdColorControl: case ZigbeeClusterLibrary::ClusterIdColorControl:
return new ZigbeeClusterColorControl(m_network, m_node, this, direction, this); return new ZigbeeClusterColorControl(m_network, m_node, this, direction, this);
break; break;
// Security // Security
case Zigbee::ClusterIdIasZone: case ZigbeeClusterLibrary::ClusterIdIasZone:
return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this); return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this);
break; break;
default: default:
// Return a default cluster since we have no special implementation for this cluster // Return a default cluster since we have no special implementation for this cluster, allowing to use generic clusters operations
return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this); return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this);
} }
} }
@ -237,18 +241,18 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
switch (frame.header.frameControl.direction) { switch (frame.header.frameControl.direction) {
case ZigbeeClusterLibrary::DirectionClientToServer: case ZigbeeClusterLibrary::DirectionClientToServer:
// Get the output/client cluster this indication is coming from // Get the output/client cluster this indication is coming from
cluster = getOutputCluster(static_cast<Zigbee::ClusterId>(indication.clusterId)); cluster = getOutputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId));
if (!cluster) { if (!cluster) {
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Client); cluster = createCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId), ZigbeeCluster::Client);
qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster; qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster;
addOutputCluster(cluster); addOutputCluster(cluster);
} }
break; break;
case ZigbeeClusterLibrary::DirectionServerToClient: case ZigbeeClusterLibrary::DirectionServerToClient:
// Get the input/server cluster this indication is coming from // Get the input/server cluster this indication is coming from
cluster = getInputCluster(static_cast<Zigbee::ClusterId>(indication.clusterId)); cluster = getInputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId));
if (!cluster) { if (!cluster) {
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Server); cluster = createCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId), ZigbeeCluster::Server);
qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster; qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster;
addInputCluster(cluster); addInputCluster(cluster);
} }

View File

@ -41,6 +41,7 @@
#include "zcl/general/zigbeeclusteronoff.h" #include "zcl/general/zigbeeclusteronoff.h"
#include "zcl/general/zigbeeclusteridentify.h" #include "zcl/general/zigbeeclusteridentify.h"
#include "zcl/general/zigbeeclusterlevelcontrol.h" #include "zcl/general/zigbeeclusterlevelcontrol.h"
#include "zcl/general/zigbeeclusterpowerconfiguration.h"
#include "zcl/measurement/zigbeeclusteroccupancysensing.h" #include "zcl/measurement/zigbeeclusteroccupancysensing.h"
#include "zcl/measurement/zigbeeclusterilluminancemeasurment.h" #include "zcl/measurement/zigbeeclusterilluminancemeasurment.h"
@ -85,17 +86,17 @@ public:
// Server clusters // Server clusters
QList<ZigbeeCluster *> inputClusters() const; QList<ZigbeeCluster *> inputClusters() const;
ZigbeeCluster *getInputCluster(Zigbee::ClusterId clusterId) const; ZigbeeCluster *getInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
bool hasInputCluster(Zigbee::ClusterId clusterId) const; bool hasInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
// Client clusters // Client clusters
QList<ZigbeeCluster *> outputClusters() const; QList<ZigbeeCluster *> outputClusters() const;
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const; ZigbeeCluster *getOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
bool hasOutputCluster(Zigbee::ClusterId clusterId) const; bool hasOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
// Convinience cast methods for getting a specific cluster object // Convinience cast methods for getting a specific cluster object
template<typename T> template<typename T>
inline T* inputCluster(Zigbee::ClusterId clusterId) inline T* inputCluster(ZigbeeClusterLibrary::ClusterId clusterId)
{ {
if (!hasInputCluster(clusterId)) if (!hasInputCluster(clusterId))
return nullptr; return nullptr;
@ -104,7 +105,7 @@ public:
} }
template<typename T> template<typename T>
inline T* outputCluster(Zigbee::ClusterId clusterId) inline T* outputCluster(ZigbeeClusterLibrary::ClusterId clusterId)
{ {
if (!hasOutputCluster(clusterId)) if (!hasOutputCluster(clusterId))
return nullptr; return nullptr;
@ -124,8 +125,8 @@ private:
quint8 m_deviceVersion = 0; quint8 m_deviceVersion = 0;
bool m_initialized = false; bool m_initialized = false;
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_inputClusters; QHash<ZigbeeClusterLibrary::ClusterId, ZigbeeCluster *> m_inputClusters;
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_outputClusters; QHash<ZigbeeClusterLibrary::ClusterId, ZigbeeCluster *> m_outputClusters;
QString m_manufacturerName; QString m_manufacturerName;
QString m_modelIdentifier; QString m_modelIdentifier;
@ -135,7 +136,7 @@ private:
void setModelIdentifier(const QString &modelIdentifier); void setModelIdentifier(const QString &modelIdentifier);
void setSoftwareBuildId(const QString &softwareBuildId); void setSoftwareBuildId(const QString &softwareBuildId);
ZigbeeCluster *createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction); ZigbeeCluster *createCluster(ZigbeeClusterLibrary::ClusterId clusterId, ZigbeeCluster::Direction direction);
void addInputCluster(ZigbeeCluster *cluster); void addInputCluster(ZigbeeCluster *cluster);
void addOutputCluster(ZigbeeCluster *cluster); void addOutputCluster(ZigbeeCluster *cluster);

View File

@ -34,24 +34,7 @@
#include <math.h> #include <math.h>
// Disabling 1000 to 2500 K, as we never want to go into full red for color temp
static QList<QColor> colorTemperatureScale = { static QList<QColor> colorTemperatureScale = {
// QColor(255, 56, 0), // 1000 K
// QColor(255, 71, 0),
// QColor(255, 83, 0),
// QColor(255, 93, 0),
// QColor(255, 101, 0),
// QColor(255, 109, 0),
// QColor(255, 115, 0),
// QColor(255, 121, 0),
// QColor(255, 126, 0),
// QColor(255, 131, 0),
// QColor(255, 138, 18),
// QColor(255, 142, 33),
// QColor(255, 147, 44),
// QColor(255, 152, 54),
// QColor(255, 157, 63),
// QColor(255, 161, 72), // 2500K
QColor(255, 165, 79), QColor(255, 165, 79),
QColor(255, 169, 87), QColor(255, 169, 87),
QColor(255, 173, 94), QColor(255, 173, 94),
@ -260,23 +243,12 @@ QString ZigbeeUtils::convertUint64ToHexString(const quint64 &value)
return QString("0x%1").arg(convertByteArrayToHexString(data).remove(" ").remove("0x")); return QString("0x%1").arg(convertByteArrayToHexString(data).remove(" ").remove("0x"));
} }
//QString ZigbeeUtils::messageTypeToString(const Zigbee::InterfaceMessageType &type) QString ZigbeeUtils::clusterIdToString(const ZigbeeClusterLibrary::ClusterId &clusterId)
//{
// QMetaObject metaObject = Zigbee::staticMetaObject;
// QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("InterfaceMessageType"));
// QString enumString = metaEnum.valueToKey(type);
// return enumString.remove("Zigbee::InterfaceMessageType(MessageType").remove(")");
//}
QString ZigbeeUtils::clusterIdToString(const Zigbee::ClusterId &clusterId)
{ {
QMetaObject metaObject = Zigbee::staticMetaObject; QMetaObject metaObject = ZigbeeClusterLibrary::staticMetaObject;
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ClusterId")); QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ClusterId"));
QString enumString = metaEnum.valueToKey(clusterId); QString enumString = metaEnum.valueToKey(clusterId);
QString clusterName = enumString.remove("Zigbee::ClusterId(ClusterId").remove(")").append(QString("(%1)").arg(ZigbeeUtils::convertUint16ToHexString(clusterId))); QString clusterName = enumString.remove("ZigbeeClusterLibrary::ClusterId(ClusterId").remove(")");
if (clusterName.isEmpty()) if (clusterName.isEmpty())
clusterName = "Unknown"; clusterName = "Unknown";
@ -287,9 +259,7 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
{ {
QMetaObject metaObject = Zigbee::staticMetaObject; QMetaObject metaObject = Zigbee::staticMetaObject;
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ZigbeeProfile")); QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ZigbeeProfile"));
QString enumString = metaEnum.valueToKey(profileId); QString enumString = metaEnum.valueToKey(profileId);
return enumString.remove("Zigbee::ZigbeeProfile(ZigbeeProfile").remove(")"); return enumString.remove("Zigbee::ZigbeeProfile(ZigbeeProfile").remove(")");
} }
@ -330,6 +300,12 @@ QPointF ZigbeeUtils::convertColorToXY(const QColor &color)
return QPointF(x, y); return QPointF(x, y);
} }
QPoint ZigbeeUtils::convertColorToXYInt(const QColor &color)
{
QPointF xyColor = convertColorToXY(color);
return QPoint(qRound(xyColor.x() * 65536), qRound(xyColor.y() * 65536));
}
QColor ZigbeeUtils::convertXYToColor(const QPointF &xyColor) QColor ZigbeeUtils::convertXYToColor(const QPointF &xyColor)
{ {
// https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ // https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/
@ -429,81 +405,3 @@ QColor ZigbeeUtils::interpolateColorFromColorTemperature(int colorTemperature, i
// FIXME: interpolate between the selected index and the next color for more accuracy if required // FIXME: interpolate between the selected index and the next color for more accuracy if required
return colorTemperatureScale.at(closestColorIndex); return colorTemperatureScale.at(closestColorIndex);
} }
ZigbeeClusterAttributeReport ZigbeeUtils::parseAttributeReport(const QByteArray &data)
{
QByteArray dataCopy = data;
quint8 sequenceNumber = 0;
quint16 sourceAddress = 0;
quint8 endpointId = 0;
quint16 clusterId = 0;
quint16 attributeId = 0;
quint8 attributeStatus = 0;
quint8 attributDataType = 0;
quint16 dataSize = 0;
QDataStream stream(&dataCopy, QIODevice::ReadOnly);
stream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributeStatus >> attributDataType >> dataSize;
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
QByteArray attributeData = data.right(dataSize);
if (attributeData.length() != dataSize) {
//qCWarning(dcZigbeeNetwork()) << "HACK" << attributeData.length() << "!=" << dataSize;
// Note: the NXP firmware for JN5169 has a bug here and does not send the attributeStatus.
// Repars data without attribute status
sequenceNumber = 0;
sourceAddress = 0;
endpointId = 0;
clusterId = 0;
attributeId = 0;
attributeStatus = 0;
attributDataType = 0;
dataSize = 0;
QDataStream alternativeStream(&dataCopy, QIODevice::ReadOnly);
alternativeStream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributDataType >> dataSize;
dataType = static_cast<Zigbee::DataType>(attributDataType);
attributeData = data.right(dataSize);
}
// qCDebug(dcZigbeeNetwork()) << "Attribute read response:";
// qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
// qCDebug(dcZigbeeNetwork()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress);
// qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endpointId);
// qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
// qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
// qCDebug(dcZigbeeNetwork()) << " Attribut status:" << static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
// qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
// qCDebug(dcZigbeeNetwork()) << " Attribut size:" << dataSize;
// qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(attributeData);
// switch (dataType) {
// case Zigbee::CharString:
// qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(attributeData);
// break;
// case Zigbee::Bool:
// qCDebug(dcZigbeeNetwork()) << " Data(converted)" << static_cast<bool>(attributeData.at(0));
// break;
// default:
// break;
// }
// ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(sourceAddress));
// if (!node) {
// qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
// return;
// }
ZigbeeClusterAttributeReport attributeReport;
attributeReport.sourceAddress = sourceAddress;
attributeReport.endpointId = endpointId;
attributeReport.clusterId = static_cast<Zigbee::ClusterId>(clusterId);
attributeReport.attributeId = attributeId;
attributeReport.attributeStatus = static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
attributeReport.dataType = dataType;
attributeReport.data = attributeData;
return attributeReport;
}

View File

@ -29,6 +29,7 @@
#define ZIGBEEUTILS_H #define ZIGBEEUTILS_H
#include <QColor> #include <QColor>
#include <QPoint>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QPointF> #include <QPointF>
@ -39,7 +40,6 @@
#include "zigbeedatatype.h" #include "zigbeedatatype.h"
#include "zcl/zigbeecluster.h" #include "zcl/zigbeecluster.h"
class ZigbeeUtils class ZigbeeUtils
{ {
Q_GADGET Q_GADGET
@ -63,7 +63,7 @@ public:
// Enum prittify print methods // Enum prittify print methods
//static QString messageTypeToString(const Zigbee::InterfaceMessageType &type); //static QString messageTypeToString(const Zigbee::InterfaceMessageType &type);
static QString clusterIdToString(const Zigbee::ClusterId &clusterId); static QString clusterIdToString(const ZigbeeClusterLibrary::ClusterId &clusterId);
static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId); static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId);
// Generate random data // Generate random data
@ -71,14 +71,13 @@ public:
// Color converter // Color converter
static QPointF convertColorToXY(const QColor &color); static QPointF convertColorToXY(const QColor &color);
static QPoint convertColorToXYInt(const QColor &color);
static QColor convertXYToColor(const QPointF &xyColor); static QColor convertXYToColor(const QPointF &xyColor);
static QColor convertXYToColor(quint16 x, quint16 y); static QColor convertXYToColor(quint16 x, quint16 y);
// Color temperature interpolation // Color temperature interpolation
static QColor interpolateColorFromColorTemperature(int colorTemperature, int minValue, int maxValue); static QColor interpolateColorFromColorTemperature(int colorTemperature, int minValue, int maxValue);
static ZigbeeClusterAttributeReport parseAttributeReport(const QByteArray &data);
}; };
#endif // ZIGBEEUTILS_H #endif // ZIGBEEUTILS_H