Implement cluster creation and handle some things for out of spec devices

This commit is contained in:
Simon Stürz 2020-03-13 13:14:58 +01:00
parent 511d9c641a
commit 9174ff39c4
15 changed files with 205 additions and 109 deletions

Binary file not shown.

View File

@ -29,6 +29,7 @@
Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork")
Q_LOGGING_CATEGORY(dcZigbeeNode, "ZigbeeNode")
Q_LOGGING_CATEGORY(dcZigbeeCluster, "ZigbeeCluster")
Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface")
Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController")
Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic")

View File

@ -33,6 +33,7 @@
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNode)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeCluster)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic)

View File

@ -199,7 +199,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandActiveEndpointsRequest(q
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeActiveEndpointRequest, data));
request.setDescription("Get active endpoints");
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeActiveEndpointResponse);
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -214,7 +214,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandRequestLinkQuality(quint
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse);
request.setDescription("Request link quality request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -301,7 +301,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandAuthenticateDevice(const
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse);
request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString()));
request.setTimoutIntervall(2000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -315,7 +315,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandNodeDescriptorRequest(qu
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse);
request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -330,7 +330,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandSimpleDescriptorRequest(
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse);
request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + " endpoint " + QString::number(endpoint));
request.setTimoutIntervall(10000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -344,7 +344,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandPowerDescriptorRequest(q
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePowerDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypePowerDescriptorResponse);
request.setDescription("Node power descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -359,7 +359,24 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandUserDescriptorRequest(qu
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeUserDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeUserDescriptorResponse);
request.setDescription("Node user descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + " " + ZigbeeUtils::convertUint16ToHexString(address));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandFactoryResetNode(quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << static_cast<quint8>(0x02);
stream << shortAddress;
stream << sourceEndpoint;
stream << destinationEndpoint;
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageBasicResetFactoryDefaults, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageBasicResetFactoryDefaultsResponse);
request.setDescription("Factory reset node " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + " " + ZigbeeUtils::convertByteToHexString(destinationEndpoint));
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -398,44 +415,41 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandReadAttributeRequest(qui
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReadAttributeRequest, data));
//request.setExpectedAdditionalMessageType(Zigbee::MessageTypeReadAttributeResponse);
request.setDescription("Read attribute request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandConfigureReportingRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, QList<quint16> attributes, bool manufacturerSpecific, quint16 manufacturerId)
ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandConfigureReportingRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, quint8 direction, bool manufacturerSpecific, quint16 manufacturerId, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << addressMode;
stream << shortAddress;
stream << sourceEndpoint;
stream << destinationEndpoint;
stream << static_cast<quint16>(cluster->clusterId());
stream << addressMode; // [0]
stream << shortAddress; // [1] [2]
stream << sourceEndpoint; // [3]
stream << destinationEndpoint; // [4]
stream << static_cast<quint16>(cluster->clusterId()); // [5] [6]
// 0: server -> client, 1: client -> server
if (cluster->direction() == ZigbeeCluster::Input) {
stream << static_cast<quint8>(1);
} else {
stream << static_cast<quint8>(0);
}
if (manufacturerSpecific) {
stream << static_cast<quint8>(1);
} else {
stream << static_cast<quint8>(0);
}
stream << manufacturerId;
stream << static_cast<quint8>(attributes.count());
for (int i = 0; i < attributes.count(); i++) {
stream << attributes.at(i);
stream << direction;// [7]
stream << static_cast<quint8>(manufacturerSpecific); // [8]
stream << manufacturerId; // [9] [10]
stream << static_cast<quint8>(reportConfigurations.count()); // [11]
for (int i = 0; i < reportConfigurations.count(); i++) {
// Configuration report
stream << reportConfigurations.at(i).direction;
stream << static_cast<quint8>(reportConfigurations.at(i).dataType);
stream << reportConfigurations.at(i).attributeId;
stream << reportConfigurations.at(i).minInterval;
stream << reportConfigurations.at(i).maxInterval;
stream << reportConfigurations.at(i).timeout;
stream << reportConfigurations.at(i).change;
}
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeConfigReportingRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeConfigReportingResponse);
request.setDescription("Configure reporting request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}
@ -452,7 +466,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandIdentify(quint8 addressM
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeIdentifySend, data));
request.setDescription("Identify request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(12000);
return sendRequest(request);
}

View File

@ -77,8 +77,10 @@ public:
ZigbeeInterfaceReply *commandPowerDescriptorRequest(quint16 shortAddress);
ZigbeeInterfaceReply *commandUserDescriptorRequest(quint16 shortAddress, quint16 address);
ZigbeeInterfaceReply *commandFactoryResetNode(quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint);
ZigbeeInterfaceReply *commandReadAttributeRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, QList<quint16> attributes, bool manufacturerSpecific, quint16 manufacturerId);
ZigbeeInterfaceReply *commandConfigureReportingRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, QList<quint16> attributes, bool manufacturerSpecific, quint16 manufacturerId);
ZigbeeInterfaceReply *commandConfigureReportingRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, quint8 direction, bool manufacturerSpecific, quint16 manufacturerId, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations);
ZigbeeInterfaceReply *commandIdentify(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, quint16 duration);
ZigbeeInterfaceReply *commandBindGroup(const ZigbeeAddress &sourceAddress, quint8 sourceEndpoint, quint16 clusterId, quint16 destinationAddress, quint8 destinationEndpoint);

View File

@ -131,7 +131,7 @@ void ZigbeeNetworkNxp::setStartingState(ZigbeeNetworkNxp::StartingState state)
if (channel() == 0) {
qCDebug(dcZigbeeNetwork()) << "Autoselect quitest channel for the zigbee network. FIXME: currently hardcoded to 13 due to firmware error.";
quint32 channelMask = 0;
channelMask |= 1 << (13);
channelMask |= 1 << (14);
reply = m_controller->commandSetChannelMask(channelMask);
} else {
quint32 channelMask = 0;
@ -675,19 +675,22 @@ void ZigbeeNetworkNxp::processAttributeReport(const ZigbeeInterfaceMessage &mess
break;
}
ZigbeeNode *node = getZigbeeNode(sourceAddress);
ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(sourceAddress));
if (!node) {
qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
return;
}
ZigbeeNodeEndpointNxp *endpoint = qobject_cast<ZigbeeNodeEndpointNxp *>(node->getEndpoint(endpointId));
if (!endpoint) {
qCWarning(dcZigbeeNetwork()) << "There is no endpoint for this attribute report.";
return;
}
ZigbeeClusterAttributeReport attributeReport;
attributeReport.sourceAddress = sourceAddress;
attributeReport.endpointId = endpointId;
attributeReport.clusterId = static_cast<Zigbee::ClusterId>(clusterId);
attributeReport.attributeId = attributeId;
attributeReport.attributeStatus = static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
attributeReport.dataType = dataType;
attributeReport.data = attributeData;
endpoint->setClusterAttribute(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeClusterAttribute(attributeId, dataType, attributeData));
node->setClusterAttributeReport(attributeReport);
}
void ZigbeeNetworkNxp::processReadAttributeResponse(const ZigbeeInterfaceMessage &message)
@ -751,19 +754,23 @@ void ZigbeeNetworkNxp::processReadAttributeResponse(const ZigbeeInterfaceMessage
break;
}
ZigbeeNode *node = getZigbeeNode(sourceAddress);
ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(sourceAddress));
if (!node) {
qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
return;
}
ZigbeeNodeEndpointNxp *endpoint = qobject_cast<ZigbeeNodeEndpointNxp *>(node->getEndpoint(endpointId));
if (!endpoint) {
qCWarning(dcZigbeeNetwork()) << "There is no endpoint for this attribute report.";
return;
}
ZigbeeClusterAttributeReport attributeReport;
attributeReport.sourceAddress = sourceAddress;
attributeReport.endpointId = endpointId;
attributeReport.clusterId = static_cast<Zigbee::ClusterId>(clusterId);
attributeReport.attributeId = attributeId;
attributeReport.attributeStatus = static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
attributeReport.dataType = dataType;
attributeReport.data = attributeData;
endpoint->setClusterAttribute(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeClusterAttribute(attributeId, dataType, attributeData));
node->setClusterAttributeReport(attributeReport);
}
void ZigbeeNetworkNxp::processLeaveIndication(const ZigbeeInterfaceMessage &message)

View File

@ -57,12 +57,12 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::readAttribute(ZigbeeCluster *cluster,
return nullptr;
}
ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::configureReporting(ZigbeeCluster *cluster, QList<quint16> attributes)
ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::configureReporting(ZigbeeCluster *cluster, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations)
{
qCDebug(dcZigbeeNode()) << "Configure reporting" << node() << cluster << attributes;
ZigbeeInterfaceReply *reply = m_controller->commandConfigureReportingRequest(0x00, node()->shortAddress(), 0x01,
endpointId(), cluster, attributes,
false, node()->manufacturerCode());
qCDebug(dcZigbeeNode()) << "Configure reporting" << node();
ZigbeeInterfaceReply *reply = m_controller->commandConfigureReportingRequest(0x02, node()->shortAddress(), 0x01,
endpointId(), cluster, 0x01,
false, node()->manufacturerCode(), reportConfigurations);
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
reply->deleteLater();
@ -95,6 +95,24 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::identify(quint16 seconds)
return nullptr;
}
ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::factoryReset()
{
qCDebug(dcZigbeeNode()) << "Factory reset" << this;
ZigbeeInterfaceReply *reply = m_controller->commandFactoryResetNode(node()->shortAddress(), 0x01, endpointId());
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
});
return nullptr;
}
ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::bindGroup(Zigbee::ClusterId clusterId, quint16 destinationAddress, quint8 destinationEndpoint)
{
qCDebug(dcZigbeeNode()) << "Bind group" << node() << clusterId << ZigbeeUtils::convertUint16ToHexString(destinationAddress) << ZigbeeUtils::convertByteToHexString(destinationEndpoint);
@ -291,10 +309,31 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::sendMoveToSaturation(quint8 saturatio
void ZigbeeNodeEndpointNxp::setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute)
{
foreach (ZigbeeCluster *cluster, m_inputClusters) {
if (cluster->clusterId() == clusterId) {
cluster->setAttribute(attribute);
emit clusterAttributeChanged(cluster, attribute);
}
// Check if this cluster is an input cluster
if (hasInputCluster(clusterId)) {
ZigbeeCluster *cluster = getInputCluster(clusterId);
cluster->setAttribute(attribute);
emit clusterAttributeChanged(cluster, attribute);
return;
}
// Check if this cluster is an output cluster
if (hasOutputCluster(clusterId)) {
ZigbeeCluster *cluster = getOutputCluster(clusterId);
cluster->setAttribute(attribute);
emit clusterAttributeChanged(cluster, attribute);
return;
}
// There is no cluster yet. Create it as output cluster if this is not the basic cluster
ZigbeeCluster *cluster = nullptr;
if (clusterId == Zigbee::ClusterIdBasic) {
cluster = new ZigbeeCluster(clusterId, ZigbeeCluster::Input, this);
addInputCluster(cluster);
} else {
cluster = new ZigbeeCluster(clusterId, ZigbeeCluster::Output, this);
addOutputCluster(cluster);
}
cluster->setAttribute(attribute);
emit clusterAttributeChanged(cluster, attribute);
}

View File

@ -44,8 +44,10 @@ public:
explicit ZigbeeNodeEndpointNxp(ZigbeeBridgeControllerNxp *controller, ZigbeeNode *node, quint8 endpoint, QObject *parent = nullptr);
ZigbeeNetworkReply *readAttribute(ZigbeeCluster *cluster, QList<quint16> attributes) override;
ZigbeeNetworkReply *configureReporting(ZigbeeCluster *cluster, QList<quint16> attributes) override;
ZigbeeNetworkReply *configureReporting(ZigbeeCluster *cluster, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations) override;
ZigbeeNetworkReply *identify(quint16 seconds) override;
ZigbeeNetworkReply *factoryReset() override;
ZigbeeNetworkReply *bindGroup(Zigbee::ClusterId clusterId, quint16 destinationAddress, quint8 destinationEndpoint) override;
ZigbeeNetworkReply *bindUnicast(Zigbee::ClusterId clusterId, const ZigbeeAddress &destinationAddress, quint8 destinationEndpoint) override;
ZigbeeNetworkReply *sendOnOffClusterCommand(ZigbeeCluster::OnOffClusterCommand command) override;

View File

@ -177,7 +177,12 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
quint8 deviceVersion = (bitField >> 4);
qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField) << deviceVersion;
ZigbeeNodeEndpointNxp *endpoint = new ZigbeeNodeEndpointNxp(m_controller, this, endpointId, this);
ZigbeeNodeEndpointNxp *endpoint = qobject_cast<ZigbeeNodeEndpointNxp *>(getEndpoint(endpointId));
if (!endpoint) {
endpoint = new ZigbeeNodeEndpointNxp(m_controller, this, endpointId, this);
m_endpoints.append(endpoint);
}
endpoint->setProfile(static_cast<Zigbee::ZigbeeProfile>(profileId));
endpoint->setDeviceId(deviceId);
endpoint->setDeviceVersion(deviceVersion);
@ -187,7 +192,9 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
for (int i = 0; i < inputClusterCount; i+=1) {
quint16 clusterId = 0;
stream >> clusterId;
endpoint->addInputCluster(new ZigbeeCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Input, endpoint));
if (!endpoint->hasInputCluster(static_cast<Zigbee::ClusterId>(clusterId))) {
endpoint->addInputCluster(new ZigbeeCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Input, endpoint));
}
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
@ -201,11 +208,11 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
quint16 clusterId = 0;
stream >> clusterId;
endpoint->addOutputCluster(new ZigbeeCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Output, endpoint));
if (!endpoint->hasInputCluster(static_cast<Zigbee::ClusterId>(clusterId))) {
endpoint->addOutputCluster(new ZigbeeCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Output, endpoint));
}
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
m_endpoints.append(endpoint);
}
m_uninitializedEndpoints.removeAll(endpointId);
@ -217,23 +224,16 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
}
break;
case InitStateReadClusterAttributes:
if (shortAddress() == 0x0000) {
qCDebug(dcZigbeeNode()) << "No need to read the endpoint baisc clusters of the coordinator node";
setState(StateInitialized);
break;
}
// if (shortAddress() == 0x0000) {
// qCDebug(dcZigbeeNode()) << "No need to read the endpoint baisc clusters of the coordinator node";
// setState(StateInitialized);
// break;
// }
foreach (ZigbeeNodeEndpoint *endpoint, m_endpoints) {
// Read basic cluster
qCDebug(dcZigbeeNode()) << "Read basic cluster for endpoint" << endpoint;
QList<quint16> attributes;
attributes.append(ZigbeeCluster::BasicAttributeZclVersion);
attributes.append(ZigbeeCluster::BasicAttributeManufacturerName);
attributes.append(ZigbeeCluster::BasicAttributeModelIdentifier);
attributes.append(ZigbeeCluster::BasicAttributePowerSource);
attributes.append(ZigbeeCluster::BasicAttributeSwBuildId);
ZigbeeCluster *basicCluster = endpoint->getInputCluster(Zigbee::ClusterIdBasic);
if (!basicCluster) {
@ -242,46 +242,29 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
return;
}
QList<quint16> attributes;
attributes.append(ZigbeeCluster::BasicAttributeZclVersion);
attributes.append(ZigbeeCluster::BasicAttributeManufacturerName);
// Note: some devices inform about the model identifier trough attribute report and the cluster contains different information
// Read the model identifier only if we don't have it yet. This is out of spec.
if (!basicCluster->hasAttribute(ZigbeeCluster::BasicAttributeModelIdentifier))
attributes.append(ZigbeeCluster::BasicAttributeModelIdentifier);
attributes.append(ZigbeeCluster::BasicAttributePowerSource);
attributes.append(ZigbeeCluster::BasicAttributeSwBuildId);
ZigbeeInterfaceReply *reply = m_controller->commandReadAttributeRequest(0x02, shortAddress(),
0x01, endpoint->endpointId(),
basicCluster,
attributes,
false,
manufacturerCode());
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply, endpoint](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
}
// QList<quint16> attributes;
// attributes.append(ZigbeeCluster::BasicAttributePowerSource);
// attributes.append(ZigbeeCluster::BasicAttributeLocationDescription);
// attributes.append(ZigbeeCluster::BasicAttributePhysicalEnvironment);
// attributes.append(ZigbeeCluster::BasicAttributeDeviceEnabled);
// attributes.append(ZigbeeCluster::BasicAttributeAlarmMask);
// attributes.append(ZigbeeCluster::BasicAttributeDisableLocalConfig);
// attributes.append(ZigbeeCluster::BasicAttributeSwBuildId);
// ZigbeeInterfaceReply *reply2 = m_controller->commandReadAttributeRequest(0x02, shortAddress(),
// 0x01, endpoint->endpointId(),
// basicCluster,
// attributes,
// false,
// manufacturerCode());
// connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply2, endpoint](){
// reply2->deleteLater();
// if (reply2->status() != ZigbeeInterfaceReply::Success) {
// qCWarning(dcZigbeeController()) << "Could not" << reply2->request().description() << reply2->status() << reply2->statusErrorMessage();
// }
// });
qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully for" << endpoint;
qCDebug(dcZigbeeNode()) << "The device should response with multiple attribute read notifications.";
setState(StateInitialized);
@ -303,3 +286,20 @@ ZigbeeNodeEndpoint *ZigbeeNodeNxp::createNodeEndpoint(quint8 endpointId, QObject
{
return new ZigbeeNodeEndpointNxp(m_controller, this, endpointId, parent);
}
void ZigbeeNodeNxp::setClusterAttributeReport(const ZigbeeClusterAttributeReport &report)
{
if (report.attributeStatus != Zigbee::ZigbeeStatusSuccess) {
qCWarning(dcZigbeeNode()) << this << "Got incalid status report" << report.endpointId << report.clusterId << report.attributeId << report.attributeStatus;
return;
}
ZigbeeNodeEndpointNxp *endpoint = qobject_cast<ZigbeeNodeEndpointNxp *>(getEndpoint(report.endpointId));
if (!endpoint) {
qCDebug(dcZigbeeNetwork()) << "Recived attribute report but there is no endpoint on this node yet. Create it...";
endpoint = new ZigbeeNodeEndpointNxp(m_controller, this, report.endpointId, this);
m_endpoints.append(endpoint);
}
endpoint->setClusterAttribute(report.clusterId, ZigbeeClusterAttribute(report.attributeId, report.dataType, report.data));
}

View File

@ -31,6 +31,7 @@
#include <QObject>
#include "zigbeenode.h"
#include "zigbeenodeendpointnxp.h"
#include "zigbeebridgecontrollernxp.h"
class ZigbeeNodeNxp : public ZigbeeNode
@ -59,6 +60,7 @@ private:
QList<quint8> m_uninitializedEndpoints;
void setInitState(InitState initState);
void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override;
protected:
void startInitialization() override;

View File

@ -27,13 +27,14 @@
#include "zigbeeutils.h"
#include "zigbeecluster.h"
#include "loggingcategory.h"
ZigbeeCluster::ZigbeeCluster(Zigbee::ClusterId clusterId, Direction direction, QObject *parent) :
QObject(parent),
m_clusterId(clusterId),
m_direction(direction)
{
qCDebug(dcZigbeeCluster()) << "Create cluster" << ZigbeeUtils::convertUint16ToHexString(clusterId) << direction;
}
ZigbeeCluster::Direction ZigbeeCluster::direction() const
@ -71,10 +72,12 @@ ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 id)
void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute)
{
if (hasAttribute(attribute.id())) {
if (hasAttribute(attribute.id())) {
qCDebug(dcZigbeeCluster()) << this << "update attribute" << attribute;
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
} else {
qCDebug(dcZigbeeCluster()) << this << "add attribute" << attribute;
m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute);
}

View File

@ -33,6 +33,27 @@
#include "zigbee.h"
#include "zigbeeclusterattribute.h"
struct ZigbeeClusterReportConfigurationRecord {
quint8 direction;
Zigbee::DataType dataType;
quint16 attributeId;
quint16 minInterval;
quint16 maxInterval;
quint16 timeout;
quint8 change;
};
struct ZigbeeClusterAttributeReport {
quint16 sourceAddress;
quint8 endpointId;
Zigbee::ClusterId clusterId;
quint16 attributeId;
Zigbee::ZigbeeStatus attributeStatus;
Zigbee::DataType dataType;
QByteArray data;
};
class ZigbeeCluster : public QObject
{
Q_OBJECT

View File

@ -199,6 +199,8 @@ private:
bool m_extendedActiveEndpointListAvailable = false;
bool m_extendedSimpleDescriptorListAvailable = false;
virtual void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) = 0;
protected:
ZigbeeNode(QObject *parent = nullptr);

View File

@ -75,11 +75,14 @@ public:
// Attribute methods
virtual ZigbeeNetworkReply *readAttribute(ZigbeeCluster *cluster, QList<quint16> attributes) = 0;
virtual ZigbeeNetworkReply *configureReporting(ZigbeeCluster *cluster, QList<quint16> attributes) = 0;
virtual ZigbeeNetworkReply *configureReporting(ZigbeeCluster *cluster, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations) = 0;
// Identify
virtual ZigbeeNetworkReply *identify(quint16 seconds) = 0;
// Reset
virtual ZigbeeNetworkReply *factoryReset() = 0;
// Binding
virtual ZigbeeNetworkReply *bindGroup(Zigbee::ClusterId clusterId, quint16 destinationAddress, quint8 destinationEndpoint) = 0;
virtual ZigbeeNetworkReply *bindUnicast(Zigbee::ClusterId clusterId, const ZigbeeAddress &destinationAddress, quint8 destinationEndpoint) = 0;

View File

@ -416,8 +416,7 @@ QColor ZigbeeUtils::interpolateColorFromColorTemperature(int colorTemperature, i
int intervalSize = maxValue - minValue;
int intervalPosition = colorTemperature - minValue;
double percentage = intervalPosition * 1.0 / intervalSize;
//qWarning() << "Interpolate color" << intervalSize << intervalPosition << percentage;
int closestColorIndex = qRound((colorTemperatureScale.count() - 1) * (1.0 - percentage));
//qWarning() << "Colors size" << colorTemperatureScale.count() << "Color position according to percentage" << closestColorIndex;
// FIXME: interpolate between the selected index and the next color for more accuracy if required
return colorTemperatureScale.at(closestColorIndex);
}