#include "zigbeenetworkmanager.h" #include "loggingcategory.h" #include "zigbeeutils.h" #include #include #include ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &serialPort, QObject *parent) : ZigbeeNode(new ZigbeeBridgeController(serialPort, parent), parent), m_serialPort(serialPort) { connect(controller(), &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived); if (controller()->available()) { qCDebug(dcZigbee()) << "Bridge controller started successfully on" << serialPort; } else { qCCritical(dcZigbee()) << "The zigbee controller is not available on" << serialPort; return; } QSettings settings; settings.beginGroup("Network"); m_extendedPanId = static_cast(settings.value("panId", 0).toLongLong()); qCDebug(dcZigbee()) << "Loading saved pan id" << m_extendedPanId; if (m_extendedPanId == 0) { m_extendedPanId = generateRandomPanId(); settings.setValue("panId", m_extendedPanId); } settings.endGroup(); qCDebug(dcZigbee()) << "PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); // Create channel mask // Note: normal number passed, that specific channel will be used || Bitfield: all channels would be 0x07FFF800 quint32 channelMask = 0; if (channel == 0) { qCDebug(dcZigbee()) << "Using quitest channel for the zigbee network."; } else { channelMask |= 1 << (channel); qCDebug(dcZigbee()) << "Using channel" << channel << "for the zigbee network."; } loadNetwork(); resetController(); getVersion(); init(); } bool ZigbeeNetworkManager::isAvailable() const { if (m_controller){ return m_controller->available(); } return false; } QString ZigbeeNetworkManager::controllerVersion() const { return m_controllerVersion; } QString ZigbeeNetworkManager::serialPort() const { return m_serialPort; } QList ZigbeeNetworkManager::nodeList() const { return m_nodeList; } quint64 ZigbeeNetworkManager::extendedPanId() const { return m_extendedPanId; } bool ZigbeeNetworkManager::networkRunning() const { return m_networkRunning; } quint64 ZigbeeNetworkManager::generateRandomPanId() { srand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); srand(qrand()); return (ULLONG_MAX - 0) * (qrand()/(double)RAND_MAX); } void ZigbeeNetworkManager::parseNetworkFormed(const QByteArray &data) { // Parse network status quint8 networkStatus = static_cast(data.at(0)); QString networkStatusString; if (networkStatus == 0) { networkStatusString = "joined"; } else if (networkStatus == 1) { networkStatusString = "created"; } else if (networkStatus >= 128 && networkStatus <= 244) { networkStatusString = "failed: Zigbee event code: " + QString::number(networkStatus); } else { networkStatusString = "unknown"; } quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2)); quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8)); // Parse network channel quint8 channel = static_cast(data.at(11)); qCDebug(dcZigbee()).noquote() << "Network" << networkStatusString; qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(extendedAddress); qCDebug(dcZigbee()) << " Channel:" << channel; // Set the node information setShortAddress(shortAddress); setExtendedAddress(ZigbeeAddress(extendedAddress)); } void ZigbeeNetworkManager::loadNetwork() { qCDebug(dcZigbee()) << "Loading network nodes"; QSettings settings; settings.beginGroup("Nodes"); foreach (const QString nodeAddress, settings.childGroups()) { settings.beginGroup(nodeAddress); quint16 shortAddress = static_cast(settings.value("shortAddress", 0).toUInt()); settings.endGroup(); ZigbeeNode *node = new ZigbeeNode(controller(), this); node->setExtendedAddress(ZigbeeAddress(nodeAddress)); node->setShortAddress(shortAddress); m_nodeList.append(node); //node->init(); } } void ZigbeeNetworkManager::saveNetwork() { qCDebug(dcZigbee()) << "Save network"; QSettings settings; settings.beginGroup("Nodes"); foreach (ZigbeeNode *node, m_nodeList) { settings.beginGroup(node->extendedAddress().toString()); settings.setValue("shortAddress", node->shortAddress()); settings.endGroup(); } } void ZigbeeNetworkManager::resetController() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReset)); request.setDescription("Reset controller"); request.setTimoutIntervall(3000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onResetControllerFinished); } void ZigbeeNetworkManager::erasePersistentData() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeErasePersistentData)); request.setDescription("Erase persistent data"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onErasePersistentDataFinished); } void ZigbeeNetworkManager::sendDataManagerAvailableResponse() { ZigbeeInterfaceMessage message; message.setMessageType(Zigbee::MessageTypeDataManagerAvailableResponse); message.setData(QByteArray::fromRawData("\x00\x00", 2)); ZigbeeInterfaceRequest request(message); request.setDescription("Data manager available response"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, reply, &ZigbeeInterfaceReply::deleteLater); } void ZigbeeNetworkManager::getVersion() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetVersion)); request.setDescription("Get version"); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeVersionList); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetVersionFinished); } void ZigbeeNetworkManager::setExtendedPanId(const quint64 &panId) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << panId; ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetExtendetPanId, data)); request.setDescription("Set extended PAN id " + QString::number(panId) + " " + ZigbeeUtils::convertUint64ToHexString(panId)); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetExtendedPanIdFinished); } void ZigbeeNetworkManager::setChannelMask(const quint32 &channelMask) { // Note: 10 < value < 27 -> using sinle channel value // 0x07fff800 select from all channels 11 - 26 // 0x2108800 primary zigbee light link channels 11, 15, 20, 25 QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << channelMask; ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetChannelMask, data)); request.setDescription("Set channel mask " + ZigbeeUtils::convertByteArrayToHexString(data)); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetChannelMaskFinished); } void ZigbeeNetworkManager::setDeviceType(const NodeType &deviceType) { quint8 deviceTypeValue = static_cast(deviceType); QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << deviceTypeValue; ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetDeviceType, data)); switch (deviceType) { case NodeTypeCoordinator: request.setDescription("Set device type coordinator"); break; case NodeTypeRouter: request.setDescription("Set device type router"); break; default: break; } ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetDeviceTypeFinished); } void ZigbeeNetworkManager::startNetwork() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartNetwork)); request.setDescription("Start network"); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); request.setTimoutIntervall(12000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartNetworkFinished); } void ZigbeeNetworkManager::startScan() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartScan)); request.setDescription("Start scan"); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); request.setTimoutIntervall(12000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartScanFinished); } void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 advertisingIntervall, bool tcSignificance) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << targetAddress; stream << advertisingIntervall; stream << static_cast(tcSignificance); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data)); request.setDescription("Permit joining request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress) + " for " + QString::number(advertisingIntervall) + "[s]"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onPermitJoiningFinished); } void ZigbeeNetworkManager::requestLinkQuality() { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << shortAddress(); stream << static_cast(0); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data)); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse); request.setDescription("Request link quality request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress())); request.setTimoutIntervall(5000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestLinkQualityFinished); } void ZigbeeNetworkManager::getPermitJoiningStatus() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetPermitJoining)); request.setDescription("Get permit joining status"); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeGetPermitJoiningResponse); request.setTimoutIntervall(1000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetPermitJoiningStatusFinished); } void ZigbeeNetworkManager::enableWhitelist() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkWhitelistEnable)); request.setDescription("Enable whitelist"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onEnableWhitelistFinished); } void ZigbeeNetworkManager::initiateTouchLink() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeInitiateTouchlink)); request.setDescription("Initiate touch link"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onInitiateTouchLinkFinished); } void ZigbeeNetworkManager::touchLinkFactoryReset() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeTouchlinkFactoryReset)); request.setDescription("Touch link factory reset"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onTouchLinkFactoryResetFinished); } void ZigbeeNetworkManager::networkAddressRequest(quint16 targetAddress, quint64 extendedAddress) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << targetAddress; stream << extendedAddress; stream << static_cast(1); stream << static_cast(0); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkAdressRequest, data)); request.setDescription("Network address request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress)); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkAdressResponse); request.setTimoutIntervall(1000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onNetworkAddressRequestFinished); } void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile) { // TargetAddress profile InputClusterCount InputClusterList OutputClusterCount OutputClusterList Q_UNUSED(profile) QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << shortAddress; stream << static_cast(0xFFFF); stream << static_cast(0); stream << static_cast(0); stream << static_cast(0); stream << static_cast(0); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data)); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse); request.setDescription("Request match descriptors " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); request.setTimoutIntervall(5000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished); } void ZigbeeNetworkManager::setInitialSecurity(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key) { // Note: calls ZPS_vAplSecSetInitialSecurityState // Key state: // ZPS_ZDO_PRECONFIGURED_LINK_KEY = 3 // This key will be used to encrypt the network key. This is the master or manufacturer key // ZPS_ZDO_ZLL_LINK_KEY = 4 // This key will be generated by the trust center. // Key Type: // ZPS_APS_UNIQUE_LINK_KEY = QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << keyState; stream << keySequence; stream << keyType; stream << QByteArray::fromHex(key.toUtf8()); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetSecurity, data)); request.setDescription("Set security configuration"); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetSecurityFinished); } void ZigbeeNetworkManager::authenticateDevice(const ZigbeeAddress &ieeeAddress) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << ieeeAddress.toUInt64(); stream << QByteArray::fromHex("5A6967426565416C6C69616E63653039"); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data)); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse); request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString())); request.setTimoutIntervall(5000); ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onAuthenticateDeviceFinished); } void ZigbeeNetworkManager::onResetControllerFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onErasePersistentDataFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onGetVersionFinished() { ZigbeeInterfaceReply *reply = static_cast(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_controllerVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion); qCDebug(dcZigbee()) << "Version:" << m_controllerVersion; } void ZigbeeNetworkManager::onSetExtendedPanIdFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onSetChannelMaskFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); if (reply->status() != ZigbeeInterfaceReply::Success) { qCWarning(dcZigbee()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); return; } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } void ZigbeeNetworkManager::onSetDeviceTypeFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onStartNetworkFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); if (reply->status() != ZigbeeInterfaceReply::Success) { qCWarning(dcZigbee()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); return; } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; qCDebug(dcZigbeeController()) << reply->additionalMessage(); parseNetworkFormed(reply->additionalMessage().data()); init(); loadNetwork(); } void ZigbeeNetworkManager::onStartScanFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); parseNetworkFormed(reply->additionalMessage().data()); } void ZigbeeNetworkManager::onGetPermitJoiningStatusFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); } void ZigbeeNetworkManager::onPermitJoiningFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onRequestMatchDescriptorFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); } void ZigbeeNetworkManager::onSetSecurityFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onNetworkAddressRequestFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); quint8 statusCode = static_cast(reply->additionalMessage().data().at(1)); quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(2, 8)); quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(10, 2)); quint8 deviceCount = static_cast(reply->additionalMessage().data().at(12)); quint8 startIndex = static_cast(reply->additionalMessage().data().at(13)); qCDebug(dcZigbee()) << "Network address response:"; qCDebug(dcZigbee()) << " SQN:" << sequenceNumber; qCDebug(dcZigbee()) << " Status:" << statusCode; qCDebug(dcZigbee()) << " Address:" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress); qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); qCDebug(dcZigbee()) << " Deice count:" << deviceCount; qCDebug(dcZigbee()) << " Start index:" << startIndex; } void ZigbeeNetworkManager::onAuthenticateDeviceFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); quint64 gatewayIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(0, 8)); QString encryptedKey = reply->additionalMessage().data().mid(8, 16).toHex(); QByteArray mic = reply->additionalMessage().data().mid(24, 4); quint64 initiatorIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(28, 8)); quint8 activeKeySequenceNumber = static_cast(reply->additionalMessage().data().at(36)); quint8 channel = static_cast(reply->additionalMessage().data().at(37)); quint16 shortPan = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(38, 2)); quint64 extendedPanId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(40, 8)); qCDebug(dcZigbee()) << "Authentication response:"; qCDebug(dcZigbee()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress); qCDebug(dcZigbee()) << " Key:" << encryptedKey; qCDebug(dcZigbee()) << " MIC:" << mic.toHex(); qCDebug(dcZigbee()) << " Initiator address:" << ZigbeeAddress(initiatorIeeeAddress); qCDebug(dcZigbee()) << " Active key sequence number:" << activeKeySequenceNumber; qCDebug(dcZigbee()) << " Channel:" << channel; qCDebug(dcZigbee()) << " Short PAN ID:" << ZigbeeUtils::convertUint16ToHexString(shortPan); qCDebug(dcZigbee()) << " Extended PAN ID:" << extendedPanId << ZigbeeUtils::convertUint64ToHexString(extendedPanId); } void ZigbeeNetworkManager::onEnableWhitelistFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onInitiateTouchLinkFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onTouchLinkFactoryResetFinished() { ZigbeeInterfaceReply *reply = static_cast(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"; } void ZigbeeNetworkManager::onRequestLinkQualityFinished() { ZigbeeInterfaceReply *reply = static_cast(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(); quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); quint8 statusCode = static_cast(reply->additionalMessage().data().at(1)); quint8 neighborTableEntries = static_cast(reply->additionalMessage().data().at(2)); quint8 neighborTableListCount = static_cast(reply->additionalMessage().data().at(3)); quint8 startIndex = static_cast(reply->additionalMessage().data().at(4)); qCDebug(dcZigbee()) << "LQI response:"; qCDebug(dcZigbee()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(statusCode); qCDebug(dcZigbee()) << " Neighbor table entries:" << neighborTableEntries; qCDebug(dcZigbee()) << " Neighbor table list count:" << neighborTableListCount; qCDebug(dcZigbee()) << " Start index:" << startIndex; int offset = 5; // Note: according to docs, if the table has no neigbors the list will be empty if (neighborTableEntries == 0) { qCDebug(dcZigbee()) << " There are no neigbors"; return; } for (int i = startIndex; i < neighborTableListCount; i++) { quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(offset, 2)); quint64 panId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 2, 8)); quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 10, 8)); quint8 depth = static_cast(reply->additionalMessage().data().at(offset + 18)); quint8 linkQuality = static_cast(reply->additionalMessage().data().at(offset + 19)); quint8 bitMap = static_cast(reply->additionalMessage().data().at(offset + 20)); offset += 21; qCDebug(dcZigbee()) << " Neighbor:" << i; qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); qCDebug(dcZigbee()) << " PAN id:" << panId; qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); qCDebug(dcZigbee()) << " Depth:" << depth; qCDebug(dcZigbee()) << " Link quality:" << linkQuality; qCDebug(dcZigbee()) << " BitMap:" << ZigbeeUtils::convertByteToHexString(bitMap); foreach (ZigbeeNode *node, m_nodeList) { if (node->extendedAddress() == ZigbeeAddress(ieeeAddress)) { node->setShortAddress(shortAddress); } } } } void ZigbeeNetworkManager::processLoggingMessage(const ZigbeeInterfaceMessage &message) { quint8 logLevel = static_cast(message.data().at(0)); QString logMessage = QString::fromUtf8(message.data().right(message.data().count() - 1)); QString logLevelString; switch (logLevel) { case 0: logLevelString = "Emergency:"; break; case 1: logLevelString = "Alert:"; break; case 2: logLevelString = "Critical:"; break; case 3: logLevelString = "Error:"; break; case 4: logLevelString = "Warning:"; break; case 5: logLevelString = "Notice:"; break; case 6: logLevelString = "Information:"; break; case 7: logLevelString = "Debug:"; break; default: logLevelString = "Unknown:"; break; } if (logLevel < 5) { qCWarning(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage; } else { qCDebug(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage; } } void ZigbeeNetworkManager::processFactoryNewRestart(const ZigbeeInterfaceMessage &message) { quint8 controllerStatus = static_cast(message.data().at(0)); QString controllerStatusString; switch (controllerStatus) { case 0: controllerStatusString = "startup"; break; case 2: controllerStatusString = "NRF start"; break; case 6: controllerStatusString = "running"; break; default: break; } qCDebug(dcZigbee()) << "Restart finished. Current controller state:" << controllerStatusString; } void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage &message) { quint8 sourceEndpoint = static_cast(message.data().at(0)); quint16 profileId = static_cast(message.data().at(1)); profileId <<= 8; profileId |= static_cast(message.data().at(2)); qCDebug(dcZigbeeController()) << "Node cluster list received:"; qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); QByteArray clusterListData = message.data().right(message.data().count() - 3); for (int i = 0; i < clusterListData.count(); i += 2) { quint16 clusterId = clusterListData.at(i); clusterId <<= 8; clusterId |= clusterListData .at(i + 1); qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); } } void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage &message) { quint8 sourceEndpoint = static_cast(message.data().at(0)); quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2)); quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2)); qCDebug(dcZigbeeController()) << "Node attribute list received:"; qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); QByteArray attributeListData = message.data().right(message.data().count() - 5); for (int i = 0; i < attributeListData.count(); i += 2) { quint16 attribute = ZigbeeUtils::convertByteArrayToUint16(attributeListData.mid(i, 2)); qCDebug(dcZigbeeController()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute); } } void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage &message) { quint8 sourceEndpoint = static_cast(message.data().at(0)); quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2)); quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2)); qCDebug(dcZigbeeController()) << "Node command list received:"; qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); QByteArray commandListData = message.data().right(message.data().count() - 5); for (int i = 0; i < commandListData.count(); i++) { quint8 attribute = commandListData.at(i); qCDebug(dcZigbeeController()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute); } } void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &message) { quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2)); quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(message.data().mid(2, 8)); quint8 macCapability = static_cast(message.data().at(10)); qCDebug(dcZigbee()) << "Device announced:"; qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); qCDebug(dcZigbee()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability); ZigbeeNode *node = new ZigbeeNode(controller(), this); node->setShortAddress(shortAddress); node->setExtendedAddress(ZigbeeAddress(ieeeAddress)); m_nodeList.append(node); node->init(); saveNetwork(); } void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message) { quint8 sequenceNumber = static_cast(message.data().at(0)); quint16 sourceAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2)); quint8 endPoint = static_cast(message.data().at(3)); quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(4, 2)); quint16 attributeId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(6, 2)); quint8 attributStatus = static_cast(message.data().at(8)); quint8 attributDataType = static_cast(message.data().at(9)); quint16 attributeSize = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(10, 2)); QByteArray data = message.data().mid(12); Zigbee::DataType dataType = static_cast(attributDataType); qCDebug(dcZigbee()) << "Attribute report:"; qCDebug(dcZigbee()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); qCDebug(dcZigbee()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress); qCDebug(dcZigbee()) << " End point:" << ZigbeeUtils::convertByteToHexString(endPoint); qCDebug(dcZigbee()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); qCDebug(dcZigbee()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId); qCDebug(dcZigbee()) << " Attribut status:" << ZigbeeUtils::convertByteToHexString(attributStatus); qCDebug(dcZigbee()) << " Attribut data type:" << dataType; qCDebug(dcZigbee()) << " Attribut size:" << attributeSize; qCDebug(dcZigbee()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data); switch (dataType) { case Zigbee::CharString: qCDebug(dcZigbee()) << " Data(converted)" << QString::fromUtf8(data); break; case Zigbee::Bool: qCDebug(dcZigbee()) << " Data(converted)" << QVariant(data).toBool(); break; default: break; } // TODO: find node and set attribute value } void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message) { quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2)); quint8 rejoining = static_cast(message.data().at(2)); qCDebug(dcZigbee()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining; // TODO: remove node } void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message) { if (message.data().isEmpty()) return; quint8 status = static_cast(message.data().at(0)); switch (status) { case 0: qCDebug(dcZigbee()) << "Restart provisioned: start up"; break; case 2: qCDebug(dcZigbee()) << "Restart provisioned: NFN start"; break; case 6: qCDebug(dcZigbee()) << "Restart provisioned: running"; break; default: qCDebug(dcZigbee()) << "Restart provisioned: unknown"; break; } } void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message) { switch (message.messageType()) { case Zigbee::MessageTypeLogging: processLoggingMessage(message); break; case Zigbee::MessageTypeFactoryNewRestart: processFactoryNewRestart(message); break; case Zigbee::MessageTypeNodeClusterList: processNodeClusterList(message); break; case Zigbee::MessageTypeNodeAttributeList: processNodeAttributeList(message); break; case Zigbee::MessageTypeNodeCommandIdList: processNodeCommandIdList(message); break; case Zigbee::MessageTypeDeviceAnnounce: processDeviceAnnounce(message); break; case Zigbee::MessageTypeAttributeReport: processAttributeReport(message); break; case Zigbee::MessageTypeLeaveIndication: processLeaveIndication(message); break; case Zigbee::MessageTypeNetworkJoinedFormed: parseNetworkFormed(message.data()); break; case Zigbee::MessageTypeRestartProvisioned: processRestartProvisioned(message); break; default: qCDebug(dcZigbeeController()) << "Message received:" << message; break; } }