Implement ZCL default response for clusters and improve ISA zone cluster

This commit is contained in:
Simon Stürz 2020-12-15 15:17:41 +01:00
parent 2edfaa402a
commit 1c30c1de8b
4 changed files with 99 additions and 2 deletions

View File

@ -39,10 +39,36 @@ ZigbeeClusterIasZone::ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *n
}
ZigbeeClusterIasZone::ZoneState ZigbeeClusterIasZone::zoneState() const
{
return m_zoneState;
}
ZigbeeClusterIasZone::ZoneType ZigbeeClusterIasZone::zoneType() const
{
return m_zoneType;
}
ZigbeeClusterIasZone::ZoneStatus ZigbeeClusterIasZone::zoneStatus() const
{
return m_zoneStatus;
}
void ZigbeeClusterIasZone::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
updateOrAddAttribute(attribute);
if (attribute.id() == AttributeZoneState) {
quint8 zoneStateInt = attribute.dataType().toUInt8();
m_zoneState = static_cast<ZoneState>(zoneStateInt);
} else if (attribute.id() == AttributeZoneType) {
quint16 zoneTypeInt = attribute.dataType().toUInt16();
m_zoneType = static_cast<ZoneType>(zoneTypeInt);
} else if (attribute.id() == AttributeZoneStatus) {
quint16 zoneStatusInt = attribute.dataType().toUInt16();
m_zoneStatus = ZoneStatus(zoneStatusInt);
}
}
void ZigbeeClusterIasZone::processDataIndication(ZigbeeClusterLibrary::Frame frame)
@ -75,6 +101,16 @@ void ZigbeeClusterIasZone::processDataIndication(ZigbeeClusterLibrary::Frame fra
// Update the ZoneState attribute
setAttribute(ZigbeeClusterAttribute(AttributeZoneState, ZigbeeDataType(Zigbee::BitMap16, frame.payload.left(2))));
emit zoneStatusChanged(ZoneStatusFlags(zoneStatus), extendedStatus, zoneId, delay);
// Respond with default response if enabled
if (!frame.header.frameControl.disableDefaultResponse) {
// Send the default response with success back to the cluster
ZigbeeClusterReply *reply = sendDefaultResponse(frame.header.transactionSequenceNumber, command, ZigbeeClusterLibrary::StatusSuccess);
connect(reply, &ZigbeeClusterReply::finished, this, [](){
qCDebug(dcZigbeeCluster()) << "Default response sent successfully to the IAS zone status notification.";
});
}
break;
}
case ServerCommandZoneEnrollRequest: {
@ -87,8 +123,16 @@ void ZigbeeClusterIasZone::processDataIndication(ZigbeeClusterLibrary::Frame fra
<< zoneType << "Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
// Update the ZoneState attribute
setAttribute(ZigbeeClusterAttribute(AttributeZoneType, ZigbeeDataType(Zigbee::Enum16, frame.payload.left(2))));
emit zoneEnrollRequest(zoneType, manufacturerCode);
// Respond with default response if enabled
if (!frame.header.frameControl.disableDefaultResponse) {
// Send the default response with success back to the cluster
ZigbeeClusterReply *reply = sendDefaultResponse(frame.header.transactionSequenceNumber, command, ZigbeeClusterLibrary::StatusSuccess);
connect(reply, &ZigbeeClusterReply::finished, this, [](){
qCDebug(dcZigbeeCluster()) << "Default response sent successfully to the IAS zone status notification.";
});
}
break;
}
}

View File

@ -123,9 +123,15 @@ public:
explicit ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
// TODO: write server commands
ZoneState zoneState() const;
ZoneType zoneType() const;
ZoneStatus zoneStatus() const;
private:
ZoneState m_zoneState = ZoneStateNotEnrolled;
ZoneType m_zoneType = ZoneTypeInvalidZone;
ZoneStatus m_zoneStatus;
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
protected:

View File

@ -282,6 +282,52 @@ ZigbeeClusterReply *ZigbeeCluster::sendClusterServerResponse(quint8 command, qui
return zclReply;
}
ZigbeeClusterReply *ZigbeeCluster::sendDefaultResponse(quint8 transactionSequenceNumber, quint8 command, quint8 status)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame control
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionServerToClient;
frameControl.disableDefaultResponse = true;
// Build ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterLibrary::CommandDefaultResponse;
header.transactionSequenceNumber = transactionSequenceNumber;
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << command << status;
// Build ZCL frame
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
qCDebug(dcZigbeeCluster()) << "Send default response" << "TSN:" << ZigbeeUtils::convertByteToHexString(transactionSequenceNumber) << ZigbeeUtils::convertByteArrayToHexString(payload);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
finishZclReply(zclReply);
return;
}
// Note: since this is a response to a request, we don't expect any additional indications and the reply is finished
finishZclReply(zclReply);
});
return zclReply;
}
ZigbeeNetworkRequest ZigbeeCluster::createGeneralRequest()
{
// Build the request

View File

@ -119,6 +119,7 @@ protected:
ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray());
ZigbeeClusterReply *sendClusterServerResponse(quint8 command, quint8 transactionSequenceNumber, const QByteArray &payload = QByteArray());
ZigbeeClusterReply *sendDefaultResponse(quint8 transactionSequenceNumber, quint8 command, quint8 status);
bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply);
void finishZclReply(ZigbeeClusterReply *zclReply);