From 3997b5a5de04c325a4398c3ae2c68c652639c67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 4 Dec 2020 14:15:35 +0100 Subject: [PATCH] Make udev optional and provide basic cluster information in node object --- .../backends/nxp/zigbeenetworknxp.cpp | 3 +- libnymea-zigbee/libnymea-zigbee.pro | 10 ++++- libnymea-zigbee/zigbeenetwork.cpp | 13 ++++++ libnymea-zigbee/zigbeenetwork.h | 7 ++++ libnymea-zigbee/zigbeenetworkdatabase.cpp | 21 ++++++---- libnymea-zigbee/zigbeenode.cpp | 25 +++++++++++ libnymea-zigbee/zigbeenode.h | 13 ++++++ libnymea-zigbee/zigbeeuartadaptermonitor.cpp | 42 ++++++++++++++++--- libnymea-zigbee/zigbeeuartadaptermonitor.h | 9 ++++ 9 files changed, 126 insertions(+), 17 deletions(-) diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp index 98854d9..e550733 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp @@ -415,7 +415,6 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr setChannel(channel); // Initialize the coordinator node if not already done. - if (m_coordinatorNode) { if (!macAddress().isNull() && ZigbeeAddress(ieeeAddress) != macAddress()) { qCWarning(dcZigbeeNetwork()) << "The mac address of the coordinator has changed since the network has been set up."; @@ -427,6 +426,7 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr } qCDebug(dcZigbeeNetwork()) << "We already have the coordinator node. Network starting done."; + setNodeInformation(m_coordinatorNode, "NXP", "JN516x", bridgeController()->firmwareVersion()); m_database->saveNode(m_coordinatorNode); setPermitJoining(0); setState(StateRunning); @@ -440,6 +440,7 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ if (state == ZigbeeNode::StateInitialized) { qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode; + setNodeInformation(m_coordinatorNode, "NXP", "JN516x", bridgeController()->firmwareVersion()); /* Note: this currently has been hardcoded into the firmware. TODO: implement appropriate method for binding coordinator to group ZigbeeClusterGroups *groupsCluster = coordinatorNode->getEndpoint(0x01)->inputCluster(ZigbeeClusterLibrary::ClusterIdGroups); diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index f5481b5..ffe5456 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -3,8 +3,14 @@ include(../config.pri) TARGET = nymea-zigbee1 TEMPLATE = lib -CONFIG += link_pkgconfig -PKGCONFIG += libudev + +disable_udev { + message(Build without libudev support) + DEFINES += DISABLE_UDEV +} else { + CONFIG += link_pkgconfig + PKGCONFIG += libudev +} SOURCES += \ backends/deconz/interface/zigbeeinterfacedeconz.cpp \ diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 7992772..a9f1084 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -541,6 +541,7 @@ void ZigbeeNetwork::addUnitializedNode(ZigbeeNode *node) }); m_uninitializedNodes.append(node); + emit nodeJoined(node); } void ZigbeeNetwork::removeNode(ZigbeeNode *node) @@ -562,6 +563,18 @@ void ZigbeeNetwork::setNodeReachable(ZigbeeNode *node, bool reachable) node->setReachable(reachable); } +void ZigbeeNetwork::setNodeInformation(ZigbeeNode *node, const QString &manufacturerName, const QString &modelName, const QString &version) +{ + node->m_manufacturerName = manufacturerName; + emit node->manufacturerNameChanged(node->manufacturerName()); + + node->m_modelName = modelName; + emit node->modelNameChanged(node->modelName()); + + node->m_version = version; + emit node->versionChanged(node->version()); +} + void ZigbeeNetwork::setState(ZigbeeNetwork::State state) { if (m_state == state) diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index f35e176..4619c70 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -192,6 +192,9 @@ protected: void setNodeReachable(ZigbeeNode *node, bool reachable); + // Set the coordinator infromation since they cannot be fetched + void setNodeInformation(ZigbeeNode *node, const QString &manufacturerName, const QString &modelName, const QString &version); + void setState(State state); void setError(Error error); @@ -218,9 +221,13 @@ signals: void channelMaskChanged(const ZigbeeChannelMask &channelMask); void securityConfigurationChanged(const ZigbeeSecurityConfiguration &securityConfiguration); + // Will be emitted if node has joined and the initialization has been finished void nodeAdded(ZigbeeNode *node); void nodeRemoved(ZigbeeNode *node); + // Will be emited when a node joined and starts initializing + void nodeJoined(ZigbeeNode *node); + void permitJoiningEnabledChanged(bool permitJoiningEnabled); void permitJoinDurationChanged(quint8 duration); void permitJoinRemainingChanged(quint8 remaining); diff --git a/libnymea-zigbee/zigbeenetworkdatabase.cpp b/libnymea-zigbee/zigbeenetworkdatabase.cpp index 56fbfe8..281bfd6 100644 --- a/libnymea-zigbee/zigbeenetworkdatabase.cpp +++ b/libnymea-zigbee/zigbeenetworkdatabase.cpp @@ -139,19 +139,24 @@ QList ZigbeeNetworkDatabase::loadNodes() } } - // Set the basic cluster attributes if present + // Set the basic cluster attributes if present to endpoint and node if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) { ZigbeeClusterBasic *basicCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdBasic); - if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeManufacturerName)) - endpoint->m_manufacturerName = basicCluster->attribute(ZigbeeClusterBasic::AttributeManufacturerName).dataType().toString(); + if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeManufacturerName)) { + endpoint->setManufacturerName(basicCluster->attribute(ZigbeeClusterBasic::AttributeManufacturerName).dataType().toString()); + node->m_manufacturerName = endpoint->manufacturerName(); + } - if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeModelIdentifier)) - endpoint->m_modelIdentifier = basicCluster->attribute(ZigbeeClusterBasic::AttributeModelIdentifier).dataType().toString(); - - if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeSwBuildId)) - endpoint->m_softwareBuildId = basicCluster->attribute(ZigbeeClusterBasic::AttributeSwBuildId).dataType().toString(); + if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeModelIdentifier)) { + endpoint->setModelIdentifier(basicCluster->attribute(ZigbeeClusterBasic::AttributeModelIdentifier).dataType().toString()); + node->m_modelName = endpoint->modelIdentifier(); + } + if (basicCluster->hasAttribute(ZigbeeClusterBasic::AttributeSwBuildId)) { + endpoint->setSoftwareBuildId(basicCluster->attribute(ZigbeeClusterBasic::AttributeSwBuildId).dataType().toString()); + node->m_version = endpoint->softwareBuildId(); + } } // Load output clusters for this endpoint diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index 331147a..4530792 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -92,6 +92,21 @@ ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const return nullptr; } +QString ZigbeeNode::manufacturerName() const +{ + return m_manufacturerName; +} + +QString ZigbeeNode::modelName() const +{ + return m_modelName; +} + +QString ZigbeeNode::version() const +{ + return m_version; +} + quint8 ZigbeeNode::lqi() const { return m_lqi; @@ -522,6 +537,8 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster) QString manufacturerName = basicCluster->attribute(attributeId).dataType().toString(&valueOk); if (valueOk) { endpoints().first()->m_manufacturerName = manufacturerName; + m_manufacturerName = manufacturerName; + emit manufacturerNameChanged(m_manufacturerName); } else { qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << basicCluster->attribute(attributeId).dataType(); } @@ -557,6 +574,8 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster) QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk); if (valueOk) { endpoints().first()->m_manufacturerName = manufacturerName; + m_manufacturerName = manufacturerName; + emit manufacturerNameChanged(m_manufacturerName); } else { qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType; } @@ -581,6 +600,8 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster) QString modelIdentifier = basicCluster->attribute(attributeId).dataType().toString(&valueOk); if (valueOk) { endpoints().first()->m_modelIdentifier= modelIdentifier; + m_modelName = modelIdentifier; + emit modelNameChanged(m_modelName); } else { qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << basicCluster->attribute(attributeId).dataType(); } @@ -616,6 +637,8 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster) QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk); if (valueOk) { endpoints().first()->m_modelIdentifier = modelIdentifier; + m_modelName = modelIdentifier; + emit modelNameChanged(m_modelName); } else { qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType; } @@ -657,6 +680,8 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster) QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk); if (valueOk) { endpoints().first()->m_softwareBuildId = softwareBuildId; + m_version = softwareBuildId; + emit versionChanged(m_version); } else { qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType; } diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index a798f32..0f07777 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -72,6 +72,11 @@ public: bool hasEndpoint(quint8 endpointId) const; ZigbeeNodeEndpoint *getEndpoint(quint8 endpointId) const; + // Basic cluster infomation + QString manufacturerName() const; + QString modelName() const; + QString version() const; + quint8 lqi() const; QDateTime lastSeen() const; @@ -102,6 +107,11 @@ private: quint16 m_shortAddress = 0; ZigbeeAddress m_extendedAddress; + // Basic cluster infomation + QString m_manufacturerName; + QString m_modelName; + QString m_version; + ZigbeeDeviceObject *m_deviceObject = nullptr; QList m_endpoints; bool m_reachable = false; @@ -144,6 +154,9 @@ signals: void stateChanged(State state); void lqiChanged(quint8 lqi); void lastSeenChanged(const QDateTime &lastSeen); + void manufacturerNameChanged(const QString &manufacturerName); + void modelNameChanged(const QString &modelName); + void versionChanged(const QString &version); void reachableChanged(bool reachable); void bindingTableRecordsChanged(); void clusterAdded(ZigbeeCluster *cluster); diff --git a/libnymea-zigbee/zigbeeuartadaptermonitor.cpp b/libnymea-zigbee/zigbeeuartadaptermonitor.cpp index e9a5bfa..bc58fec 100644 --- a/libnymea-zigbee/zigbeeuartadaptermonitor.cpp +++ b/libnymea-zigbee/zigbeeuartadaptermonitor.cpp @@ -30,23 +30,49 @@ #include +#ifndef DISABLE_UDEV #include +#endif ZigbeeUartAdapterMonitor::ZigbeeUartAdapterMonitor(QObject *parent) : QObject(parent) { qRegisterMetaType(); + // Read initially all tty devices + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + addAdapterInternally(serialPortInfo.systemLocation()); + } + +#ifdef DISABLE_UDEV + m_timer = new QTimer(this); + m_timer->setInterval(5000); + m_timer->setSingleShot(false); + connect(m_timer, &QTimer::timeout, this, [=](){ + QStringList availablePorts; + // Add a new adapter if not in the list already + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + availablePorts.append(serialPortInfo.systemLocation()); + if (!m_availableAdapters.contains(serialPortInfo.systemLocation())) { + addAdapterInternally(serialPortInfo.systemLocation()); + } + } + // Remove adapters no longer available + foreach (const QString &systemLocation, m_availableAdapters.keys()) { + if (!availablePorts.contains(systemLocation)) { + emit adapterRemoved(m_availableAdapters.take(systemLocation)); + } + } + + }); + +#else + // Init udev m_udev = udev_new(); if (!m_udev) { qCWarning(dcZigbeeAdapterMonitor()) << "Could not initialize udev for the adapter monitor"; return; } - // Read initially all tty devices - foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { - addAdapterInternally(serialPortInfo.systemLocation()); - } - // Create udev monitor m_monitor = udev_monitor_new_from_netlink(m_udev, "udev"); if (!m_monitor) { @@ -124,11 +150,15 @@ ZigbeeUartAdapterMonitor::ZigbeeUartAdapterMonitor(QObject *parent) : QObject(pa }); m_notifier->setEnabled(true); +#endif + m_isValid = true; } ZigbeeUartAdapterMonitor::~ZigbeeUartAdapterMonitor() { +#ifndef DISABLE_UDEV + if (m_notifier) delete m_notifier; @@ -137,7 +167,7 @@ ZigbeeUartAdapterMonitor::~ZigbeeUartAdapterMonitor() if (m_udev) udev_unref(m_udev); - +#endif } QList ZigbeeUartAdapterMonitor::availableAdapters() const diff --git a/libnymea-zigbee/zigbeeuartadaptermonitor.h b/libnymea-zigbee/zigbeeuartadaptermonitor.h index 28ab619..94cb7ba 100644 --- a/libnymea-zigbee/zigbeeuartadaptermonitor.h +++ b/libnymea-zigbee/zigbeeuartadaptermonitor.h @@ -31,6 +31,10 @@ #include #include +#ifdef DISABLE_UDEV +#include +#endif + #include "zigbeeuartadapter.h" class ZigbeeUartAdapterMonitor : public QObject @@ -47,9 +51,14 @@ public: private: bool m_isValid = false; + +#ifdef DISABLE_UDEV + QTimer *m_timer = nullptr; +#else struct udev *m_udev = nullptr; struct udev_monitor *m_monitor = nullptr; QSocketNotifier *m_notifier = nullptr; +#endif QHash m_availableAdapters;