From 6afc214202cbd6f7e89637e09d21412bd80ec312 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 8 Nov 2021 00:58:55 +0100 Subject: [PATCH] More work on OnOff, LevelControl and ScenesCluster This alignes the OnOff cluster with the LevelControl cluster in terms of signal behavior: Previously, the OnOff cluster would fire a generic commandSent() signal for some commands and specific signals for others. Effectively forcing the user to connect multiple signals even if only the command would be of interest. The LevelControl cluster instead always fired a generic commandSent() signal and *additionally* more specific signals for parsed parameters. This changes the OnOff cluster to be in line with the LevelCluster as and making the API a bit simpler to use when parameters are not of interest. Also it completes the specific parsing for all 3 clusters. --- .../zcl/general/zigbeeclusterlevelcontrol.cpp | 41 +++++++++++++------ .../zcl/general/zigbeeclusterlevelcontrol.h | 18 ++++---- .../zcl/general/zigbeeclusteronoff.cpp | 15 ++----- .../zcl/general/zigbeeclusteronoff.h | 2 +- .../zcl/general/zigbeeclusterscenes.cpp | 11 +++-- .../zcl/general/zigbeeclusterscenes.h | 2 +- 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp index fee03c5..e74a89a 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp @@ -29,6 +29,7 @@ #include "zigbeenetworkreply.h" #include "loggingcategory.h" #include "zigbeenetwork.h" +#include "zigbeeutils.h" #include @@ -56,12 +57,12 @@ ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMove(ZigbeeClusterLevelCon return executeClusterCommand(ZigbeeClusterLevelControl::CommandMove, payload); } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStep(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStep(StepMode stepMode, quint8 stepSize, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(fadeMode) << stepSize << transitionTime; + stream << static_cast(stepMode) << stepSize << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandStep, payload); } @@ -88,12 +89,12 @@ ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveWithOnOff(ZigbeeCluste return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveWithOnOff, payload); } -ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStepWithOnOff(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime) +ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStepWithOnOff(StepMode stepMode, quint8 stepSize, quint16 transitionTime) { QByteArray payload; QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(fadeMode) << stepSize << transitionTime; + stream << static_cast(stepMode) << stepSize << transitionTime; return executeClusterCommand(ZigbeeClusterLevelControl::CommandStepWithOnOff, payload); } @@ -128,8 +129,6 @@ void ZigbeeClusterLevelControl::setAttribute(const ZigbeeClusterAttribute &attri void ZigbeeClusterLevelControl::processDataIndication(ZigbeeClusterLibrary::Frame frame) { - qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame; - // Increase the tsn for continuous id increasing on both sides m_transactionSequenceNumber = frame.header.transactionSequenceNumber; @@ -139,30 +138,48 @@ void ZigbeeClusterLevelControl::processDataIndication(ZigbeeClusterLibrary::Fram if (frame.header.frameControl.direction == ZigbeeClusterLibrary::DirectionClientToServer) { // Read the payload which is Command command = static_cast(frame.header.command); - qCDebug(dcZigbeeCluster()) << "Command sent from" << m_node << m_endpoint << this << command; emit commandSent(command, frame.payload); + bool withOnOff = false; switch (command) { + case CommandMoveToLevelWithOnOff: + case CommandMoveToLevel: { + QByteArray payload = frame.payload; + QDataStream payloadStream(&payload, QIODevice::ReadOnly); + payloadStream.setByteOrder(QDataStream::LittleEndian); + quint8 level; quint16 transitionTime; + payloadStream >> level >> transitionTime; + withOnOff = command == CommandMoveToLevelWithOnOff; + qCDebug(dcZigbeeCluster()).noquote().nospace() << "Command received from " << m_node << " " << m_endpoint << " " << this << " " << command << " withOnOff: " << withOnOff << " level: 0x" << QString::number(level, 16) << " transitionTime: 0x" << QString::number(transitionTime, 16); + emit commandMoveToLevelSent(withOnOff, level, transitionTime); + break; + } + case CommandStepWithOnOff: case CommandStep: { QByteArray payload = frame.payload; QDataStream payloadStream(&payload, QIODevice::ReadOnly); payloadStream.setByteOrder(QDataStream::LittleEndian); - quint8 fadeModeValue = 0; quint8 stepSize; quint16 transitionTime; - payloadStream >> fadeModeValue >> stepSize >> transitionTime; - emit commandStepSent(static_cast(fadeModeValue), stepSize, transitionTime); + quint8 stepModeValue = 0; quint8 stepSize; quint16 transitionTime; + payloadStream >> stepModeValue >> stepSize >> transitionTime; + withOnOff = command == CommandMoveToLevelWithOnOff; + qCDebug(dcZigbeeCluster()).noquote().nospace() << "Command received from " << m_node << " " << m_endpoint << " " << this << " " << command << " withOnOff: " << withOnOff << " stepModeValue: 0x" << QString::number(stepModeValue, 16) << " stepSize: 0x" << QString::number(stepSize, 16) << " transitionTime: 0x" << QString::number(transitionTime, 16); + emit commandStepSent(withOnOff, static_cast(stepModeValue), stepSize, transitionTime); break; } + case CommandMoveWithOnOff: case CommandMove: { QByteArray payload = frame.payload; QDataStream payloadStream(&payload, QIODevice::ReadOnly); payloadStream.setByteOrder(QDataStream::LittleEndian); quint8 moveModeValue = 0; quint8 rate;; payloadStream >> moveModeValue >> rate; - emit commandMoveSent(static_cast(moveModeValue), rate); + withOnOff = command == CommandMoveToLevelWithOnOff; + qCDebug(dcZigbeeCluster()).noquote().nospace() << "Command received from " << m_node << " " << m_endpoint << " " << this << " " << command << " withOnOff:" << withOnOff << " moveModeValue: 0x" << QString::number(moveModeValue, 16) << " rate: 0x" << QString::number(rate, 16); + emit commandMoveSent(withOnOff, static_cast(moveModeValue), rate); break; } default: - qCDebug(dcZigbeeCluster()) << "Command received without special implementation"; + qCDebug(dcZigbeeCluster()).noquote().nospace() << "Command received from " << m_node << " " << m_endpoint << " " << this << " " << command << " payload: 0x" << ZigbeeUtils::convertByteArrayToHexString(frame.payload); break; } diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h index 0f6f346..82001e6 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.h @@ -75,23 +75,23 @@ public: }; Q_ENUM(MoveMode) - enum FadeMode { - FadeModeUp = 0x00, - FadeModeDown = 0x01 + enum StepMode { + StepModeUp = 0x00, + StepModeDown = 0x01 }; - Q_ENUM(FadeMode) + Q_ENUM(StepMode) explicit ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); ZigbeeClusterReply *commandMoveToLevel(quint8 level, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandMove(MoveMode moveMode, quint8 rate = 0xff); - ZigbeeClusterReply *commandStep(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); + ZigbeeClusterReply *commandStep(StepMode stepMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandStop(); // With on/off ZigbeeClusterReply *commandMoveToLevelWithOnOff(quint8 level, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandMoveWithOnOff(MoveMode moveMode, quint8 rate = 0xff); - ZigbeeClusterReply *commandStepWithOnOff(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); + ZigbeeClusterReply *commandStepWithOnOff(StepMode stepMode, quint8 stepSize = 0x01, quint16 transitionTime = 0xffff); ZigbeeClusterReply *commandStopWithOnOff(); quint8 currentLevel() const; @@ -107,8 +107,10 @@ protected: signals: void currentLevelChanged(quint8 level); void commandSent(ZigbeeClusterLevelControl::Command command, const QByteArray ¶meter = QByteArray()); - void commandMoveSent(MoveMode moveMode, quint8 rate = 0xff); - void commandStepSent(FadeMode fadeMode, quint8 stepSize, quint16 transitionTime); + void commandMoveToLevelSent(bool withOnOff, quint8 level, quint16 transitionTime); + void commandMoveSent(bool withOnOff, MoveMode moveMode, quint8 rate = 0xff); + void commandStepSent(bool withOnOff, StepMode stepMode, quint8 stepSize, quint16 transitionTime); + void commandStopSent(); }; diff --git a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp index c13bddd..aae0ff6 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.cpp @@ -114,23 +114,15 @@ void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame if (frame.header.frameControl.direction == ZigbeeClusterLibrary::DirectionClientToServer) { // Read the payload which is Command command = static_cast(frame.header.command); - qCDebug(dcZigbeeCluster()) << "Received" << command << "from" << m_node << m_endpoint << this; + emit commandSent(command, frame.payload); switch (command) { - case CommandOn: - emit commandSent(CommandOn); - break; - case CommandOff: - emit commandSent(CommandOff); - break; - case CommandToggle: - emit commandSent(CommandToggle); - break; case CommandOffWithEffect: { QByteArray payload = frame.payload; QDataStream payloadStream(&payload, QIODevice::ReadOnly); payloadStream.setByteOrder(QDataStream::LittleEndian); quint8 effectValue = 0; quint16 effectVariant; payloadStream >> effectValue >> effectVariant; + qCDebug(dcZigbeeCluster()) << "Command received from" << m_node << m_endpoint << this << command << "effect:" << effectValue << "effectVariant:" << effectVariant; emit commandOffWithEffectSent(static_cast(effectValue), effectVariant); break; } @@ -140,11 +132,12 @@ void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame payloadStream.setByteOrder(QDataStream::LittleEndian); quint8 acceptOnlyWhenOnInt = 0; quint16 onTime; quint16 offTime; payloadStream >> acceptOnlyWhenOnInt >> onTime >> offTime; + qCDebug(dcZigbeeCluster()) << "Command received from" << m_node << m_endpoint << this << command << "accentOnlyWhenOnInt:" << acceptOnlyWhenOnInt << "onTime:" << onTime << "offTime:" << offTime; emit commandOnWithTimedOffSent(static_cast(acceptOnlyWhenOnInt), onTime, offTime); break; } default: - qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command << ZigbeeUtils::convertByteArrayToHexString(frame.payload); + qCDebug(dcZigbeeCluster()) << "Command received from" << m_node << m_endpoint << this << command << ZigbeeUtils::convertByteArrayToHexString(frame.payload); break; } } diff --git a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h index 561ff8f..1434d27 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusteronoff.h @@ -94,7 +94,7 @@ signals: void powerChanged(bool power); // Client cluster signals - void commandSent(Command command); + void commandSent(Command command, const QByteArray ¶meters = QByteArray()); // On and off time is in 1/10 seconds void commandOnWithTimedOffSent(bool acceptOnlyWhenOn, quint16 onTime, quint16 offTime); diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterscenes.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterscenes.cpp index 3d04521..ff0b48a 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterscenes.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterscenes.cpp @@ -45,8 +45,6 @@ void ZigbeeClusterScenes::setAttribute(const ZigbeeClusterAttribute &attribute) void ZigbeeClusterScenes::processDataIndication(ZigbeeClusterLibrary::Frame frame) { - qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame; - // Increase the tsn for continuous id increasing on both sides m_transactionSequenceNumber = frame.header.transactionSequenceNumber; @@ -54,8 +52,13 @@ void ZigbeeClusterScenes::processDataIndication(ZigbeeClusterLibrary::Frame fram case Client: { // Read the payload which is Command command = static_cast(frame.header.command); - qCDebug(dcZigbeeCluster()) << "Received" << command << "from" << m_node << m_endpoint << this << ZigbeeUtils::convertByteArrayToHexString(frame.payload); - emit commandSent(frame.header.command, frame.payload); + QByteArray payload = frame.payload; + QDataStream payloadStream(&payload, QIODevice::ReadOnly); + payloadStream.setByteOrder(QDataStream::LittleEndian); + quint16 groupId = 0; quint8 sceneId; + payloadStream >> groupId >> sceneId; + qCDebug(dcZigbeeCluster()).noquote() << "Received" << command << "for group" << "0x" + QString::number(groupId, 16) << "and scene" << sceneId << "from" << m_node << m_endpoint << this; + emit commandSent(command, groupId, sceneId); break; } case Server: diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterscenes.h b/libnymea-zigbee/zcl/general/zigbeeclusterscenes.h index c169247..7333f60 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterscenes.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterscenes.h @@ -63,7 +63,7 @@ public: explicit ZigbeeClusterScenes(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); signals: - void commandSent(quint8 command, const QByteArray &payload); + void commandSent(Command command, quint16 groupId, quint8 sceneId); private: void setAttribute(const ZigbeeClusterAttribute &attribute) override;