commit
b55b215ab2
@ -1,11 +1,13 @@
|
|||||||
# nymea-zigbee
|
# nymea-zigbee
|
||||||
|
----------------------
|
||||||
|
|
||||||
This repository contains the nymea-zigbee library and tools.
|
This repository contains the nymea-zigbee library and tools.
|
||||||
|
|
||||||
# Supported hardware
|
# Supported hardware
|
||||||
|
|
||||||
## NXP
|
Currently the only supported hardware is from NXP, but the tool will be designed to support also other hardware modules.
|
||||||
|
|
||||||
|
## NXP
|
||||||
* JN5168 (SoM)
|
* JN5168 (SoM)
|
||||||
* JN5169 (USB Stick)
|
* JN5169 (USB Stick)
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,19 @@ void ZigbeeNetworkManager::setPermitJoining(bool permitJoining)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ZigbeeInterfaceReply *reply = m_controller->commandPermitJoin(0, (permitJoining ? 255 : 0));
|
ZigbeeInterfaceReply *reply = m_controller->commandPermitJoin(0, (permitJoining ? 255 : 0));
|
||||||
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandPermitJoiningFinished);
|
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply, permitJoining](){
|
||||||
|
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." << permitJoining;
|
||||||
|
|
||||||
|
// Read the permit joining status back in order to update the state
|
||||||
|
readPermitJoinStatus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState state)
|
void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState state)
|
||||||
@ -67,8 +79,7 @@ void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState
|
|||||||
}
|
}
|
||||||
case StartingStateGetVersion: {
|
case StartingStateGetVersion: {
|
||||||
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get controller version";
|
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get controller version";
|
||||||
ZigbeeInterfaceReply *reply = m_controller->commandGetVersion();
|
readControllerVersion();
|
||||||
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandGetVersionFinished);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StartingStateSetPanId: {
|
case StartingStateSetPanId: {
|
||||||
@ -115,8 +126,7 @@ void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState
|
|||||||
}
|
}
|
||||||
case StartingStateGetPermitJoinStatus: {
|
case StartingStateGetPermitJoinStatus: {
|
||||||
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get permit join status";
|
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get permit join status";
|
||||||
ZigbeeInterfaceReply *reply = m_controller->commandGetPermitJoinStatus();
|
readPermitJoinStatus();
|
||||||
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandGetPermitJoiningStatusFinished);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StartingStateReadeNodeDescriptor: {
|
case StartingStateReadeNodeDescriptor: {
|
||||||
@ -140,6 +150,57 @@ void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::readControllerVersion()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->commandGetVersion();
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply->additionalMessage().data().count() != 4) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << ":" << "Invalid payload size";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
|
||||||
|
// Parse version
|
||||||
|
quint16 majorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(0, 2));
|
||||||
|
quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2));
|
||||||
|
|
||||||
|
m_controllerFirmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
|
||||||
|
qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerFirmwareVersion;
|
||||||
|
|
||||||
|
if (m_startingState == StartingStateGetVersion) setStartingState(StartingStateSetPanId);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::readPermitJoinStatus()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->commandGetPermitJoinStatus();
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, [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";
|
||||||
|
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||||
|
|
||||||
|
m_permitJoining = static_cast<bool>(reply->additionalMessage().data().at(0));
|
||||||
|
emit permitJoiningChanged(m_permitJoining);
|
||||||
|
|
||||||
|
if (m_startingState == StartingStateGetPermitJoinStatus) setStartingState(StartingStateReadeNodeDescriptor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile)
|
//void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile)
|
||||||
//{
|
//{
|
||||||
|
|
||||||
@ -209,33 +270,6 @@ void ZigbeeNetworkManager::onCommandErasePersistentDataFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeNetworkManager::onCommandGetVersionFinished()
|
|
||||||
{
|
|
||||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
|
||||||
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply->additionalMessage().data().count() != 4) {
|
|
||||||
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << ":" << "Invalid payload size";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
|
||||||
|
|
||||||
// Parse version
|
|
||||||
quint16 majorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(0, 2));
|
|
||||||
quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2));
|
|
||||||
|
|
||||||
m_controllerFirmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
|
|
||||||
qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerFirmwareVersion;
|
|
||||||
|
|
||||||
if (m_startingState == StartingStateGetVersion) setStartingState(StartingStateSetPanId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished()
|
void ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished()
|
||||||
{
|
{
|
||||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
@ -309,42 +343,6 @@ void ZigbeeNetworkManager::onCommandStartScanFinished()
|
|||||||
processNetworkFormed(reply->additionalMessage());
|
processNetworkFormed(reply->additionalMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeNetworkManager::onCommandGetPermitJoiningStatusFinished()
|
|
||||||
{
|
|
||||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
|
||||||
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";
|
|
||||||
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
|
||||||
|
|
||||||
m_permitJoining = static_cast<bool>(reply->additionalMessage().data().at(0));
|
|
||||||
emit permitJoiningChanged(m_permitJoining);
|
|
||||||
|
|
||||||
if (m_startingState == StartingStateGetPermitJoinStatus) setStartingState(StartingStateReadeNodeDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeNetworkManager::onCommandPermitJoiningFinished()
|
|
||||||
{
|
|
||||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
|
||||||
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";
|
|
||||||
|
|
||||||
// Read the permit joining status back in order to update the state
|
|
||||||
ZigbeeInterfaceReply *getJoiningReply = m_controller->commandGetPermitJoinStatus();
|
|
||||||
connect(getJoiningReply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandGetPermitJoiningStatusFinished);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeNetworkManager::onCommandRequestMatchDescriptorFinished()
|
void ZigbeeNetworkManager::onCommandRequestMatchDescriptorFinished()
|
||||||
{
|
{
|
||||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
@ -473,10 +471,10 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
|
|||||||
quint8 channel = static_cast<quint8>(data.at(11));
|
quint8 channel = static_cast<quint8>(data.at(11));
|
||||||
|
|
||||||
qCDebug(dcZigbeeNetwork()).noquote() << "Network" << networkStatusString;
|
qCDebug(dcZigbeeNetwork()).noquote() << "Network" << networkStatusString;
|
||||||
|
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId();
|
||||||
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress);
|
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress);
|
||||||
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
|
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
|
||||||
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId();
|
|
||||||
qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining();
|
qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining();
|
||||||
|
|
||||||
m_networkRunning = true;
|
m_networkRunning = true;
|
||||||
@ -829,6 +827,7 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
|||||||
if (m_startingState == StartingStateReadPowerDescriptor) {
|
if (m_startingState == StartingStateReadPowerDescriptor) {
|
||||||
setStartingState(StartingStateNone);
|
setStartingState(StartingStateNone);
|
||||||
setState(StateRunning);
|
setState(StateRunning);
|
||||||
|
readControllerVersion();
|
||||||
foreach (ZigbeeNode *node, nodes()) {
|
foreach (ZigbeeNode *node, nodes()) {
|
||||||
node->setConnected(true);
|
node->setConnected(true);
|
||||||
}
|
}
|
||||||
@ -1091,16 +1090,41 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
|
|||||||
|
|
||||||
void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message)
|
void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message)
|
||||||
{
|
{
|
||||||
quint8 sequenceNumber = static_cast<quint8>(message.data().at(0));
|
QByteArray data = message.data();
|
||||||
quint16 sourceAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
|
quint8 sequenceNumber = 0;
|
||||||
quint8 endPoint = static_cast<quint8>(message.data().at(3));
|
quint16 sourceAddress = 0;
|
||||||
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(4, 2));
|
quint8 endPoint = 0;
|
||||||
quint16 attributeId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(6, 2));
|
quint16 clusterId = 0;
|
||||||
quint8 attributDataType = static_cast<quint8>(message.data().at(8));
|
quint16 attributeId = 0;
|
||||||
|
quint8 attributeStatus = 0;
|
||||||
|
quint8 attributDataType = 0;
|
||||||
|
quint16 dataSize = 0;
|
||||||
|
|
||||||
|
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||||
|
stream >> sequenceNumber >> sourceAddress >> endPoint >> clusterId >> attributeId >> attributeStatus >> attributDataType >> dataSize;
|
||||||
|
|
||||||
quint16 attributeSize = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(9, 2));
|
|
||||||
QByteArray data = message.data().mid(11);
|
|
||||||
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
|
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||||
|
QByteArray attributeData = data.left(dataSize);
|
||||||
|
|
||||||
|
if (attributeData.length() != dataSize) {
|
||||||
|
qCCritical(dcZigbeeNetwork()) << "HACK";
|
||||||
|
// 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;
|
||||||
|
endPoint = 0;
|
||||||
|
clusterId = 0;
|
||||||
|
attributeId = 0;
|
||||||
|
attributeStatus = 0;
|
||||||
|
attributDataType = 0;
|
||||||
|
dataSize = 0;
|
||||||
|
|
||||||
|
QDataStream alternativeStream(&data, QIODevice::ReadOnly);
|
||||||
|
alternativeStream >> sequenceNumber >> sourceAddress >> endPoint >> clusterId >> attributeId >> attributDataType >> dataSize;
|
||||||
|
|
||||||
|
dataType = static_cast<Zigbee::DataType>(attributDataType);
|
||||||
|
attributeData = data.left(dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(dcZigbeeNetwork()) << "Attribute report:";
|
qCDebug(dcZigbeeNetwork()) << "Attribute report:";
|
||||||
qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
||||||
@ -1109,7 +1133,7 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
|
|||||||
qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
||||||
qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
|
qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
|
||||||
qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
|
qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
|
||||||
qCDebug(dcZigbeeNetwork()) << " Attribut size:" << attributeSize;
|
qCDebug(dcZigbeeNetwork()) << " Attribut size:" << dataSize;
|
||||||
qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data);
|
qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data);
|
||||||
|
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
|
|||||||
@ -54,6 +54,9 @@ private:
|
|||||||
bool m_networkRunning = false;
|
bool m_networkRunning = false;
|
||||||
bool m_factoryResetting = false;
|
bool m_factoryResetting = false;
|
||||||
|
|
||||||
|
void readControllerVersion();
|
||||||
|
void readPermitJoinStatus();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void permitJoiningChanged(bool permitJoining);
|
void permitJoiningChanged(bool permitJoining);
|
||||||
|
|
||||||
@ -65,14 +68,11 @@ private slots:
|
|||||||
void onCommandResetControllerFinished();
|
void onCommandResetControllerFinished();
|
||||||
void onCommandSoftResetControllerFinished();
|
void onCommandSoftResetControllerFinished();
|
||||||
void onCommandErasePersistentDataFinished();
|
void onCommandErasePersistentDataFinished();
|
||||||
void onCommandGetVersionFinished();
|
|
||||||
void onCommandSetExtendedPanIdFinished();
|
void onCommandSetExtendedPanIdFinished();
|
||||||
void onCommandSetChannelMaskFinished();
|
void onCommandSetChannelMaskFinished();
|
||||||
void onCommandSetNodeTypeFinished();
|
void onCommandSetNodeTypeFinished();
|
||||||
void onCommandStartNetworkFinished();
|
void onCommandStartNetworkFinished();
|
||||||
void onCommandStartScanFinished();
|
void onCommandStartScanFinished();
|
||||||
void onCommandGetPermitJoiningStatusFinished();
|
|
||||||
void onCommandPermitJoiningFinished();
|
|
||||||
void onCommandEnableWhitelistFinished();
|
void onCommandEnableWhitelistFinished();
|
||||||
|
|
||||||
void onCommandNodeDescriptorRequestFinished();
|
void onCommandNodeDescriptorRequestFinished();
|
||||||
|
|||||||
Reference in New Issue
Block a user