From 275e4c8b970d18083b65f353b2bcedfe633f920f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 5 Jun 2020 18:58:11 +0200 Subject: [PATCH] Implement color control cluster and improve uart communication --- .../deconz/zigbeebridgecontrollerdeconz.cpp | 34 ++- .../deconz/zigbeebridgecontrollerdeconz.h | 3 + .../backends/deconz/zigbeenetworkdeconz.cpp | 24 +- libnymea-zigbee/libnymea-zigbee.pro | 2 + .../zcl/general/zigbeeclusterlevelcontrol.cpp | 16 +- .../zcl/general/zigbeeclusterlevelcontrol.h | 8 +- .../lighting/zigbeeclustercolorcontrol.cpp | 233 +++++++++++++++++ .../zcl/lighting/zigbeeclustercolorcontrol.h | 246 ++++++++++++++++++ libnymea-zigbee/zcl/zigbeecluster.h | 33 --- libnymea-zigbee/zigbeenetwork.cpp | 10 +- libnymea-zigbee/zigbeenetwork.h | 5 +- libnymea-zigbee/zigbeenodeendpoint.cpp | 5 + libnymea-zigbee/zigbeenodeendpoint.h | 2 + 13 files changed, 549 insertions(+), 72 deletions(-) create mode 100644 libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp create mode 100644 libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.h diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp index 7bf4ce6..a07614a 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp @@ -224,9 +224,9 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataCo ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request) { // Send the request only if there are free slots on the device, otherwise enque request -// if (m_apsFreeSlotsAvailable) { + // if (m_apsFreeSlotsAvailable) { -// } + // } qCDebug(dcZigbeeAps()) << "APSDE-DATA.request" << request; ZigbeeInterfaceDeconzReply *interfaceReply = nullptr; @@ -253,14 +253,14 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(con quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber() { - return m_sequenceNumber++; + m_sequenceNumber += 3; + return m_sequenceNumber; } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) { // Create the reply ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent); - connect(reply, &ZigbeeInterfaceDeconzReply::timeout, this, [this, reply](){ qCWarning(dcZigbeeController()) << "Reply timeout" << reply->command() << "SQN:" << reply->sequenceNumber(); if (m_pendingReplies.contains(reply->sequenceNumber())) { @@ -414,7 +414,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters( // If read request failes, this mehtod returns the status code of the failed request. // Create an independent reply for finishing the entire read sequence - ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, m_sequenceNumber, this); + ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, generateSequenceNumber(), this); connect(readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::finished, readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection); // Read MAC address of the bridge @@ -934,22 +934,28 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray & << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data); // Check if this is an interface response for a pending reply - if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) { - ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(sequenceNumber); - if (!reply) { - qCWarning(dcZigbeeController()) << "Received message but the corresponding reply does not exist any more."; + if (m_pendingReplies.contains(sequenceNumber)) { + if (m_pendingReplies.value(sequenceNumber)->command() == command) { + // SQN and command maches + ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(sequenceNumber); + if (!reply) { + qCWarning(dcZigbeeController()) << "Received message but the corresponding reply does not exist any more."; + return; + } + reply->m_responseData = data; + reply->m_statusCode = status; + reply->finished(); return; + } else { + qCWarning(dcZigbeeController()) << "Received message with a pending request SQN but the command does not match. SQN mismatch."; + qCWarning(dcZigbeeController()) << "The SQN matches" << m_pendingReplies.value(sequenceNumber)->command() << "but command" << command << "received for SQN" << sequenceNumber; } - reply->m_responseData = data; - reply->m_statusCode = status; - reply->finished(); - return; } // Note: we got a notification, lets set the current sequence number to the notification id, // so the next request will be a continuouse increase - m_sequenceNumber = sequenceNumber + 1; + //m_sequenceNumber = sequenceNumber + 10; // No request for this data, lets check which notification and process the data switch (command) { diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h index 0ae2988..9b7877b 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h @@ -110,6 +110,8 @@ private: Deconz::NetworkState m_networkState = Deconz::NetworkStateOffline; QTimer *m_watchdogTimer = nullptr; + // Interface queue, send all requests sequentially and always wait for the interface response + // APS request queue bool m_apsFreeSlotsAvailable = false; QQueue m_requestQueue; @@ -120,6 +122,7 @@ private: ZigbeeInterfaceDeconzReply *createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent); // Send data depending on the request destination address mode + QByteArray buildRequestEnqueueSendDataGroupMessage(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp index 8ddd1fe..c5889c8 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp @@ -284,6 +284,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo case CreateNetworkStateInitializeCoordinatorNode: { if (m_coordinatorNode) { qCDebug(dcZigbeeNetwork()) << "We already have the coordinator node. Network starting done."; + m_database->saveNode(m_coordinatorNode); m_initializing = false; setState(StateRunning); setPermitJoiningInternal(false); @@ -417,7 +418,7 @@ void ZigbeeNetworkDeconz::startNetworkInternally() m_createNewNetwork = false; // Check if we have to create a pan ID and select the channel - if (panId() == 0) { + if (panId() == 0 || !m_coordinatorNode) { m_createNewNetwork = true; } @@ -497,8 +498,25 @@ void ZigbeeNetworkDeconz::startNetworkInternally() if (m_controller->networkState() == Deconz::NetworkStateConnected) { qCDebug(dcZigbeeNetwork()) << "The network is already running."; m_initializing = false; - setState(StateRunning); - setPermitJoiningInternal(false); + setPermitJoining(false); + // Set the permit joining timeout network configuration parameter + QByteArray parameterData; + QDataStream stream(¶meterData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(0); + + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode(); + setState(StateRunning); + }); + } else if (m_controller->networkState() == Deconz::NetworkStateOffline) { m_initializing = true; qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it"; diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 4816dd4..2ff0b88 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -11,6 +11,7 @@ SOURCES += \ zcl/general/zigbeeclusteridentify.cpp \ zcl/general/zigbeeclusterlevelcontrol.cpp \ zcl/general/zigbeeclusteronoff.cpp \ + zcl/lighting/zigbeeclustercolorcontrol.cpp \ zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \ zcl/measurement/zigbeeclusteroccupancysensing.cpp \ zcl/measurement/zigbeeclusterrelativehumiditymeasurement.cpp \ @@ -60,6 +61,7 @@ HEADERS += \ zcl/general/zigbeeclusteridentify.h \ zcl/general/zigbeeclusterlevelcontrol.h \ zcl/general/zigbeeclusteronoff.h \ + zcl/lighting/zigbeeclustercolorcontrol.h \ zcl/measurement/zigbeeclusterilluminancemeasurment.h \ zcl/measurement/zigbeeclusteroccupancysensing.h \ zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h \ diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp index c2e973d..e9d0d48 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp @@ -38,12 +38,12 @@ ZigbeeClusterLevelControl::ZigbeeClusterLevelControl(ZigbeeNetwork *network, Zig } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevel(quint8 level, quint16 transistionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevel(quint8 level, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << level << transistionTime; + stream << level << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveToLevel, payload); } @@ -56,12 +56,12 @@ ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMove(ZigbeeClusterLevelCon return executeClusterCommand(ZigbeeClusterLevelControl::CommandMove, payload); } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStep(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transistionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStep(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(fadeMode) << stepSize << transistionTime; + stream << static_cast(fadeMode) << stepSize << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandStep, payload); } @@ -70,12 +70,12 @@ ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStop() return executeClusterCommand(ZigbeeClusterLevelControl::CommandStop); } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevelWithOnOff(quint8 level, quint16 transistionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevelWithOnOff(quint8 level, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << level << transistionTime; + stream << level << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveToLevelWithOnOff, payload); } @@ -88,12 +88,12 @@ ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveWithOnOff(ZigbeeCluste return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveWithOnOff, payload); } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStepWithOnOff(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transistionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStepWithOnOff(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(fadeMode) << stepSize << transistionTime; + stream << static_cast(fadeMode) << stepSize << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandStepWithOnOff, payload); } diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h index ce34bf7..820d757 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h @@ -83,15 +83,15 @@ public: explicit ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); - ZigbeeClusterReply *commandMoveToLevel(quint8 level, quint16 transistionTime = 0xffff); + ZigbeeClusterReply *commandMoveToLevel(quint8 level, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandMove(MoveMode moveMode, quint8 rate = 0xff); - ZigbeeClusterReply *commandStep(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transistionTime = 0xffff); + ZigbeeClusterReply *commandStep(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandStop(); // With on/off - ZigbeeClusterReply *commandMoveToLevelWithOnOff(quint8 level, quint16 transistionTime = 0xffff); + ZigbeeClusterReply *commandMoveToLevelWithOnOff(quint8 level, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandMoveWithOnOff(MoveMode moveMode, quint8 rate = 0xff); - ZigbeeClusterReply *commandStepWithOnOff(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transistionTime = 0xffff); + ZigbeeClusterReply *commandStepWithOnOff(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandStopWithOnOff(); private: diff --git a/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp new file mode 100644 index 0000000..30b26e2 --- /dev/null +++ b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp @@ -0,0 +1,233 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeeclustercolorcontrol.h" +#include "zigbeenetworkreply.h" +#include "loggingcategory.h" +#include "zigbeenetwork.h" + +#include + +ZigbeeClusterColorControl::ZigbeeClusterColorControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : + ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdColorControl, direction, parent) +{ + +} + +/*! Send the move to \a hue command with the given \a direction and \a transitionTime. The transition time has the unit 1/10 seconds. */ +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToHue(quint8 hue, ZigbeeClusterColorControl::MoveDirection direction, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << hue << static_cast(direction) << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveToHue, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveHue(ZigbeeClusterColorControl::MoveMode moveMode, quint8 rate) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(moveMode) << rate; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveHue, payload); +} + +/*! Send the step hue command with the given \a stepMode, \a stepSize and \a transitionTime. The transition time has the unit 1/10 seconds. */ +ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepHue(ZigbeeClusterColorControl::StepMode stepMode, quint8 stepSize, quint8 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(stepMode) << stepSize << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandStepHue, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToSaturation(quint8 saturation, ZigbeeClusterColorControl::MoveDirection direction, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << saturation << static_cast(direction) << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveToSaturation, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveSaturation(ZigbeeClusterColorControl::MoveMode moveMode, quint8 rate) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(moveMode) << rate; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveSaturation, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepSaturation(ZigbeeClusterColorControl::StepMode stepMode, quint8 stepSize, quint8 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(stepMode) << stepSize << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandStepSaturation, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToHueAndSaturation(quint8 hue, quint8 saturation, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << hue << saturation << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveToHueAndSaturation, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColor(quint16 colorX, quint16 colorY, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << colorX << colorY << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveToColor, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveColor(quint16 colorXRate, quint16 colorYRate) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << colorXRate << colorYRate; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveColor, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepColor(quint16 stepX, quint16 stepY, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << stepX << stepY << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandStepColor, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveToColorTemperature(quint16 colorTemperatureMireds, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << colorTemperatureMireds << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveToColorTemperature, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedMoveToHue(quint16 enhancedHue, ZigbeeClusterColorControl::MoveDirection direction, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << enhancedHue << static_cast(direction) << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedMoveHue, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedMoveHue(ZigbeeClusterColorControl::MoveMode moveMode, quint16 rate) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(moveMode) << rate; + return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedMoveHue, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedStepHue(ZigbeeClusterColorControl::StepMode stepMode, quint16 stepSize, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(stepMode) << stepSize << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedStepHue, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedMoveToHueAndSaturation(quint16 enhancedHue, quint8 saturation, quint16 transitionTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << enhancedHue << saturation << transitionTime; + return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedMoveToHueAndSaturation, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandColorLoopSet(ColorLoopUpdateFlags updateFlag, ZigbeeClusterColorControl::ColorLoopAction action, ZigbeeClusterColorControl::ColorLoopDirection direction, quint16 time, quint16 startHue) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(updateFlag); + stream << static_cast(action); + stream << static_cast(direction); + stream << time << startHue; + return executeClusterCommand(ZigbeeClusterColorControl::CommandColorLoopSet, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandStopMoveStep() +{ + return executeClusterCommand(ZigbeeClusterColorControl::CommandStopMoveStep); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandMoveColorTemperature(ZigbeeClusterColorControl::MoveMode moveMode, quint16 rate, quint16 minColorTemperature, quint16 maxColorTemperature) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(moveMode) << rate << minColorTemperature << maxColorTemperature; + return executeClusterCommand(ZigbeeClusterColorControl::CommandMoveColorTemperature, payload); +} + +ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepColorTemperature(ZigbeeClusterColorControl::StepMode stepMode, quint16 stepSize, quint16 transitionTime, quint16 minColorTemperature, quint16 maxColorTemperature) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(stepMode) << stepSize << transitionTime << minColorTemperature << maxColorTemperature; + return executeClusterCommand(ZigbeeClusterColorControl::CommandStepColorTemperature, payload); +} + +void ZigbeeClusterColorControl::setAttribute(const ZigbeeClusterAttribute &attribute) +{ + qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast(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); + } +} + +void ZigbeeClusterColorControl::processDataIndication(ZigbeeClusterLibrary::Frame frame) +{ + qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame; + + // Increase the tsn for continuouse id increasing on both sides + m_transactionSequenceNumber = frame.header.transactionSequenceNumber; +} + + diff --git a/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.h b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.h new file mode 100644 index 0000000..f83dfa9 --- /dev/null +++ b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.h @@ -0,0 +1,246 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEECLUSTERCOLORCONTROL_H +#define ZIGBEECLUSTERCOLORCONTROL_H + +#include + +#include "zcl/zigbeecluster.h" +#include "zcl/zigbeeclusterreply.h" + +class ZigbeeNode; +class ZigbeeNetwork; +class ZigbeeNodeEndpoint; +class ZigbeeNetworkReply; + +class ZigbeeClusterColorControl : public ZigbeeCluster +{ + Q_OBJECT + + friend class ZigbeeNode; + friend class ZigbeeNetwork; + +public: + + enum Attribute { + // Color information + AttributeCurrentHue = 0x0000, + AttributeCurrentSaturation = 0x0001, + AttributeRemainingTime = 0x0002, + AttributeCurrentX = 0x0003, + AttributeCurrentY = 0x0004, + AttributeDriftCompensation = 0x0005, + AttributeCompensationText = 0x0006, + AttributeColorTemperatureMireds = 0x0007, + AttributeColorMode = 0x0008, + AttributeEnhancedCurrentHue = 0x4000, + AttributeEnhancedColorMode = 0x4001, + AttributeColorLoopActive = 0x4002, + AttributeColorLoopDirection = 0x4003, + AttributeColorLoopTime = 0x4004, + AttributeColorLoopStartEnhancedHue = 0x4005, + AttributeColorLoopStoredEnhancedHue = 0x4006, + AttributeColorCapabilities = 0x400a, + AttributeColorTempPhysicalMinMireds = 0x400b, + AttributeColorTempPhysicalMaxMireds = 0x400c, + // Primaries information + AttributeNumberOfPrimaries = 0x0010, + AttributePrimary1X = 0x0011, + AttributePrimary1Y = 0x0012, + AttributePrimary1Intensity = 0x0013, + AttributePrimary2X = 0x0015, + AttributePrimary2Y = 0x0016, + AttributePrimary2Intensity = 0x0017, + AttributePrimary3X = 0x0019, + AttributePrimary3Y = 0x001a, + AttributePrimary3Intensity = 0x001b, + // Additional primaries information + AttributePrimary4X = 0x0020, + AttributePrimary4Y = 0x0021, + AttributePrimary4Intensity = 0x0022, + AttributePrimary5X = 0x0024, + AttributePrimary5Y = 0x0025, + AttributePrimary5Intensity = 0x0026, + AttributePrimary6X = 0x0028, + AttributePrimary6Y = 0x0029, + AttributePrimary6Intensity = 0x002a, + // Defined color points settings + AttributeWhitePointX = 0x0030, + AttributeWhitePointY = 0x0031, + AttributeColorPointRX = 0x0032, + AttributeColorPointRY = 0x0033, + AttributeColorPointRIntensity = 0x0034, + AttributeColorPointGX = 0x0036, + AttributeColorPointGY = 0x0037, + AttributeColorPointGIntensity = 0x0038, + AttributeColorPointBX = 0x003a, + AttributeColorPointBY = 0x003b, + AttributeColorPointBIntensity = 0x003c + }; + Q_ENUM(Attribute) + + enum DriftCompensation { + DriftCompensationNone = 0x00, + DriftCompensationOther = 0x01, + DriftCompensationTemperatureMonitoring = 0x02, + DriftCompensationOpticalLuminanceMonitoring = 0x03, + DriftCompensationOpticalColorMonitoring = 0x04 + }; + Q_ENUM(DriftCompensation) + + enum ColorMode { + ColorModeHueSaturation = 0x00, + ColorModeXY = 0x01, + ColorModeColorTemperatureMired = 0x02 + }; + Q_ENUM(ColorMode) + + enum EnhancedColorMode { + EnhancedColorModeCurrentHueSaturation = 0x00, + EnhancedColorModeCurrentXY = 0x01, + EnhancedColorModeColorTemperatureMireds = 0x02, + EnhancedColorModeEnhancedCurrentHueSaturation = 0x03 + }; + Q_ENUM(EnhancedColorMode) + + + enum ColorCapability { + ColorCapabilityHueSaturation = 0x01, + ColorCapabilityEnhancedHue = 0x02, + ColorCapabilityColorLoop = 0x04, + ColorCapabilityXY = 0x08, + ColorCapabilityColorTemperature = 0x10 + }; + Q_ENUM(ColorCapability) + Q_DECLARE_FLAGS(ColorCapabilities, ColorCapability) + + enum Command { + CommandMoveToHue = 0x00, + CommandMoveHue = 0x01, + CommandStepHue = 0x02, + CommandMoveToSaturation = 0x03, + CommandMoveSaturation = 0x04, + CommandStepSaturation = 0x05, + CommandMoveToHueAndSaturation = 0x06, + CommandMoveToColor = 0x07, + CommandMoveColor = 0x08, + CommandStepColor = 0x09, + CommandMoveToColorTemperature = 0x0a, + CommandEnhancedMoveToHue = 0x40, + CommandEnhancedMoveHue = 0x41, + CommandEnhancedStepHue = 0x42, + CommandEnhancedMoveToHueAndSaturation = 0x43, + CommandColorLoopSet = 0x44, + CommandStopMoveStep = 0x47, + CommandMoveColorTemperature = 0x4b, + CommandStepColorTemperature = 0x4c + }; + Q_ENUM(Command) + + enum MoveDirection { + MoveDirectionShortestDistance = 0x00, + MoveDirectionLongestDistance = 0x01, + MoveDirectionUp = 0x02, + MoveDirectionDown = 0x03 + }; + Q_ENUM(MoveDirection) + + enum MoveMode { + MoveModeStop = 0x00, + MoveModeUp = 0x01, + MoveModeDown = 0x02 + }; + Q_ENUM(MoveMode) + + enum StepMode { + StepModeUp = 0x01, + StepModeDown = 0x03 + }; + Q_ENUM(StepMode) + + // For the color loop command + enum ColorLoopUpdate { + ColorLoopUpdateAction = 0x01, + ColorLoopUpdateDirection = 0x02, + ColorLoopUpdateTime = 0x04, + ColorLoopUpdateStartHue = 0x08 + }; + Q_ENUM(ColorLoopUpdate) + Q_DECLARE_FLAGS(ColorLoopUpdateFlags, ColorLoopUpdate) + + enum ColorLoopAction { + ColorLoopActionDeactivate = 0x00, + ColorLoopActionActivateColorLoopStartEnhancedHue = 0x01, + ColorLoopActionActivateEnhancedCurrentHue = 0x02 + }; + Q_ENUM(ColorLoopAction) + + enum ColorLoopDirection { + ColorLoopDirectionDecrementHue = 0x00, + ColorLoopDirectionIncrementHue = 0x01 + }; + Q_ENUM(ColorLoopDirection) + + explicit ZigbeeClusterColorControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); + + ZigbeeClusterReply *commandMoveToHue(quint8 hue, MoveDirection direction, quint16 transitionTime); + ZigbeeClusterReply *commandMoveHue(MoveMode moveMode, quint8 rate); + ZigbeeClusterReply *commandStepHue(StepMode stepMode, quint8 stepSize, quint8 transitionTime); + ZigbeeClusterReply *commandMoveToSaturation(quint8 saturation, MoveDirection direction, quint16 transitionTime); + ZigbeeClusterReply *commandMoveSaturation(MoveMode moveMode, quint8 rate); + ZigbeeClusterReply *commandStepSaturation(StepMode stepMode, quint8 stepSize, quint8 transitionTime); + ZigbeeClusterReply *commandMoveToHueAndSaturation(quint8 hue, quint8 saturation, quint16 transitionTime); + + ZigbeeClusterReply *commandMoveToColor(quint16 colorX, quint16 colorY, quint16 transitionTime); + ZigbeeClusterReply *commandMoveColor(quint16 colorXRate, quint16 colorYRate); + ZigbeeClusterReply *commandStepColor(quint16 stepX, quint16 stepY, quint16 transitionTime); + + ZigbeeClusterReply *commandEnhancedMoveToHue(quint16 enhancedHue, MoveDirection direction, quint16 transitionTime); + ZigbeeClusterReply *commandEnhancedMoveHue(MoveMode moveMode, quint16 rate); + ZigbeeClusterReply *commandEnhancedStepHue(StepMode stepMode, quint16 stepSize, quint16 transitionTime); + ZigbeeClusterReply *commandEnhancedMoveToHueAndSaturation(quint16 enhancedHue, quint8 saturation, quint16 transitionTime); + + ZigbeeClusterReply *commandColorLoopSet(ColorLoopUpdateFlags updateFlag, ColorLoopAction action, ColorLoopDirection direction, quint16 time, quint16 startHue); + ZigbeeClusterReply *commandStopMoveStep(); + + ZigbeeClusterReply *commandMoveToColorTemperature(quint16 colorTemperatureMireds, quint16 transitionTime); + ZigbeeClusterReply *commandMoveColorTemperature(MoveMode moveMode, quint16 rate, quint16 minColorTemperature, quint16 maxColorTemperature); + ZigbeeClusterReply *commandStepColorTemperature(StepMode stepMode, quint16 stepSize, quint16 transitionTime, quint16 minColorTemperature, quint16 maxColorTemperature); + +private: + void setAttribute(const ZigbeeClusterAttribute &attribute) override; + +protected: + void processDataIndication(ZigbeeClusterLibrary::Frame frame) override; + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterColorControl::ColorCapabilities) +Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterColorControl::ColorLoopUpdateFlags) + +#endif // ZIGBEECLUSTERCOLORCONTROL_H diff --git a/libnymea-zigbee/zcl/zigbeecluster.h b/libnymea-zigbee/zcl/zigbeecluster.h index 01728ca..1adf9fa 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.h +++ b/libnymea-zigbee/zcl/zigbeecluster.h @@ -90,39 +90,6 @@ public: // }; // Q_ENUM(PowerConfigurationAttribute) - -// // Color cluster 0x0300 - -// enum ColorControlClusterAttribute { -// ColorControlClusterAttributeCurrentHue = 0x0000, -// ColorControlClusterAttributeCurrentSaturation = 0x0001, -// ColorControlClusterAttributeRemainingTime = 0x0002, -// ColorControlClusterAttributeCurrentX = 0x0003, -// ColorControlClusterAttributeCurrentY = 0x0004, -// ColorControlClusterAttributeDriftCompensation = 0x0005, -// ColorControlClusterAttributeCompensationText = 0x0006, -// ColorControlClusterAttributeColorTemperatureMireds = 0x0007, -// ColorControlClusterAttributeColorMode = 0x0008, -// ColorControlClusterAttributeEnhancedCurrentHue = 0x4000, -// ColorControlClusterAttributeEnhancedColorMode = 0x4001, -// ColorControlClusterAttributeColorLoopActive = 0x4002, -// ColorControlClusterAttributeColorLoopDirection = 0x4003, -// ColorControlClusterAttributeColorLoopTime = 0x4004, -// ColorControlClusterAttributeColorLoopStartEnhancedHue = 0x4005, -// ColorControlClusterAttributeColorLoopStoredEnhancedHue = 0x4006, -// ColorControlClusterAttributeColorCapabilities = 0x400a, -// ColorControlClusterAttributeColorTempPhysicalMinMireds = 0x400b, -// ColorControlClusterAttributeColorTempPhysicalMaxMireds = 0x400c -// }; -// Q_ENUM(ColorControlClusterAttribute) - -// enum ColorControlClusterColorMode { -// ColorControlClusterColorModeHueSaturation = 0x00, -// ColorControlClusterColorModeXY = 0x01, -// ColorControlClusterColorModeColorTemperatureMired = 0x02 -// }; -// Q_ENUM(ColorControlClusterColorMode) - explicit ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Zigbee::ClusterId clusterId, Direction direction, QObject *parent = nullptr); ZigbeeNode *node() const; diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 30cac65..a68b464 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -309,10 +309,6 @@ void ZigbeeNetwork::saveNetwork() settings.setValue("networkKey", securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", securityConfiguration().globalTrustCenterLinkKey().toString()); settings.endGroup(); - - foreach (ZigbeeNode *node, nodes()) { - m_database->saveNode(node); - } } void ZigbeeNetwork::loadNetwork() @@ -458,12 +454,12 @@ void ZigbeeNetwork::setState(ZigbeeNetwork::State state) qCDebug(dcZigbeeNetwork()) << "State changed" << state; m_state = state; - emit stateChanged(m_state); if (state == StateRunning) { saveNetwork(); qCDebug(dcZigbeeNetwork()) << this; } + emit stateChanged(m_state); } void ZigbeeNetwork::setError(ZigbeeNetwork::Error error) @@ -478,7 +474,7 @@ void ZigbeeNetwork::setError(ZigbeeNetwork::Error error) bool ZigbeeNetwork::networkConfigurationAvailable() const { - return m_extendedPanId != 0 && m_channel != 0; + return m_extendedPanId != 0 && m_channel != 0 && m_coordinatorNode; } ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request) @@ -545,7 +541,7 @@ void ZigbeeNetwork::onNodeClusterAttributeChanged(ZigbeeCluster *cluster, const QDebug operator<<(QDebug debug, ZigbeeNetwork *network) { - debug.nospace().noquote() << "ZigbeeNetwork (" << ZigbeeUtils::convertUint64ToHexString(network->extendedPanId()) + debug.nospace().noquote() << "ZigbeeNetwork (" << ZigbeeUtils::convertUint16ToHexString(network->panId()) << ", Channel " << network->channel() << ")" << endl; foreach (ZigbeeNode *node, network->nodes()) { diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index fa55774..32b2e7f 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -133,7 +133,6 @@ private: ZigbeeDeviceProfile::NodeType m_nodeType = ZigbeeDeviceProfile::NodeTypeCoordinator; // Network storage - ZigbeeNetworkDatabase *m_database = nullptr; QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf"; QList m_nodes; QList m_uninitializedNodes; @@ -147,6 +146,7 @@ protected: ZigbeeNode *m_coordinatorNode = nullptr; bool m_permitJoining = false; ZigbeeSecurityConfiguration m_securityConfiguration; + ZigbeeNetworkDatabase *m_database = nullptr; ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent); ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, quint8 macCapabilities, QObject *parent); @@ -157,7 +157,6 @@ protected: void clearSettings(); void saveNode(ZigbeeNode *node); - void addNode(ZigbeeNode *node); void addUnitializedNode(ZigbeeNode *node); void removeNode(ZigbeeNode *node); @@ -187,8 +186,8 @@ signals: void nodeRemoved(ZigbeeNode *node); void permitJoiningChanged(bool permitJoining); - void stateChanged(State state); void errorOccured(Error error); + void stateChanged(State state); private slots: void onNodeStateChanged(ZigbeeNode::State state); diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index 38785b6..abf3b56 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -194,6 +194,11 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi return new ZigbeeClusterIlluminanceMeasurment(m_network, m_node, this, direction, this); break; + // Lighting + case Zigbee::ClusterIdColorControl: + return new ZigbeeClusterColorControl(m_network, m_node, this, direction, this); + break; + // Security case Zigbee::ClusterIdIasZone: return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this); diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index 3641cc4..a8bb959 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -47,6 +47,8 @@ #include "zcl/measurement/zigbeeclustertemperaturemeasurement.h" #include "zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h" +#include "zcl/lighting/zigbeeclustercolorcontrol.h" + #include "zcl/security/zigbeeclusteriaszone.h" class ZigbeeNode;