Implement ZCL default response for clusters and improve ISA zone cluster
This commit is contained in:
parent
2edfaa402a
commit
1c30c1de8b
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user