Implement basic cluster fetching
parent
9174ff39c4
commit
b211dbf347
|
|
@ -143,7 +143,10 @@ void ZigbeeInterface::onReadyRead()
|
|||
m_lengthValue = 0;
|
||||
m_escapeDetected = false;
|
||||
m_data.clear();
|
||||
|
||||
if (!m_unhandledBuffer.isEmpty()) {
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "Controller debug message:" << QString::fromUtf8(m_unhandledBuffer);
|
||||
m_unhandledBuffer.clear();
|
||||
}
|
||||
setReadingState(WaitForTypeMsb);
|
||||
break;
|
||||
case 0x02:
|
||||
|
|
@ -185,7 +188,8 @@ void ZigbeeInterface::onReadyRead()
|
|||
// Read data bytes depending on the reading state
|
||||
switch (m_readingState) {
|
||||
case WaitForStart:
|
||||
qCWarning(dcZigbeeInterfaceTraffic()) << "Wait for start but reviced data:" << byte;
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "Wait for start but reviced data:" << byte;
|
||||
m_unhandledBuffer.append(static_cast<char>(byte));
|
||||
break;
|
||||
case WaitForTypeMsb:
|
||||
m_messageTypeValue = byte;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ private:
|
|||
QTimer *m_reconnectTimer = nullptr;
|
||||
QSerialPort *m_serialPort = nullptr;
|
||||
QByteArray m_messageBuffer;
|
||||
QByteArray m_unhandledBuffer;
|
||||
bool m_available = false;
|
||||
|
||||
// Message parsing
|
||||
|
|
|
|||
|
|
@ -381,6 +381,23 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandFactoryResetNode(quint16
|
|||
return sendRequest(request);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandManagementLeaveRequest(quint16 shortAddress, const ZigbeeAddress &ieeeAddress, bool rejoin, bool removeChildren)
|
||||
{
|
||||
QByteArray data;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream << shortAddress;
|
||||
stream << ieeeAddress.toUInt64();
|
||||
stream << (rejoin ? static_cast<quint8>(0x01) : static_cast<quint8>(0x00));
|
||||
stream << (removeChildren ? static_cast<quint8>(0x01) : static_cast<quint8>(0x00));
|
||||
|
||||
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLeaveRequest, data));
|
||||
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLeaveResponse);
|
||||
request.setDescription("Leave node request " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
|
||||
request.setTimoutIntervall(10000);
|
||||
|
||||
return sendRequest(request);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandReadAttributeRequest(quint8 addressMode, quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint, ZigbeeCluster *cluster, QList<quint16> attributes, bool manufacturerSpecific, quint16 manufacturerId)
|
||||
{
|
||||
// Address mode: TODO
|
||||
|
|
@ -413,7 +430,9 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandReadAttributeRequest(qui
|
|||
}
|
||||
|
||||
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReadAttributeRequest, data));
|
||||
//request.setExpectedAdditionalMessageType(Zigbee::MessageTypeReadAttributeResponse);
|
||||
if (attributes.count() == 1) {
|
||||
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeReadAttributeResponse);
|
||||
}
|
||||
request.setDescription("Read attribute request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
|
||||
request.setTimoutIntervall(12000);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ public:
|
|||
ZigbeeInterfaceReply *commandUserDescriptorRequest(quint16 shortAddress, quint16 address);
|
||||
|
||||
ZigbeeInterfaceReply *commandFactoryResetNode(quint16 shortAddress, quint8 sourceEndpoint, quint8 destinationEndpoint);
|
||||
ZigbeeInterfaceReply *commandManagementLeaveRequest(quint16 shortAddress, const ZigbeeAddress &ieeeAddress, bool rejoin = false, bool removeChildren = false);
|
||||
|
||||
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, quint8 direction, bool manufacturerSpecific, quint16 manufacturerId, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations);
|
||||
|
|
|
|||
|
|
@ -695,81 +695,14 @@ void ZigbeeNetworkNxp::processAttributeReport(const ZigbeeInterfaceMessage &mess
|
|||
|
||||
void ZigbeeNetworkNxp::processReadAttributeResponse(const ZigbeeInterfaceMessage &message)
|
||||
{
|
||||
QByteArray data = message.data();
|
||||
ZigbeeClusterAttributeReport attributeReport = ZigbeeUtils::parseAttributeReport(message.data());
|
||||
|
||||
quint8 sequenceNumber = 0;
|
||||
quint16 sourceAddress = 0;
|
||||
quint8 endpointId = 0;
|
||||
quint16 clusterId = 0;
|
||||
quint16 attributeId = 0;
|
||||
quint8 attributeStatus = 0;
|
||||
quint8 attributDataType = 0;
|
||||
quint16 dataSize = 0;
|
||||
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
stream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributeStatus >> attributDataType >> dataSize;
|
||||
|
||||
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||
QByteArray attributeData = data.right(dataSize);
|
||||
|
||||
if (attributeData.length() != dataSize) {
|
||||
qCWarning(dcZigbeeNetwork()) << "HACK" << attributeData.length() << "!=" << dataSize;
|
||||
// Note: the NXP firmware for JN5169 has a bug here and does not send the attributeStatus.
|
||||
// Repars data without attribute status
|
||||
sequenceNumber = 0;
|
||||
sourceAddress = 0;
|
||||
endpointId = 0;
|
||||
clusterId = 0;
|
||||
attributeId = 0;
|
||||
attributeStatus = 0;
|
||||
attributDataType = 0;
|
||||
dataSize = 0;
|
||||
|
||||
QDataStream alternativeStream(&data, QIODevice::ReadOnly);
|
||||
alternativeStream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributDataType >> dataSize;
|
||||
|
||||
dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||
attributeData = data.right(dataSize);
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Attribute read response:";
|
||||
qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
||||
qCDebug(dcZigbeeNetwork()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress);
|
||||
qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endpointId);
|
||||
qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
||||
qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
|
||||
qCDebug(dcZigbeeNetwork()) << " Attribut status:" << static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
|
||||
qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
|
||||
qCDebug(dcZigbeeNetwork()) << " Attribut size:" << dataSize;
|
||||
qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(attributeData);
|
||||
|
||||
switch (dataType) {
|
||||
case Zigbee::CharString:
|
||||
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(attributeData);
|
||||
break;
|
||||
case Zigbee::Bool:
|
||||
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << static_cast<bool>(attributeData.at(0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(sourceAddress));
|
||||
ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(attributeReport.sourceAddress));
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
|
||||
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;
|
||||
|
||||
node->setClusterAttributeReport(attributeReport);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::readAttribute(ZigbeeCluster *cluster,
|
|||
ZigbeeInterfaceReply *reply = m_controller->commandReadAttributeRequest(0x02, node()->shortAddress(), 0x01,
|
||||
endpointId(), cluster, attributes,
|
||||
false, node()->manufacturerCode());
|
||||
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
|
||||
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||
|
|
@ -52,6 +52,10 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::readAttribute(ZigbeeCluster *cluster,
|
|||
}
|
||||
|
||||
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||
if (!reply->additionalMessage().data().isEmpty()) {
|
||||
ZigbeeClusterAttributeReport report = ZigbeeUtils::parseAttributeReport(reply->additionalMessage().data());
|
||||
setClusterAttribute(report.clusterId, ZigbeeClusterAttribute(report.attributeId, report.dataType, report.data));
|
||||
}
|
||||
});
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -60,8 +64,11 @@ ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::readAttribute(ZigbeeCluster *cluster,
|
|||
ZigbeeNetworkReply *ZigbeeNodeEndpointNxp::configureReporting(ZigbeeCluster *cluster, QList<ZigbeeClusterReportConfigurationRecord> reportConfigurations)
|
||||
{
|
||||
qCDebug(dcZigbeeNode()) << "Configure reporting" << node();
|
||||
|
||||
// FIXME: check the report configuration and the direction field according to specs
|
||||
|
||||
ZigbeeInterfaceReply *reply = m_controller->commandConfigureReportingRequest(0x02, node()->shortAddress(), 0x01,
|
||||
endpointId(), cluster, 0x01,
|
||||
endpointId(), cluster, 0x00,
|
||||
false, node()->manufacturerCode(), reportConfigurations);
|
||||
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
|
||||
reply->deleteLater();
|
||||
|
|
@ -336,4 +343,5 @@ void ZigbeeNodeEndpointNxp::setClusterAttribute(Zigbee::ClusterId clusterId, con
|
|||
}
|
||||
cluster->setAttribute(attribute);
|
||||
emit clusterAttributeChanged(cluster, attribute);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,22 @@ ZigbeeNodeNxp::ZigbeeNodeNxp(ZigbeeBridgeControllerNxp *controller, QObject *par
|
|||
|
||||
}
|
||||
|
||||
void ZigbeeNodeNxp::leaveNetworkRequest(bool rejoin, bool removeChildren)
|
||||
{
|
||||
ZigbeeInterfaceReply *reply = m_controller->commandManagementLeaveRequest(shortAddress(), extendedAddress(), rejoin, removeChildren);
|
||||
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||
// TODO: check error handling
|
||||
//return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
|
||||
{
|
||||
m_initState = initState;
|
||||
|
|
@ -170,8 +186,10 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
|
|||
qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
|
||||
if (profileId == Zigbee::ZigbeeProfileLightLink) {
|
||||
qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::LightLinkDevice>(deviceId);
|
||||
} else {
|
||||
} else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) {
|
||||
qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::HomeAutomationDevice>(deviceId);
|
||||
} else if (profileId == Zigbee::ZigbeeProfileGreenPower) {
|
||||
qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::GreenPowerDevice>(deviceId);
|
||||
}
|
||||
|
||||
quint8 deviceVersion = (bitField >> 4);
|
||||
|
|
@ -208,7 +226,7 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
|
|||
|
||||
quint16 clusterId = 0;
|
||||
stream >> clusterId;
|
||||
if (!endpoint->hasInputCluster(static_cast<Zigbee::ClusterId>(clusterId))) {
|
||||
if (!endpoint->hasOutputCluster(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));
|
||||
|
|
@ -218,20 +236,22 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
|
|||
m_uninitializedEndpoints.removeAll(endpointId);
|
||||
if (m_uninitializedEndpoints.isEmpty()) {
|
||||
qCDebug(dcZigbeeNode()) << "All endpoints fetched.";
|
||||
setInitState(InitStateReadClusterAttributes);
|
||||
setInitState(InitStateReadBasicClusterAttributes);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case InitStateReadClusterAttributes:
|
||||
// if (shortAddress() == 0x0000) {
|
||||
// qCDebug(dcZigbeeNode()) << "No need to read the endpoint baisc clusters of the coordinator node";
|
||||
// setState(StateInitialized);
|
||||
// break;
|
||||
// }
|
||||
case InitStateReadBasicClusterAttributes:
|
||||
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) {
|
||||
|
||||
ZigbeeNodeEndpointNxp *endpointNxp = qobject_cast<ZigbeeNodeEndpointNxp *>(endpoint);
|
||||
|
||||
// Read basic cluster
|
||||
qCDebug(dcZigbeeNode()) << "Read basic cluster for endpoint" << endpoint;
|
||||
|
||||
|
|
@ -242,34 +262,53 @@ void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState)
|
|||
return;
|
||||
}
|
||||
|
||||
QList<quint16> attributes;
|
||||
attributes.append(ZigbeeCluster::BasicAttributeZclVersion);
|
||||
attributes.append(ZigbeeCluster::BasicAttributeManufacturerName);
|
||||
m_uninitializedEndpoints.clear();
|
||||
m_uninitalizedBasicClusterAttributes.append(ZigbeeCluster::BasicAttributeZclVersion);
|
||||
m_uninitalizedBasicClusterAttributes.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.
|
||||
// Read the model identifier only if we don't have it yet. This is out of spec but required for some strange endpoints.
|
||||
if (!basicCluster->hasAttribute(ZigbeeCluster::BasicAttributeModelIdentifier))
|
||||
attributes.append(ZigbeeCluster::BasicAttributeModelIdentifier);
|
||||
m_uninitalizedBasicClusterAttributes.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());
|
||||
m_uninitalizedBasicClusterAttributes.append(ZigbeeCluster::BasicAttributePowerSource);
|
||||
m_uninitalizedBasicClusterAttributes.append(ZigbeeCluster::BasicAttributeSwBuildId);
|
||||
|
||||
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();
|
||||
}
|
||||
// Note: for having smoother flow request each attribute sequentially, not all at once
|
||||
|
||||
qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully for" << endpoint;
|
||||
qCDebug(dcZigbeeNode()) << "The device should response with multiple attribute read notifications.";
|
||||
setState(StateInitialized);
|
||||
});
|
||||
for (int i = 0; i < m_uninitalizedBasicClusterAttributes.count(); i++) {
|
||||
quint16 attributeId = m_uninitalizedBasicClusterAttributes.at(i);
|
||||
ZigbeeInterfaceReply *reply = m_controller->commandReadAttributeRequest(0x02, shortAddress(),
|
||||
0x01, endpoint->endpointId(),
|
||||
basicCluster,
|
||||
{ attributeId },
|
||||
false,
|
||||
manufacturerCode());
|
||||
|
||||
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply, endpointNxp, attributeId](){
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||
} else {
|
||||
ZigbeeClusterAttributeReport report = ZigbeeUtils::parseAttributeReport(reply->additionalMessage().data());
|
||||
qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully for" << endpointNxp << report;
|
||||
if (report.attributeStatus == Zigbee::ZigbeeStatusSuccess) {
|
||||
if (attributeId == ZigbeeCluster::BasicAttributeManufacturerName) {
|
||||
endpointNxp->setManufacturerName(QString::fromUtf8(report.data));
|
||||
} else if (attributeId == ZigbeeCluster::BasicAttributeModelIdentifier) {
|
||||
endpointNxp->setModelIdentifier(QString::fromUtf8(report.data));
|
||||
} else if (attributeId == ZigbeeCluster::BasicAttributeSwBuildId) {
|
||||
endpointNxp->setSoftwareBuildId(QString::fromUtf8(report.data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_uninitalizedBasicClusterAttributes.removeAll(attributeId);
|
||||
if (m_uninitalizedBasicClusterAttributes.isEmpty()) {
|
||||
setState(StateInitialized);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -290,7 +329,7 @@ ZigbeeNodeEndpoint *ZigbeeNodeNxp::createNodeEndpoint(quint8 endpointId, QObject
|
|||
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;
|
||||
qCWarning(dcZigbeeNode()) << this << "Got incalid status report" << report;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,17 +47,20 @@ public:
|
|||
InitStatePowerDescriptor,
|
||||
InitStateActiveEndpoints,
|
||||
InitStateSimpleDescriptors,
|
||||
InitStateReadClusterAttributes
|
||||
InitStateReadBasicClusterAttributes
|
||||
};
|
||||
Q_ENUM(InitState)
|
||||
|
||||
explicit ZigbeeNodeNxp(ZigbeeBridgeControllerNxp *controller, QObject *parent = nullptr);
|
||||
|
||||
void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override;
|
||||
|
||||
private:
|
||||
ZigbeeBridgeControllerNxp *m_controller = nullptr;
|
||||
InitState m_initState = InitStateNone;
|
||||
|
||||
QList<quint8> m_uninitializedEndpoints;
|
||||
QList<quint16> m_uninitalizedBasicClusterAttributes;
|
||||
|
||||
void setInitState(InitState initState);
|
||||
void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ public:
|
|||
ZigbeeProfileTelecomAutomation = 0x0107,
|
||||
ZigbeeProfilePersonalHomeHospitalCare = 0x0108,
|
||||
ZigbeeProfileAdvancedMetering = 0x0109,
|
||||
ZigbeeProfileLightLink = 0xC05E
|
||||
ZigbeeProfileLightLink = 0xC05E,
|
||||
ZigbeeProfileGreenPower = 0xA1E0
|
||||
};
|
||||
Q_ENUM(ZigbeeProfile)
|
||||
|
||||
|
|
@ -306,6 +307,10 @@ public:
|
|||
// Over the air uppgrade (OTA)
|
||||
ClusterIdOtaUpgrade = 0x0019,
|
||||
|
||||
// Poll controll
|
||||
ClusterIdPollControl = 0x0020,
|
||||
|
||||
|
||||
// Closures
|
||||
ClusterIdShadeConfiguration = 0x0100,
|
||||
|
||||
|
|
@ -342,9 +347,6 @@ public:
|
|||
ClusterIdLoadControl = 0x0701,
|
||||
ClusterIdSimpleMetering = 0x0702,
|
||||
|
||||
// Electrical Measurement
|
||||
ClusterIdElectricalMeasurement = 0x0B04,
|
||||
|
||||
// ZLL
|
||||
ClusterIdTouchlinkCommissioning = 0x1000,
|
||||
|
||||
|
|
@ -352,7 +354,15 @@ public:
|
|||
ClusterIdApplianceControl = 0x001B,
|
||||
ClusterIdApplianceIdentification = 0x0B00,
|
||||
ClusterIdApplianceEventsAlerts = 0x0B02,
|
||||
ClusterIdApplianceStatistics = 0x0B03
|
||||
ClusterIdApplianceStatistics = 0x0B03,
|
||||
|
||||
// Electrical Measurement
|
||||
ClusterIdElectricalMeasurement = 0x0B04,
|
||||
ClusterIdDiagnostics = 0x0B05,
|
||||
|
||||
// Zigbee green power
|
||||
ClusterIdGreenPower = 0x0021
|
||||
|
||||
};
|
||||
Q_ENUM(ClusterId)
|
||||
|
||||
|
|
@ -451,6 +461,18 @@ public:
|
|||
};
|
||||
Q_ENUM(HomeAutomationDevice)
|
||||
|
||||
|
||||
enum GreenPowerDevice {
|
||||
GreenPowerDeviceProxy = 0x0060,
|
||||
GreenPowerDeviceProxyMinimum = 0x0061,
|
||||
GreenPowerDeviceProxyTargetPlus = 0x0062,
|
||||
GreenPowerDeviceProxyTarget = 0x0063,
|
||||
GreenPowerDeviceProxyCommissioningTool = 0x0064,
|
||||
GreenPowerDeviceProxyCombo = 0x0065,
|
||||
GreenPowerDeviceProxyComboMinimum = 0x0066
|
||||
};
|
||||
Q_ENUM(GreenPowerDevice)
|
||||
|
||||
enum DataType {
|
||||
NoData = 0x00,
|
||||
Data8 = 0x08,
|
||||
|
|
|
|||
|
|
@ -93,3 +93,16 @@ QDebug operator<<(QDebug debug, ZigbeeCluster *cluster)
|
|||
|
||||
return debug.space();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeReport)
|
||||
{
|
||||
debug.nospace().noquote() << "AttributeReport("
|
||||
<< attributeReport.clusterId << ", "
|
||||
<< attributeReport.attributeId << ", "
|
||||
<< attributeReport.attributeStatus << ", "
|
||||
<< attributeReport.dataType << ", "
|
||||
<< attributeReport.data << ", "
|
||||
<< ")";
|
||||
|
||||
return debug.space();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct ZigbeeClusterReportConfigurationRecord {
|
|||
quint8 change;
|
||||
};
|
||||
|
||||
struct ZigbeeClusterAttributeReport {
|
||||
typedef struct ZigbeeClusterAttributeReport {
|
||||
quint16 sourceAddress;
|
||||
quint8 endpointId;
|
||||
Zigbee::ClusterId clusterId;
|
||||
|
|
@ -51,8 +51,7 @@ struct ZigbeeClusterAttributeReport {
|
|||
Zigbee::ZigbeeStatus attributeStatus;
|
||||
Zigbee::DataType dataType;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
} ZigbeeClusterAttributeReport;
|
||||
|
||||
class ZigbeeCluster : public QObject
|
||||
{
|
||||
|
|
@ -218,5 +217,6 @@ signals:
|
|||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, ZigbeeCluster *cluster);
|
||||
QDebug operator<<(QDebug debug, const ZigbeeClusterAttributeReport &attributeReport);
|
||||
|
||||
#endif // ZIGBEECLUSTER_H
|
||||
|
|
|
|||
|
|
@ -280,7 +280,9 @@ void ZigbeeNetwork::loadNetwork()
|
|||
endpoint->m_profile = static_cast<Zigbee::ZigbeeProfile>(settings.value("profile", 0).toUInt());
|
||||
endpoint->m_deviceId = static_cast<quint16>(settings.value("deviceId", 0).toUInt());
|
||||
endpoint->m_deviceVersion = static_cast<quint8>(settings.value("deviceId", 0).toUInt());
|
||||
//qCDebug(dcZigbeeNetwork()) << "Created" << endpoint;
|
||||
endpoint->m_manufacturerName = settings.value("manufacturerName").toString();
|
||||
endpoint->m_modelIdentifier = settings.value("modelIdentifier").toString();
|
||||
endpoint->m_softwareBuildId = settings.value("softwareBuildId").toString();
|
||||
|
||||
int inputClustersCount = settings.beginReadArray("inputClusters");
|
||||
for (int n = 0; n < inputClustersCount; n ++) {
|
||||
|
|
@ -339,11 +341,6 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node)
|
|||
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
|
||||
settings.beginGroup("Nodes");
|
||||
|
||||
// Clear settings for this node before storing it
|
||||
// settings.beginGroup(node->extendedAddress().toString());
|
||||
// settings.remove("");
|
||||
// settings.endGroup();
|
||||
|
||||
// Save this node
|
||||
settings.beginGroup(node->extendedAddress().toString());
|
||||
settings.setValue("nwkAddress", node->shortAddress());
|
||||
|
|
@ -359,6 +356,9 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node)
|
|||
settings.setValue("profile", endpoint->profile());
|
||||
settings.setValue("deviceId", endpoint->deviceId());
|
||||
settings.setValue("deviceVersion", endpoint->deviceVersion());
|
||||
settings.setValue("manufacturerName", endpoint->manufacturerName());
|
||||
settings.setValue("modelIdentifier", endpoint->modelIdentifier());
|
||||
settings.setValue("softwareBuildId", endpoint->softwareBuildId());
|
||||
|
||||
settings.beginWriteArray("inputClusters");
|
||||
for (int n = 0; n < endpoint->inputClusters().count(); n++) {
|
||||
|
|
|
|||
|
|
@ -238,42 +238,6 @@ void ZigbeeNode::setConnected(bool connected)
|
|||
emit connectedChanged(m_connected);
|
||||
}
|
||||
|
||||
|
||||
//void ZigbeeNode::identify()
|
||||
//{
|
||||
// QByteArray data;
|
||||
// QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
// stream << m_shortAddress;
|
||||
// stream << static_cast<quint8>(0);
|
||||
|
||||
// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data));
|
||||
// request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse);
|
||||
// request.setDescription("Node link quality request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
|
||||
// request.setTimoutIntervall(10000);
|
||||
|
||||
// ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
|
||||
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestLinkQuality);
|
||||
//}
|
||||
|
||||
//void ZigbeeNode::toggle(int addressMode)
|
||||
//{
|
||||
// QByteArray data;
|
||||
// QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
// stream << static_cast<quint8>(addressMode); // adress mode
|
||||
// stream << m_shortAddress;
|
||||
// stream << static_cast<quint8>(1); // source endpoint
|
||||
// stream << static_cast<quint8>(1); // destination endpoint
|
||||
// stream << static_cast<quint8>(2); // command toggle
|
||||
|
||||
// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeCluserOnOff, data));
|
||||
// request.setDescription("Toggle request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
|
||||
|
||||
// ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
|
||||
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onToggleFinished);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
void ZigbeeNode::setShortAddress(const quint16 &shortAddress)
|
||||
{
|
||||
m_shortAddress = shortAddress;
|
||||
|
|
@ -587,6 +551,7 @@ QDebug operator<<(QDebug debug, ZigbeeNode *node)
|
|||
{
|
||||
debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress());
|
||||
debug.nospace().noquote() << ", " << node->extendedAddress().toString();
|
||||
debug.nospace().noquote() << ", " << node->nodeType();
|
||||
debug.nospace().noquote() << ")";
|
||||
return debug.space();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@ public:
|
|||
QList<PowerSource> availablePowerSources() const;
|
||||
PowerLevel powerLevel() const;
|
||||
|
||||
virtual void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) = 0;
|
||||
|
||||
private:
|
||||
bool m_connected = false;
|
||||
State m_state = StateUninitialized;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,21 @@ void ZigbeeNodeEndpoint::setDeviceVersion(quint8 deviceVersion)
|
|||
m_deviceVersion = deviceVersion;
|
||||
}
|
||||
|
||||
QString ZigbeeNodeEndpoint::manufacturerName() const
|
||||
{
|
||||
return m_manufacturerName;
|
||||
}
|
||||
|
||||
QString ZigbeeNodeEndpoint::modelIdentifier() const
|
||||
{
|
||||
return m_modelIdentifier;
|
||||
}
|
||||
|
||||
QString ZigbeeNodeEndpoint::softwareBuildId() const
|
||||
{
|
||||
return m_softwareBuildId;
|
||||
}
|
||||
|
||||
QList<ZigbeeCluster *> ZigbeeNodeEndpoint::inputClusters() const
|
||||
{
|
||||
return m_inputClusters.values();
|
||||
|
|
@ -151,8 +166,10 @@ QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint)
|
|||
debug.nospace().noquote() << ", " << endpoint->profile();
|
||||
if (endpoint->profile() == Zigbee::ZigbeeProfileLightLink) {
|
||||
debug.nospace().noquote() << ", " << static_cast<Zigbee::LightLinkDevice>(endpoint->deviceId());
|
||||
} else {
|
||||
} else if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation) {
|
||||
debug.nospace().noquote() << ", " << static_cast<Zigbee::HomeAutomationDevice>(endpoint->deviceId());
|
||||
} else if (endpoint->profile() == Zigbee::ZigbeeProfileGreenPower) {
|
||||
debug.nospace().noquote() << ", " << static_cast<Zigbee::GreenPowerDevice>(endpoint->deviceId());
|
||||
}
|
||||
|
||||
debug.nospace().noquote() << ")";
|
||||
|
|
|
|||
|
|
@ -420,3 +420,81 @@ QColor ZigbeeUtils::interpolateColorFromColorTemperature(int colorTemperature, i
|
|||
// FIXME: interpolate between the selected index and the next color for more accuracy if required
|
||||
return colorTemperatureScale.at(closestColorIndex);
|
||||
}
|
||||
|
||||
ZigbeeClusterAttributeReport ZigbeeUtils::parseAttributeReport(const QByteArray &data)
|
||||
{
|
||||
QByteArray dataCopy = data;
|
||||
quint8 sequenceNumber = 0;
|
||||
quint16 sourceAddress = 0;
|
||||
quint8 endpointId = 0;
|
||||
quint16 clusterId = 0;
|
||||
quint16 attributeId = 0;
|
||||
quint8 attributeStatus = 0;
|
||||
quint8 attributDataType = 0;
|
||||
quint16 dataSize = 0;
|
||||
|
||||
QDataStream stream(&dataCopy, QIODevice::ReadOnly);
|
||||
stream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributeStatus >> attributDataType >> dataSize;
|
||||
|
||||
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||
QByteArray attributeData = data.right(dataSize);
|
||||
|
||||
if (attributeData.length() != dataSize) {
|
||||
//qCWarning(dcZigbeeNetwork()) << "HACK" << attributeData.length() << "!=" << dataSize;
|
||||
// Note: the NXP firmware for JN5169 has a bug here and does not send the attributeStatus.
|
||||
// Repars data without attribute status
|
||||
sequenceNumber = 0;
|
||||
sourceAddress = 0;
|
||||
endpointId = 0;
|
||||
clusterId = 0;
|
||||
attributeId = 0;
|
||||
attributeStatus = 0;
|
||||
attributDataType = 0;
|
||||
dataSize = 0;
|
||||
|
||||
QDataStream alternativeStream(&dataCopy, QIODevice::ReadOnly);
|
||||
alternativeStream >> sequenceNumber >> sourceAddress >> endpointId >> clusterId >> attributeId >> attributDataType >> dataSize;
|
||||
|
||||
dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||
attributeData = data.right(dataSize);
|
||||
}
|
||||
|
||||
// qCDebug(dcZigbeeNetwork()) << "Attribute read response:";
|
||||
// qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
||||
// qCDebug(dcZigbeeNetwork()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress);
|
||||
// qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endpointId);
|
||||
// qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
||||
// qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
|
||||
// qCDebug(dcZigbeeNetwork()) << " Attribut status:" << static_cast<Zigbee::ZigbeeStatus>(attributeStatus);
|
||||
// qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
|
||||
// qCDebug(dcZigbeeNetwork()) << " Attribut size:" << dataSize;
|
||||
// qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(attributeData);
|
||||
|
||||
// switch (dataType) {
|
||||
// case Zigbee::CharString:
|
||||
// qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(attributeData);
|
||||
// break;
|
||||
// case Zigbee::Bool:
|
||||
// qCDebug(dcZigbeeNetwork()) << " Data(converted)" << static_cast<bool>(attributeData.at(0));
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
|
||||
// ZigbeeNodeNxp *node = qobject_cast<ZigbeeNodeNxp *>(getZigbeeNode(sourceAddress));
|
||||
// if (!node) {
|
||||
// qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
|
||||
// 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;
|
||||
return attributeReport;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <QBitArray>
|
||||
|
||||
#include "zigbee.h"
|
||||
#include "zigbeecluster.h"
|
||||
|
||||
class ZigbeeUtils
|
||||
{
|
||||
|
|
@ -73,6 +74,8 @@ public:
|
|||
// Color temperature interpolation
|
||||
static QColor interpolateColorFromColorTemperature(int colorTemperature, int minValue, int maxValue);
|
||||
|
||||
static ZigbeeClusterAttributeReport parseAttributeReport(const QByteArray &data);
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEEUTILS_H
|
||||
|
|
|
|||
Loading…
Reference in New Issue