Make udev optional and provide basic cluster information in node object

This commit is contained in:
Simon Stürz 2020-12-04 14:15:35 +01:00
parent 72150b6bfb
commit 3997b5a5de
9 changed files with 126 additions and 17 deletions

View File

@ -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<ZigbeeClusterGroups>(ZigbeeClusterLibrary::ClusterIdGroups);

View File

@ -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 \

View File

@ -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)

View File

@ -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);

View File

@ -139,19 +139,24 @@ QList<ZigbeeNode *> 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<ZigbeeClusterBasic>(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

View File

@ -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;
}

View File

@ -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<ZigbeeNodeEndpoint *> 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);

View File

@ -30,23 +30,49 @@
#include <QSerialPortInfo>
#ifndef DISABLE_UDEV
#include <libudev.h>
#endif
ZigbeeUartAdapterMonitor::ZigbeeUartAdapterMonitor(QObject *parent) : QObject(parent)
{
qRegisterMetaType<ZigbeeUartAdapter>();
// 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<ZigbeeUartAdapter> ZigbeeUartAdapterMonitor::availableAdapters() const

View File

@ -31,6 +31,10 @@
#include <QObject>
#include <QSocketNotifier>
#ifdef DISABLE_UDEV
#include <QTimer>
#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<QString, ZigbeeUartAdapter> m_availableAdapters;