Add scene cluster basic structure

pull/10/head
Simon Stürz 2020-12-11 18:06:43 +01:00
parent 2893f39e61
commit 94539c0d02
16 changed files with 234 additions and 8 deletions

View File

@ -57,6 +57,7 @@ public:
NotificationNetworkStarted = 0x7E,
NotificationApsDataConfirm = 0x80,
NotificationApsDataIndication = 0x81,
NotificationApsDataAck = 0x82,
NotificationNodeJoined = 0x90,
NotificationNodeLeft = 0x91,
NotificationDebugMessage = 0xFE

View File

@ -511,11 +511,25 @@ void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &pac
stream >> confirm.sourceEndpoint >> confirm.destinationEndpoint >> confirm.zigbeeStatusCode;
qCDebug(dcZigbeeController()) << confirm;
qCDebug(dcZigbeeAps()) << "APSDE-DATA.confirm" << confirm;
qCDebug(dcZigbeeAps()) << confirm;
emit apsDataConfirmReceived(confirm);
break;
}
case Nxp::NotificationApsDataAck: {
QDataStream stream(&payload, QIODevice::ReadOnly);
stream.setByteOrder(QDataStream::LittleEndian);
Zigbee::ApsdeDataAck acknowledgement;
stream >> acknowledgement.requestId >> acknowledgement.zigbeeStatusCode >> acknowledgement.sourceEndpoint;
stream >> acknowledgement.destinationAddressMode >> acknowledgement.destinationAddress >> acknowledgement.destinationEndpoint;
stream >> acknowledgement.profileId >> acknowledgement.clusterId;
qCDebug(dcZigbeeController()) << acknowledgement;
qCDebug(dcZigbeeAps()) << acknowledgement;
emit apsDataAckReceived(acknowledgement);
break;
}
case Nxp::NotificationApsDataIndication: {
QDataStream stream(&payload, QIODevice::ReadOnly);
stream.setByteOrder(QDataStream::LittleEndian);

View File

@ -535,7 +535,7 @@ void ZigbeeNetworkNxp::onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &
{
ZigbeeNetworkReply *reply = m_pendingReplies.value(confirm.requestId);
if (!reply) {
qCDebug(dcZigbeeNetwork()) << "Received confirmation but could not find any reply. Ignoring the confirmation";
qCDebug(dcZigbeeNetwork()) << "Received confirmation but could not find any reply. Ignoring the confirmation" << confirm;
return;
}
@ -554,6 +554,15 @@ void ZigbeeNetworkNxp::onApsDataIndicationReceived(const Zigbee::ApsdeDataIndica
handleZigbeeClusterLibraryIndication(indication);
}
void ZigbeeNetworkNxp::onApsDataAckReceived(const Zigbee::ApsdeDataAck &acknowledgement)
{
ZigbeeNetworkReply *reply = m_pendingReplies.value(acknowledgement.requestId);
if (reply && reply->buffered()) {
qCDebug(dcZigbeeNetwork()) << "Buffered frame from network request has been acknowledged" << acknowledgement;
setReplyResponseError(reply, static_cast<Zigbee::ZigbeeApsStatus>(acknowledgement.zigbeeStatusCode));
}
}
void ZigbeeNetworkNxp::onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining)
{
qCDebug(dcZigbeeNetwork()) << "Received node left indication" << ieeeAddress.toString() << "rejoining:" << rejoining;

View File

@ -71,6 +71,7 @@ private slots:
void onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm);
void onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
void onApsDataAckReceived(const Zigbee::ApsdeDataAck &acknowledgement);
void onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining);

View File

@ -37,6 +37,7 @@ SOURCES += \
zcl/general/zigbeeclustermultistatevalue.cpp \
zcl/general/zigbeeclusteronoff.cpp \
zcl/general/zigbeeclusterpowerconfiguration.cpp \
zcl/general/zigbeeclusterscenes.cpp \
zcl/hvac/zigbeeclusterthermostat.cpp \
zcl/lighting/zigbeeclustercolorcontrol.cpp \
zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \
@ -103,6 +104,7 @@ HEADERS += \
zcl/general/zigbeeclustermultistatevalue.h \
zcl/general/zigbeeclusteronoff.h \
zcl/general/zigbeeclusterpowerconfiguration.h \
zcl/general/zigbeeclusterscenes.h \
zcl/hvac/zigbeeclusterthermostat.h \
zcl/lighting/zigbeeclustercolorcontrol.h \
zcl/measurement/zigbeeclusterilluminancemeasurment.h \

View File

@ -71,7 +71,7 @@ public:
enum MoveMode {
MoveModeUp = 0x00,
ModeModeDown = 0x01
MoveModeDown = 0x01
};
Q_ENUM(MoveMode)

View File

@ -0,0 +1,65 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "zigbeeclusterscenes.h"
#include "loggingcategory.h"
#include "zigbeeutils.h"
#include <QDataStream>
ZigbeeClusterScenes::ZigbeeClusterScenes(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdScenes, direction, parent)
{
}
void ZigbeeClusterScenes::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
updateOrAddAttribute(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;
switch (m_direction) {
case Client: {
// Read the payload which is
Command command = static_cast<Command>(frame.header.command);
qCDebug(dcZigbeeCluster()) << "Received" << command << "from" << m_node << m_endpoint << this << ZigbeeUtils::convertByteArrayToHexString(frame.payload);
emit commandSent(frame.header.command, frame.payload);
break;
}
case Server:
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
break;
}
}

View File

@ -0,0 +1,76 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 ZIGBEECLUSTERSCENES_H
#define ZIGBEECLUSTERSCENES_H
#include <QObject>
#include "zcl/zigbeecluster.h"
class ZigbeeClusterScenes : public ZigbeeCluster
{
Q_OBJECT
public:
enum Attribute {
AttributeSceneCount = 0x0000,
AttributeCurrentScene = 0x0001,
AttributeCurrentGroup = 0x0002,
AttributeSceneValid = 0x0003,
AttributeNameSupported = 0x0004,
AttributeLastConfiguredBy = 0x0005 // Optional
};
Q_ENUM(Attribute)
enum Command {
CommandAddScene = 0x00,
CommandViewScene = 0x01,
CommandRemoveScene = 0x02,
CommandRemoveAllScenes = 0x03,
CommandStoreScene = 0x04,
CommandRecallScene = 0x05,
CommandGetSceneMembership = 0x06,
CommandEnhancedAddScene= 0x40, // O
CommandEnhancedViewScene= 0x41, // O
CommandCopyScene= 0x42 // O
};
Q_ENUM(Command)
explicit ZigbeeClusterScenes(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
signals:
void commandSent(quint8 command, const QByteArray &payload);
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
protected:
void processDataIndication(ZigbeeClusterLibrary::Frame frame) override;
};
#endif // ZIGBEECLUSTERSCENES_H

View File

@ -32,7 +32,7 @@
QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataConfirm &confirm)
{
debug.nospace() << "APSDE-DATA.confirm(";
debug.nospace() << "Request ID: " << confirm.requestId << ", ";
debug.nospace() << "SQN: " << confirm.requestId << ", ";
if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup)
debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(confirm.destinationShortAddress) << ", ";
@ -84,3 +84,25 @@ QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataIndication &indication)
debug.nospace() << "RSSI: " << indication.rssi << "dBm)";
return debug.space();
}
QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataAck &acknowledgement)
{
debug.nospace() << "APSDE-DATA.acknowledgement(";
debug.nospace() << "SQN: " << acknowledgement.requestId << ", ";
if (acknowledgement.destinationAddressMode == Zigbee::DestinationAddressModeGroup) {
debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(acknowledgement.destinationAddress) << ", ";
} else {
debug.nospace() << "Network address:" << ZigbeeUtils::convertUint16ToHexString(acknowledgement.destinationAddress) << ", ";
}
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(acknowledgement.destinationEndpoint) << ", ";
debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(acknowledgement.sourceEndpoint) << ", ";
debug.nospace() << static_cast<Zigbee::ZigbeeProfile>(acknowledgement.profileId) << ", ";
if (acknowledgement.profileId == static_cast<quint16>(Zigbee::ZigbeeProfileDevice)) {
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(acknowledgement.clusterId) << ", ";
} else {
debug.nospace() << static_cast<ZigbeeClusterLibrary::ClusterId>(acknowledgement.clusterId) << ", ";
}
debug.nospace() << static_cast<ZigbeeClusterLibrary::Status>(acknowledgement.zigbeeStatusCode);
debug.nospace() << ")";
return debug.space();
}

View File

@ -320,11 +320,12 @@ public:
ZigbeeNwkLayerStatusMaxFrmCntr = 0xcc,
ZigbeeNwkLayerStatusNoKey = 0xcd,
ZigbeeNwkLayerStatusBadCcmOutput = 0xce,
ZigbeeNwkLayerStatusNoRoutingCapacity = 0xef, // Resource problem on the hardware
ZigbeeNwkLayerStatusRouteDiscoveryFailed = 0xd0,
ZigbeeNwkLayerStatusRouteError = 0xd1,
ZigbeeNwkLayerStatusBtTableFull = 0xd2,
ZigbeeNwkLayerStatusFrameNotBuffered = 0xd3,
ZigbeeNwkLayerStatusFrameBuffered = 0xd4
ZigbeeNwkLayerStatusFrameBuffered = 0xd4 // Buffered until route discovery has been done
};
Q_ENUM(ZigbeeNwkLayerStatus)
@ -377,6 +378,16 @@ public:
qint8 rssi = 0;
} ApsdeDataIndication;
typedef struct ApsdeDataAck {
quint8 requestId = 0;
quint8 destinationAddressMode = Zigbee::DestinationAddressModeShortAddress;
quint16 destinationAddress = 0;
quint8 destinationEndpoint = 0;
quint8 sourceEndpoint = 0;
quint16 profileId = 0;
quint16 clusterId = 0;
quint8 zigbeeStatusCode = 0;
} ApsdeDataAck;
///* Manufacturer Codes */
///* Codes less than 0x1000 were issued for RF4CE */
@ -1069,11 +1080,11 @@ public:
//#define ZBEE_MFG_SWANN "Swann Communications"
//#define ZBEE_MFG_TI "Texas Instruments"
};
QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataConfirm &confirm);
QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataIndication &indication);
QDebug operator<<(QDebug debug, const Zigbee::ApsdeDataAck &acknowledgement);
Q_DECLARE_OPERATORS_FOR_FLAGS(Zigbee::ZigbeeChannels)
Q_DECLARE_OPERATORS_FOR_FLAGS(Zigbee::ZigbeeTxOptions)

View File

@ -83,6 +83,7 @@ signals:
// APS notifications
void apsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm);
void apsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
void apsDataAckReceived(const Zigbee::ApsdeDataAck &acknowledgement);
};

View File

@ -843,9 +843,16 @@ void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::Zig
finishNetworkReply(reply);
} else {
// There has been an error while transporting the request to the device
// Note: if the APS status is >= 0xc1, it has to interpreted as NWK layer error
if (zigbeeApsStatus >= 0xc1 && zigbeeApsStatus <= 0xd4) {
reply->m_zigbeeNwkStatus = static_cast<Zigbee::ZigbeeNwkLayerStatus>(static_cast<quint8>(zigbeeApsStatus));
if (reply->zigbeeNwkStatus() == Zigbee::ZigbeeNwkLayerStatusFrameBuffered) {
// The frame has been buffered and will be sent once the route has been discovered.
// If the ACK will arrive, the frame was sent successfully, otherwise on timeout the request failed
reply->m_buffered = true;
// Restart the timer and wait for ack
reply->m_timer->start();
return;
}
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeNwkStatusError);
} else if (zigbeeApsStatus >= 0xE0 && zigbeeApsStatus <= 0xF4) {
reply->m_zigbeeMacStatus = static_cast<Zigbee::ZigbeeMacLayerStatus>(static_cast<quint8>(zigbeeApsStatus));

View File

@ -47,6 +47,11 @@ Zigbee::ZigbeeApsStatus ZigbeeNetworkReply::zigbeeApsStatus() const
return m_zigbeeApsStatus;
}
bool ZigbeeNetworkReply::buffered() const
{
return m_buffered;
}
Zigbee::ZigbeeNwkLayerStatus ZigbeeNetworkReply::zigbeeNwkStatus() const
{
return m_zigbeeNwkStatus;
@ -60,7 +65,13 @@ ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObj
m_timer->setSingleShot(true);
m_timer->setInterval(10000);
connect(m_timer, &QTimer::timeout, this, [this](){
m_error = ErrorTimeout;
if (m_buffered) {
// We did not receive any reply from the buffered message, assuming the route could not be discovered to the device
m_zigbeeNwkStatus = Zigbee::ZigbeeNwkLayerStatusRouteDiscoveryFailed;
m_error = ErrorZigbeeNwkStatusError;
} else {
m_error = ErrorTimeout;
}
emit finished();
});
}

View File

@ -60,10 +60,13 @@ public:
Zigbee::ZigbeeNwkLayerStatus zigbeeNwkStatus() const;
Zigbee::ZigbeeApsStatus zigbeeApsStatus() const;
bool buffered() const;
private:
explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr);
ZigbeeNetworkRequest m_request;
QTimer *m_timer = nullptr;
bool m_buffered = false;
Error m_error = ErrorNoError;
Zigbee::ZigbeeMacLayerStatus m_zigbeeMacStatus = Zigbee::ZigbeeMacLayerStatusSuccess;

View File

@ -177,6 +177,8 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(ZigbeeClusterLibrary::ClusterId
return new ZigbeeClusterLevelControl(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdGroups:
return new ZigbeeClusterGroups(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdScenes:
return new ZigbeeClusterScenes(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdAnalogInput:
return new ZigbeeClusterAnalogInput(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdAnalogOutput:

View File

@ -43,6 +43,7 @@
#include "zcl/general/zigbeeclusterlevelcontrol.h"
#include "zcl/general/zigbeeclusterpowerconfiguration.h"
#include "zcl/general/zigbeeclustergroups.h"
#include "zcl/general/zigbeeclusterscenes.h"
#include "zcl/general/zigbeeclusteranaloginput.h"
#include "zcl/general/zigbeeclusteranalogoutput.h"
#include "zcl/general/zigbeeclusteranalogvalue.h"