Implement power configuration cluster
This commit is contained in:
parent
0992028a8a
commit
cdd7a1a1aa
22
README.md
22
README.md
@ -9,8 +9,10 @@ Depending on your available hardware following gateway modules are supported
|
||||
|
||||
## NXP
|
||||
|
||||
* JN5168 (SoM)
|
||||
* JN5169 (USB Stick)
|
||||
> Note: the firmware erquires an entire rework and implement the APS layer
|
||||
|
||||
* ~~JN5168 (SoM)~~
|
||||
* ~~JN5169 (USB Stick)~~
|
||||
|
||||
## deCONZ
|
||||
|
||||
@ -20,15 +22,11 @@ Depending on your available hardware following gateway modules are supported
|
||||
* 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
@ -11,6 +11,7 @@ SOURCES += \
|
||||
zcl/general/zigbeeclusteridentify.cpp \
|
||||
zcl/general/zigbeeclusterlevelcontrol.cpp \
|
||||
zcl/general/zigbeeclusteronoff.cpp \
|
||||
zcl/general/zigbeeclusterpowerconfiguration.cpp \
|
||||
zcl/lighting/zigbeeclustercolorcontrol.cpp \
|
||||
zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \
|
||||
zcl/measurement/zigbeeclusteroccupancysensing.cpp \
|
||||
@ -61,6 +62,7 @@ HEADERS += \
|
||||
zcl/general/zigbeeclusteridentify.h \
|
||||
zcl/general/zigbeeclusterlevelcontrol.h \
|
||||
zcl/general/zigbeeclusteronoff.h \
|
||||
zcl/general/zigbeeclusterpowerconfiguration.h \
|
||||
zcl/lighting/zigbeeclustercolorcontrol.h \
|
||||
zcl/measurement/zigbeeclusterilluminancemeasurment.h \
|
||||
zcl/measurement/zigbeeclusteroccupancysensing.h \
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h
Normal file
101
libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h
Normal 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
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
qCDebug(dcZigbeeCluster()) << "Move to color" << colorX << colorY << transitionTime << "1/10 s";
|
||||
QByteArray payload;
|
||||
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
@ -132,6 +133,8 @@ ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepColor(quint16 stepX, q
|
||||
|
||||
ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColorTemperature(quint16 colorTemperatureMireds, quint16 transitionTime)
|
||||
{
|
||||
qCDebug(dcZigbeeCluster()) << "Move to color temperature" << colorTemperatureMireds << transitionTime << "1/10 s";
|
||||
|
||||
QByteArray payload;
|
||||
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "zigbeenetwork.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "zigbeenetwork.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "zigbeenetwork.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "zigbeenetwork.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include <QDataStream>
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
#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),
|
||||
m_network(network),
|
||||
m_node(node),
|
||||
@ -61,14 +61,14 @@ ZigbeeCluster::Direction ZigbeeCluster::direction() const
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
Zigbee::ClusterId ZigbeeCluster::clusterId() const
|
||||
ZigbeeClusterLibrary::ClusterId ZigbeeCluster::clusterId() const
|
||||
{
|
||||
return m_clusterId;
|
||||
}
|
||||
|
||||
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
|
||||
@ -105,6 +105,32 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> 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
|
||||
ZigbeeNetworkRequest request = createGeneralRequest();
|
||||
|
||||
@ -124,17 +150,9 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
|
||||
// ZCL header
|
||||
ZigbeeClusterLibrary::Header header;
|
||||
header.frameControl = frameControl;
|
||||
header.command = ZigbeeClusterLibrary::CommandReadAttributes;
|
||||
header.command = command;
|
||||
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
|
||||
ZigbeeClusterLibrary::Frame frame;
|
||||
frame.header = header;
|
||||
@ -163,6 +181,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
|
||||
return zclReply;
|
||||
}
|
||||
|
||||
|
||||
ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame)
|
||||
{
|
||||
ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this);
|
||||
@ -198,6 +217,7 @@ ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const Q
|
||||
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
|
||||
|
||||
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
|
||||
qCDebug(dcZigbeeCluster()) << "Executing command" << ZigbeeUtils::convertByteToHexString(command) << ZigbeeUtils::convertByteArrayToHexString(payload);
|
||||
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
|
||||
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
|
||||
if (!verifyNetworkError(zclReply, networkReply)) {
|
||||
|
||||
@ -48,9 +48,9 @@ struct ZigbeeClusterReportConfigurationRecord {
|
||||
typedef struct ZigbeeClusterAttributeReport {
|
||||
quint16 sourceAddress;
|
||||
quint8 endpointId;
|
||||
Zigbee::ClusterId clusterId;
|
||||
ZigbeeClusterLibrary::ClusterId clusterId;
|
||||
quint16 attributeId;
|
||||
Zigbee::ZigbeeStatus attributeStatus;
|
||||
ZigbeeClusterLibrary::Status attributeStatus;
|
||||
Zigbee::DataType dataType;
|
||||
QByteArray data;
|
||||
} ZigbeeClusterAttributeReport;
|
||||
@ -75,29 +75,14 @@ public:
|
||||
};
|
||||
Q_ENUM(Direction)
|
||||
|
||||
|
||||
// // Power configuration cluster 0x0001
|
||||
|
||||
// enum PowerConfigurationAttribute {
|
||||
// PowerConfigurationAttributeMainsInformation = 0x0000,
|
||||
// PowerConfigurationAttributeMainsSettings = 0x0001,
|
||||
// PowerConfigurationAttributeBatteryInformation = 0x0002,
|
||||
// PowerConfigurationAttributeBatterySettings = 0x0003,
|
||||
// PowerConfigurationAttributeBatterySource2Information = 0x0004,
|
||||
// PowerConfigurationAttributeBattterySource2Settings = 0x0005,
|
||||
// PowerConfigurationAttributeBatterySource3Information = 0x0006,
|
||||
// PowerConfigurationAttributeBattterySource3Settings = 0x0007
|
||||
// };
|
||||
// Q_ENUM(PowerConfigurationAttribute)
|
||||
|
||||
explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent = nullptr);
|
||||
explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeClusterLibrary::ClusterId clusterId, Direction direction, QObject *parent = nullptr);
|
||||
|
||||
ZigbeeNode *node() const;
|
||||
ZigbeeNodeEndpoint *endpoint() const;
|
||||
|
||||
Direction direction() const;
|
||||
|
||||
Zigbee::ClusterId clusterId() const;
|
||||
ZigbeeClusterLibrary::ClusterId clusterId() const;
|
||||
QString clusterName() const;
|
||||
|
||||
QList<ZigbeeClusterAttribute> attributes() const;
|
||||
@ -106,13 +91,17 @@ public:
|
||||
|
||||
// ZCL global commands
|
||||
ZigbeeClusterReply *readAttributes(QList<quint16> attributes);
|
||||
ZigbeeClusterReply *configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations);
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
ZigbeeNetwork *m_network = nullptr;
|
||||
ZigbeeNode *m_node = nullptr;
|
||||
ZigbeeNodeEndpoint *m_endpoint= nullptr;
|
||||
|
||||
Zigbee::ClusterId m_clusterId = Zigbee::ClusterIdUnknown;
|
||||
ZigbeeClusterLibrary::ClusterId m_clusterId = ZigbeeClusterLibrary::ClusterIdUnknown;
|
||||
Direction m_direction = Server;
|
||||
QHash<quint16, ZigbeeClusterAttribute> m_attributes;
|
||||
|
||||
@ -120,6 +109,12 @@ protected:
|
||||
ZigbeeNetworkRequest createGeneralRequest();
|
||||
quint8 m_transactionSequenceNumber = 0;
|
||||
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 *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray());
|
||||
bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply);
|
||||
|
||||
@ -112,11 +112,11 @@ QList<ZigbeeClusterLibrary::ReadAttributeStatusRecord> ZigbeeClusterLibrary::par
|
||||
|
||||
// Read attribute id and status
|
||||
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;
|
||||
|
||||
if (status != Zigbee::ZigbeeStatusSuccess) {
|
||||
if (status != ZigbeeClusterLibrary::StatusSuccess) {
|
||||
qCWarning(dcZigbeeCluster()) << "Attribute status record" << ZigbeeUtils::convertUint16ToHexString(attributeId) << "finished with error" << status;
|
||||
// If not success, we are done and can continue with the next status record
|
||||
continue;
|
||||
@ -254,6 +254,45 @@ QByteArray ZigbeeClusterLibrary::buildFrame(const ZigbeeClusterLibrary::Frame &f
|
||||
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)
|
||||
{
|
||||
debug.nospace() << "FrameControl(";
|
||||
@ -305,3 +344,28 @@ QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::ReadAttributeStatusR
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
@ -66,6 +66,133 @@ public:
|
||||
};
|
||||
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 {
|
||||
GlobalAttributeClusterRevision = 0xfffd,
|
||||
GlobalAttributeAttributeReportingStatus = 0xfffe
|
||||
@ -91,6 +218,12 @@ public:
|
||||
};
|
||||
Q_ENUM(Direction)
|
||||
|
||||
enum ReportingDirection {
|
||||
ReportingDirectionReporting = 0x00,
|
||||
ReportingDirectionReceiving = 0x01
|
||||
};
|
||||
Q_ENUM(ReportingDirection)
|
||||
|
||||
typedef struct FrameControl {
|
||||
FrameType frameType = FrameTypeGlobal;
|
||||
bool manufacturerSpecific = false;
|
||||
@ -114,10 +247,28 @@ public:
|
||||
// Read attribute
|
||||
typedef struct ReadAttributeStatusRecord {
|
||||
quint16 attributeId;
|
||||
Zigbee::ZigbeeStatus attributeStatus;
|
||||
ZigbeeClusterLibrary::Status attributeStatus;
|
||||
ZigbeeDataType dataType;
|
||||
} 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
|
||||
static quint8 buildFrameControlByte(const FrameControl &frameControl);
|
||||
@ -132,12 +283,21 @@ public:
|
||||
|
||||
static Frame parseFrameData(const QByteArray &frameData);
|
||||
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::Header &header);
|
||||
QDebug operator<<(QDebug debug, const ZigbeeClusterLibrary::Frame &frame);
|
||||
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
|
||||
|
||||
@ -45,7 +45,7 @@ QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataConfirm &confirm)
|
||||
|
||||
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(confirm.destinationEndpoint) << ", ";
|
||||
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() << ")";
|
||||
|
||||
return debug.space();
|
||||
@ -76,7 +76,7 @@ QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataIndication &indication)
|
||||
if (indication.profileId == static_cast<quint16>(Zigbee::ZigbeeProfileDevice)) {
|
||||
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(indication.clusterId) << ", ";
|
||||
} else {
|
||||
debug.nospace() << static_cast<Zigbee::ClusterId>(indication.clusterId) << ", ";
|
||||
debug.nospace() << static_cast<ZigbeeClusterLibrary::ClusterId>(indication.clusterId) << ", ";
|
||||
}
|
||||
|
||||
debug.nospace() << "ASDU: " << ZigbeeUtils::convertByteArrayToHexString(indication.asdu) << ", ";
|
||||
|
||||
@ -74,113 +74,6 @@ public:
|
||||
Q_ENUM(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 {
|
||||
// Lightning devices
|
||||
LightLinkDeviceOnOffLight = 0x0000,
|
||||
@ -350,17 +243,6 @@ public:
|
||||
};
|
||||
Q_ENUM(SourceAddressMode)
|
||||
|
||||
enum ZigbeeZclStatus {
|
||||
|
||||
};
|
||||
Q_ENUM(ZigbeeZclStatus)
|
||||
|
||||
|
||||
enum ZigbeeZdpStatus {
|
||||
|
||||
};
|
||||
Q_ENUM(ZigbeeZdpStatus)
|
||||
|
||||
enum ZigbeeTxOption {
|
||||
ZigbeeTxOptionSecurityEnabled = 0x01,
|
||||
ZigbeeTxOptionUseNetworkKey = 0x02,
|
||||
@ -434,45 +316,6 @@ public:
|
||||
};
|
||||
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.
|
||||
typedef struct ApsdeDataConfirm {
|
||||
quint8 requestId = 0;
|
||||
|
||||
@ -303,7 +303,7 @@ void ZigbeeNetwork::saveNetwork()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName;
|
||||
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
|
||||
settings.beginGroup("Network");
|
||||
settings.beginGroup("ZigbeeNetwork");
|
||||
settings.setValue("panId", panId());
|
||||
settings.setValue("channel", channel());
|
||||
settings.setValue("networkKey", securityConfiguration().networkKey().toString());
|
||||
@ -321,7 +321,7 @@ void ZigbeeNetwork::loadNetwork()
|
||||
}
|
||||
|
||||
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
|
||||
settings.beginGroup("Network");
|
||||
settings.beginGroup("ZigbeeNetwork");
|
||||
quint16 panId = static_cast<quint16>(settings.value("panId", 0).toUInt());
|
||||
setPanId(panId);
|
||||
setChannel(settings.value("channel", 0).toUInt());
|
||||
@ -535,6 +535,7 @@ void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state)
|
||||
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());
|
||||
if (state == ZigbeeNode::StateInitialized && m_uninitializedNodes.contains(node)) {
|
||||
m_uninitializedNodes.removeAll(node);
|
||||
// Disconnect this slot since we don't need it any more
|
||||
disconnect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
|
||||
addNode(node);
|
||||
}
|
||||
|
||||
@ -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()
|
||||
{
|
||||
qCDebug(dcZigbeeNetworkDatabase()) << "Loading nodes from database" << m_db.databaseName();
|
||||
@ -93,7 +101,7 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
|
||||
.arg(endpointId);
|
||||
QSqlQuery inputClustersQuery = m_db.exec(query);
|
||||
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);
|
||||
endpoint->addInputCluster(cluster);
|
||||
|
||||
@ -122,8 +130,8 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
|
||||
}
|
||||
|
||||
// Set the basic cluster attributes if present
|
||||
if (endpoint->hasInputCluster(Zigbee::ClusterIdBasic)) {
|
||||
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic);
|
||||
if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
|
||||
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
|
||||
|
||||
if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeManufacturerName))
|
||||
endpoint->m_manufacturerName = basicCluster->attribute(ZigbeeClusterBasic::AttributeManufacturerName).dataType().toString();
|
||||
@ -142,7 +150,7 @@ QList<ZigbeeNode *> ZigbeeNetworkDatabase::loadNodes()
|
||||
.arg(endpointId);
|
||||
QSqlQuery outputClustersQuery = m_db.exec(query);
|
||||
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);
|
||||
qCDebug(dcZigbeeNetworkDatabase()) << "Loaded" << cluster;
|
||||
endpoint->addOutputCluster(cluster);
|
||||
@ -178,70 +186,89 @@ bool ZigbeeNetworkDatabase::initDatabase()
|
||||
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
|
||||
createTable("nodes",
|
||||
"(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string
|
||||
"shortAddress INTEGER NOT NULL, " // uint16
|
||||
"nodeDescriptor BLOB NOT NULL, " // bytes as received from the node
|
||||
"powerDescriptor INTEGER NOT NULL)"); // uint16
|
||||
createIndices("ieeeAddressIndex", "nodes", "ieeeAddress");
|
||||
|
||||
if (!m_db.tables().contains("nodes")) {
|
||||
createTable("nodes",
|
||||
"(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string
|
||||
"shortAddress INTEGER NOT NULL, " // uint16
|
||||
"nodeDescriptor BLOB NOT NULL, " // bytes as received from the node
|
||||
"powerDescriptor INTEGER NOT NULL)"); // uint16
|
||||
createIndices("ieeeAddressIndex", "nodes", "ieeeAddress");
|
||||
}
|
||||
|
||||
// Create endpoints table
|
||||
createTable("endpoints",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"ieeeAddress INTEGER NOT NULL, " // // reference to nodes.ieeeAddress
|
||||
"endpointId INTEGER NOT NULL, " // uint8
|
||||
"profileId INTEGER NOT NULL, " // uint16
|
||||
"deviceId INTEGER NOT NULL, " // uint16
|
||||
"deviceVersion INTEGER, " // uint8
|
||||
"CONSTRAINT fk_ieeeAddress FOREIGN KEY(ieeeAddress) REFERENCES nodes(ieeeAddress) ON DELETE CASCADE)");
|
||||
createIndices("endpointIndex", "endpoints", "ieeeAddress, endpointId");
|
||||
|
||||
if (!m_db.tables().contains("endpoints")) {
|
||||
createTable("endpoints",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"ieeeAddress INTEGER NOT NULL, " // // reference to nodes.ieeeAddress
|
||||
"endpointId INTEGER NOT NULL, " // uint8
|
||||
"profileId INTEGER NOT NULL, " // uint16
|
||||
"deviceId INTEGER NOT NULL, " // uint16
|
||||
"deviceVersion INTEGER, " // uint8
|
||||
"CONSTRAINT fk_ieeeAddress FOREIGN KEY(ieeeAddress) REFERENCES nodes(ieeeAddress) ON DELETE CASCADE)");
|
||||
createIndices("endpointIndex", "endpoints", "ieeeAddress, endpointId");
|
||||
}
|
||||
|
||||
// Create server cluster table
|
||||
createTable("serverClusters",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"endpointId INTEGER NOT NULL, " // reference to endpoint.id
|
||||
"clusterId INTEGER NOT NULL, " // uint16
|
||||
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
|
||||
createIndices("serverClusterIndex", "serverClusters", "endpointId, clusterId");
|
||||
if (!m_db.tables().contains("serverClusters")) {
|
||||
createTable("serverClusters",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"endpointId INTEGER NOT NULL, " // reference to endpoint.id
|
||||
"clusterId INTEGER NOT NULL, " // uint16
|
||||
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
|
||||
createIndices("serverClusterIndex", "serverClusters", "endpointId, clusterId");
|
||||
}
|
||||
|
||||
// Create client cluster table
|
||||
createTable("clientClusters",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"endpointId INTEGER NOT NULL, " // reference to endpoint.id
|
||||
"clusterId INTEGER NOT NULL, " // uint16
|
||||
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
|
||||
createIndices("clientClusterIndex", "clientClusters", "endpointId, clusterId");
|
||||
if (!m_db.tables().contains("clientClusters")) {
|
||||
createTable("clientClusters",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"endpointId INTEGER NOT NULL, " // reference to endpoint.id
|
||||
"clusterId INTEGER NOT NULL, " // uint16
|
||||
"CONSTRAINT fk_endpoint FOREIGN KEY(endpointId) REFERENCES endpoints(id) ON DELETE CASCADE)");
|
||||
createIndices("clientClusterIndex", "clientClusters", "endpointId, clusterId");
|
||||
}
|
||||
|
||||
// Create cluster attributes table
|
||||
createTable("attributes",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"clusterId INTEGER NOT NULL, " // reference to serverClusters.id
|
||||
"attributeId INTEGER NOT NULL, " // uint16
|
||||
"dataType INTEGER NOT NULL, " // uint8
|
||||
"data BLOB NOT NULL, " // raw data from attribute
|
||||
"CONSTRAINT fk_cluster FOREIGN KEY(clusterId) REFERENCES serverClusters(id) ON DELETE CASCADE)");
|
||||
createIndices("attributesIndex", "attributes", "clusterId, attributeId");
|
||||
if (!m_db.tables().contains("attributes")) {
|
||||
createTable("attributes",
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " // for db relation
|
||||
"clusterId INTEGER NOT NULL, " // reference to serverClusters.id
|
||||
"attributeId INTEGER NOT NULL, " // uint16
|
||||
"dataType INTEGER NOT NULL, " // uint8
|
||||
"data BLOB NOT NULL, " // raw data from attribute
|
||||
"CONSTRAINT fk_cluster FOREIGN KEY(clusterId) REFERENCES serverClusters(id) ON DELETE CASCADE)");
|
||||
createIndices("attributesIndex", "attributes", "clusterId, attributeId");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDatabase::createTable(const QString &tableName, const QString &schema)
|
||||
{
|
||||
m_db.exec(QString("CREATE TABLE IF NOT EXISTS %1 %2;").arg(tableName).arg(schema));
|
||||
m_db.exec(QString("PRAGMA schema_version = %1;").arg(DB_VERSION));
|
||||
m_db.exec(QString("PRAGMA user_version = %1;").arg(DB_VERSION));
|
||||
qCDebug(dcZigbeeNetworkDatabase()) << "Creating table" << tableName << schema;
|
||||
QString query = QString("CREATE TABLE IF NOT EXISTS %1 %2;").arg(tableName).arg(schema);
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
@ -256,9 +283,10 @@ bool ZigbeeNetworkDatabase::saveNodeEndpoint(ZigbeeNodeEndpoint *endpoint)
|
||||
.arg(static_cast<quint16>(endpoint->deviceId()))
|
||||
.arg(static_cast<quint8>(endpoint->deviceVersion()));
|
||||
|
||||
qCDebug(dcZigbeeNetworkDatabase()) << queryString;
|
||||
m_db.exec(queryString);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -378,7 +406,7 @@ bool ZigbeeNetworkDatabase::removeNode(ZigbeeNode *node)
|
||||
{
|
||||
qCDebug(dcZigbeeNetworkDatabase()) << "Remove" << node;
|
||||
// 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);
|
||||
if (m_db.lastError().type() != QSqlError::NoError) {
|
||||
qCWarning(dcZigbeeNetworkDatabase()) << "Could not remove node from database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText();
|
||||
|
||||
@ -44,6 +44,7 @@ class ZigbeeNetworkDatabase : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ZigbeeNetworkDatabase(ZigbeeNetwork *network, const QString &databaseName, QObject *parent = nullptr);
|
||||
~ZigbeeNetworkDatabase();
|
||||
|
||||
QList<ZigbeeNode *> loadNodes();
|
||||
bool wipeDatabase();
|
||||
|
||||
@ -32,6 +32,11 @@
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
QStringList ZigbeeNetworkManager::availableBackendTypes()
|
||||
{
|
||||
return {"deCONZ"};
|
||||
}
|
||||
|
||||
ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::BackendType backend, QObject *parent)
|
||||
{
|
||||
// Note: required for generating random PAN ID
|
||||
|
||||
@ -25,8 +25,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ZIGBEEMANAGER_H
|
||||
#define ZIGBEEMANAGER_H
|
||||
#ifndef ZIGBEENETWORKMANAGER_H
|
||||
#define ZIGBEENETWORKMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
@ -39,7 +39,9 @@ public:
|
||||
BackendTypeDeconz
|
||||
};
|
||||
|
||||
static QStringList availableBackendTypes();
|
||||
|
||||
static ZigbeeNetwork *createZigbeeNetwork(BackendType backend, QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // ZIGBEEMANAGER_H
|
||||
#endif // ZIGBEENETWORKMANAGER_H
|
||||
|
||||
@ -151,7 +151,7 @@ QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request)
|
||||
if (request.profileId() == Zigbee::ZigbeeProfileDevice) {
|
||||
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(request.clusterId()) << ", ";
|
||||
} else {
|
||||
debug.nospace() << static_cast<Zigbee::ClusterId>(request.clusterId()) << ", ";
|
||||
debug.nospace() << static_cast<ZigbeeClusterLibrary::ClusterId>(request.clusterId()) << ", ";
|
||||
}
|
||||
|
||||
if (request.destinationAddressMode() == Zigbee::DestinationAddressModeGroup)
|
||||
|
||||
@ -280,7 +280,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
|
||||
if (m_requestRetry < 3) {
|
||||
m_requestRetry++;
|
||||
qCDebug(dcZigbeeNode()) << "Retry to request simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << m_requestRetry << "/" << "3 attempts.";
|
||||
initEndpoints();
|
||||
initEndpoint(endpointId);
|
||||
} else {
|
||||
qCWarning(dcZigbeeNode()) << "Failed to read simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << "after 3 attempts. Giving up.";
|
||||
m_requestRetry = 0;
|
||||
@ -338,10 +338,10 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
|
||||
for (int i = 0; i < inputClusterCount; i++) {
|
||||
quint16 clusterId = 0;
|
||||
stream >> clusterId;
|
||||
if (!endpoint->hasInputCluster(static_cast<Zigbee::ClusterId>(clusterId))) {
|
||||
endpoint->addInputCluster(endpoint->createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Server));
|
||||
if (!endpoint->hasInputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId))) {
|
||||
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
|
||||
@ -350,10 +350,10 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
|
||||
for (int i = 0; i < outputClusterCount; i++) {
|
||||
quint16 clusterId = 0;
|
||||
stream >> clusterId;
|
||||
if (!endpoint->hasOutputCluster(static_cast<Zigbee::ClusterId>(clusterId))) {
|
||||
endpoint->addOutputCluster(endpoint->createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Client));
|
||||
if (!endpoint->hasOutputCluster(static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId))) {
|
||||
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);
|
||||
@ -380,7 +380,7 @@ void ZigbeeNode::initBasicCluster()
|
||||
// Get the first endpoint which implements the basic cluster
|
||||
ZigbeeNodeEndpoint *endpoint = nullptr;
|
||||
foreach (ZigbeeNodeEndpoint *ep, endpoints()) {
|
||||
if (ep->hasInputCluster(Zigbee::ClusterIdBasic)) {
|
||||
if (ep->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
|
||||
endpoint = ep;
|
||||
break;
|
||||
}
|
||||
@ -392,7 +392,7 @@ void ZigbeeNode::initBasicCluster()
|
||||
return;
|
||||
}
|
||||
|
||||
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic);
|
||||
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
|
||||
if (!basicCluster) {
|
||||
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
|
||||
@ -527,6 +527,11 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster)
|
||||
|
||||
// Finished with reading basic cluster, the node is initialized.
|
||||
// TODO: read other interesting cluster information
|
||||
|
||||
|
||||
// Bind client clusters to the sensor group
|
||||
// Configure reporting
|
||||
|
||||
setState(StateInitialized);
|
||||
});
|
||||
}
|
||||
|
||||
@ -114,6 +114,9 @@ private:
|
||||
void readModelIdentifier(ZigbeeClusterBasic *basicCluster);
|
||||
void readSoftwareBuildId(ZigbeeClusterBasic *basicCluster);
|
||||
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
void nodeInitializationFailed();
|
||||
void stateChanged(State state);
|
||||
|
||||
@ -97,12 +97,12 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::inputClusters() const
|
||||
return m_inputClusters.values();
|
||||
}
|
||||
|
||||
ZigbeeCluster *ZigbeeNodeEndpoint::getInputCluster(Zigbee::ClusterId clusterId) const
|
||||
ZigbeeCluster *ZigbeeNodeEndpoint::getInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -112,12 +112,12 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::outputClusters() const
|
||||
return m_outputClusters.values();
|
||||
}
|
||||
|
||||
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const
|
||||
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -163,48 +163,52 @@ void ZigbeeNodeEndpoint::setSoftwareBuildId(const QString &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) {
|
||||
// General
|
||||
case Zigbee::ClusterIdBasic:
|
||||
case ZigbeeClusterLibrary::ClusterIdBasic:
|
||||
return new ZigbeeClusterBasic(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
case Zigbee::ClusterIdOnOff:
|
||||
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
|
||||
case ZigbeeClusterLibrary::ClusterIdPowerConfiguration:
|
||||
return new ZigbeeClusterPowerConfiguration(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
case Zigbee::ClusterIdIdentify:
|
||||
case ZigbeeClusterLibrary::ClusterIdIdentify:
|
||||
return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this);
|
||||
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);
|
||||
break;
|
||||
|
||||
// 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);
|
||||
break;
|
||||
case Zigbee::ClusterIdRelativeHumidityMeasurement:
|
||||
case ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement:
|
||||
return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
case Zigbee::ClusterIdOccupancySensing:
|
||||
case ZigbeeClusterLibrary::ClusterIdOccupancySensing:
|
||||
return new ZigbeeClusterOccupancySensing(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
case Zigbee::ClusterIdIlluminanceMeasurement:
|
||||
return new ZigbeeClusterIlluminanceMeasurment(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
|
||||
// Lighting
|
||||
case Zigbee::ClusterIdColorControl:
|
||||
case ZigbeeClusterLibrary::ClusterIdColorControl:
|
||||
return new ZigbeeClusterColorControl(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
|
||||
// Security
|
||||
case Zigbee::ClusterIdIasZone:
|
||||
case ZigbeeClusterLibrary::ClusterIdIasZone:
|
||||
return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this);
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -237,18 +241,18 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
|
||||
switch (frame.header.frameControl.direction) {
|
||||
case ZigbeeClusterLibrary::DirectionClientToServer:
|
||||
// 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) {
|
||||
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;
|
||||
addOutputCluster(cluster);
|
||||
}
|
||||
break;
|
||||
case ZigbeeClusterLibrary::DirectionServerToClient:
|
||||
// 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) {
|
||||
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;
|
||||
addInputCluster(cluster);
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "zcl/general/zigbeeclusteronoff.h"
|
||||
#include "zcl/general/zigbeeclusteridentify.h"
|
||||
#include "zcl/general/zigbeeclusterlevelcontrol.h"
|
||||
#include "zcl/general/zigbeeclusterpowerconfiguration.h"
|
||||
|
||||
#include "zcl/measurement/zigbeeclusteroccupancysensing.h"
|
||||
#include "zcl/measurement/zigbeeclusterilluminancemeasurment.h"
|
||||
@ -85,17 +86,17 @@ public:
|
||||
|
||||
// Server clusters
|
||||
QList<ZigbeeCluster *> inputClusters() const;
|
||||
ZigbeeCluster *getInputCluster(Zigbee::ClusterId clusterId) const;
|
||||
bool hasInputCluster(Zigbee::ClusterId clusterId) const;
|
||||
ZigbeeCluster *getInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
|
||||
bool hasInputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
|
||||
|
||||
// Client clusters
|
||||
QList<ZigbeeCluster *> outputClusters() const;
|
||||
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const;
|
||||
bool hasOutputCluster(Zigbee::ClusterId clusterId) const;
|
||||
ZigbeeCluster *getOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
|
||||
bool hasOutputCluster(ZigbeeClusterLibrary::ClusterId clusterId) const;
|
||||
|
||||
// Convinience cast methods for getting a specific cluster object
|
||||
template<typename T>
|
||||
inline T* inputCluster(Zigbee::ClusterId clusterId)
|
||||
inline T* inputCluster(ZigbeeClusterLibrary::ClusterId clusterId)
|
||||
{
|
||||
if (!hasInputCluster(clusterId))
|
||||
return nullptr;
|
||||
@ -104,7 +105,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* outputCluster(Zigbee::ClusterId clusterId)
|
||||
inline T* outputCluster(ZigbeeClusterLibrary::ClusterId clusterId)
|
||||
{
|
||||
if (!hasOutputCluster(clusterId))
|
||||
return nullptr;
|
||||
@ -124,8 +125,8 @@ private:
|
||||
quint8 m_deviceVersion = 0;
|
||||
bool m_initialized = false;
|
||||
|
||||
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_inputClusters;
|
||||
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_outputClusters;
|
||||
QHash<ZigbeeClusterLibrary::ClusterId, ZigbeeCluster *> m_inputClusters;
|
||||
QHash<ZigbeeClusterLibrary::ClusterId, ZigbeeCluster *> m_outputClusters;
|
||||
|
||||
QString m_manufacturerName;
|
||||
QString m_modelIdentifier;
|
||||
@ -135,7 +136,7 @@ private:
|
||||
void setModelIdentifier(const QString &modelIdentifier);
|
||||
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 addOutputCluster(ZigbeeCluster *cluster);
|
||||
|
||||
@ -34,24 +34,7 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// Disabling 1000 to 2500 K, as we never want to go into full red for color temp
|
||||
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, 169, 87),
|
||||
QColor(255, 173, 94),
|
||||
@ -260,23 +243,12 @@ QString ZigbeeUtils::convertUint64ToHexString(const quint64 &value)
|
||||
return QString("0x%1").arg(convertByteArrayToHexString(data).remove(" ").remove("0x"));
|
||||
}
|
||||
|
||||
//QString ZigbeeUtils::messageTypeToString(const Zigbee::InterfaceMessageType &type)
|
||||
//{
|
||||
// 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)
|
||||
QString ZigbeeUtils::clusterIdToString(const ZigbeeClusterLibrary::ClusterId &clusterId)
|
||||
{
|
||||
QMetaObject metaObject = Zigbee::staticMetaObject;
|
||||
QMetaObject metaObject = ZigbeeClusterLibrary::staticMetaObject;
|
||||
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ClusterId"));
|
||||
|
||||
QString enumString = metaEnum.valueToKey(clusterId);
|
||||
QString clusterName = enumString.remove("Zigbee::ClusterId(ClusterId").remove(")").append(QString("(%1)").arg(ZigbeeUtils::convertUint16ToHexString(clusterId)));
|
||||
QString clusterName = enumString.remove("ZigbeeClusterLibrary::ClusterId(ClusterId").remove(")");
|
||||
if (clusterName.isEmpty())
|
||||
clusterName = "Unknown";
|
||||
|
||||
@ -287,9 +259,7 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
|
||||
{
|
||||
QMetaObject metaObject = Zigbee::staticMetaObject;
|
||||
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ZigbeeProfile"));
|
||||
|
||||
QString enumString = metaEnum.valueToKey(profileId);
|
||||
|
||||
return enumString.remove("Zigbee::ZigbeeProfile(ZigbeeProfile").remove(")");
|
||||
}
|
||||
|
||||
@ -330,6 +300,12 @@ QPointF ZigbeeUtils::convertColorToXY(const QColor &color)
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#define ZIGBEEUTILS_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QPoint>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QPointF>
|
||||
@ -39,7 +40,6 @@
|
||||
#include "zigbeedatatype.h"
|
||||
#include "zcl/zigbeecluster.h"
|
||||
|
||||
|
||||
class ZigbeeUtils
|
||||
{
|
||||
Q_GADGET
|
||||
@ -63,7 +63,7 @@ public:
|
||||
|
||||
// Enum prittify print methods
|
||||
//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);
|
||||
|
||||
// Generate random data
|
||||
@ -71,14 +71,13 @@ public:
|
||||
|
||||
// Color converter
|
||||
static QPointF convertColorToXY(const QColor &color);
|
||||
static QPoint convertColorToXYInt(const QColor &color);
|
||||
static QColor convertXYToColor(const QPointF &xyColor);
|
||||
static QColor convertXYToColor(quint16 x, quint16 y);
|
||||
|
||||
// Color temperature interpolation
|
||||
static QColor interpolateColorFromColorTemperature(int colorTemperature, int minValue, int maxValue);
|
||||
|
||||
static ZigbeeClusterAttributeReport parseAttributeReport(const QByteArray &data);
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEEUTILS_H
|
||||
|
||||
Reference in New Issue
Block a user