Add cluster and attribute base classes and improve node initialization

This commit is contained in:
Simon Stürz 2019-05-16 02:54:17 +02:00
parent 2922a87449
commit 7745f09581
19 changed files with 725 additions and 132 deletions

View File

@ -14,6 +14,7 @@ ZigbeeInterface::ZigbeeInterface(QObject *parent) :
ZigbeeInterface::~ZigbeeInterface() ZigbeeInterface::~ZigbeeInterface()
{ {
qCCritical(dcZigbeeInterface()) << "Destroy interface";
disable(); disable();
} }
@ -127,14 +128,21 @@ void ZigbeeInterface::onReadyRead()
// Check message sanity // Check message sanity
quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data); quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data);
if (crc != m_crcValue) { if (crc != m_crcValue) {
qCWarning(dcZigbeeInterface()) << "Invalid CRC value" << crc << "!=" << m_crcValue; qCWarning(dcZigbeeInterface()) << "Received message end: Invalid CRC value" << crc << "!=" << m_crcValue;
} else if (m_data.count() != m_lengthValue) { } else if (m_data.count() != m_lengthValue) {
qCWarning(dcZigbeeInterface()) << "ERROR:s Invalid data length" << m_data.count() << "!=" << m_lengthValue; qCWarning(dcZigbeeInterface()) << "Received message end: Invalid data length of message" << m_data.count() << "!=" << m_lengthValue;
} else { } else {
// We got a valid message // We got a valid message
ZigbeeInterfaceMessage message(messageType, m_data); ZigbeeInterfaceMessage message(messageType, m_data);
qCDebug(dcZigbeeInterface()) << "<--" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(m_crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(m_lengthValue); qCDebug(dcZigbeeInterface()) << "<--" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(m_crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(m_lengthValue);
emit messageReceived(message); emit messageReceived(message);
// Clear all information for the next byte
m_crcValue = 0;
m_messageTypeValue = 0;
m_lengthValue = 0;
m_escapeDetected = false;
m_data.clear();
} }
setReadingState(WaitForStart); setReadingState(WaitForStart);
break; break;
@ -150,6 +158,7 @@ void ZigbeeInterface::onReadyRead()
// Read data bytes depending on the reading state // Read data bytes depending on the reading state
switch (m_readingState) { switch (m_readingState) {
case WaitForStart: case WaitForStart:
qCWarning(dcZigbeeInterfaceTraffic()) << "Wait for start but reviced data:" << byte;
break; break;
case WaitForTypeMsb: case WaitForTypeMsb:
m_messageTypeValue = byte; m_messageTypeValue = byte;

View File

@ -11,6 +11,8 @@ SOURCES += \
interface/zigbeeinterfacerequest.cpp \ interface/zigbeeinterfacerequest.cpp \
interface/zigbeeinterfacereply.cpp \ interface/zigbeeinterfacereply.cpp \
nxp/nxpzigbeenetworkmanager.cpp \ nxp/nxpzigbeenetworkmanager.cpp \
zigbeecluster.cpp \
zigbeeclusterattribute.cpp \
zigbeenetwork.cpp \ zigbeenetwork.cpp \
zigbeenetworkmanager.cpp \ zigbeenetworkmanager.cpp \
zigbee.cpp \ zigbee.cpp \
@ -27,6 +29,8 @@ HEADERS += \
interface/zigbeeinterfacerequest.h \ interface/zigbeeinterfacerequest.h \
interface/zigbeeinterfacereply.h \ interface/zigbeeinterfacereply.h \
nxp/nxpzigbeenetworkmanager.h \ nxp/nxpzigbeenetworkmanager.h \
zigbeecluster.h \
zigbeeclusterattribute.h \
zigbeenetwork.h \ zigbeenetwork.h \
zigbeenetworkmanager.h \ zigbeenetworkmanager.h \
zigbee.h \ zigbee.h \

View File

@ -1,6 +1,7 @@
#include "loggingcategory.h" #include "loggingcategory.h"
Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork") Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork")
Q_LOGGING_CATEGORY(dcZigbeeNode, "ZigbeeNode")
Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface")
Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController")
Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic")

View File

@ -5,6 +5,7 @@
#include <QLoggingCategory> #include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNode)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController)
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic)

View File

@ -216,6 +216,7 @@ public:
enum ClusterId { enum ClusterId {
// Basics // Basics
ClusterIdUnknown = 0xffff,
ClusterIdBasic = 0x0000, ClusterIdBasic = 0x0000,
ClusterIdPower = 0x0001, ClusterIdPower = 0x0001,
ClusterIdDeviceTemperature = 0x0002, ClusterIdDeviceTemperature = 0x0002,
@ -292,6 +293,24 @@ public:
}; };
Q_ENUM(ClusterId) Q_ENUM(ClusterId)
enum ClusterAttributeBasic {
ClusterAttributeBasicZclVersion = 0x0000,
ClusterAttributeBasicApplicationVersion = 0x0001,
ClusterAttributeBasicStackVersion = 0x0002,
ClusterAttributeBasicHardwareVersion = 0x0003,
ClusterAttributeBasicManufacturerName = 0x0004,
ClusterAttributeBasicModelIdentifier = 0x0005,
ClusterAttributeBasicDataCode = 0x0006,
ClusterAttributeBasicPowerSource = 0x0007,
ClusterAttributeBasicLocationDescription = 0x0010,
ClusterAttributeBasicPhysicalEnvironment = 0x0011,
ClusterAttributeBasicDeviceEnabled = 0x0012,
ClusterAttributeBasicAlarmMask = 0x0013,
ClusterAttributeBasicDisableLocalConfig = 0x0014,
ClusterAttributeBasicSoftwareBuildId = 0x4000
};
Q_ENUM(ClusterAttributeBasic)
enum LightLinkDevice { enum LightLinkDevice {
// Lightning devices // Lightning devices

View File

@ -12,6 +12,11 @@ ZigbeeBridgeController::ZigbeeBridgeController(QObject *parent) :
connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived); connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived);
} }
ZigbeeBridgeController::~ZigbeeBridgeController()
{
qCDebug(dcZigbeeController()) << "Destroy controller";
}
bool ZigbeeBridgeController::available() const bool ZigbeeBridgeController::available() const
{ {
return m_interface->available(); return m_interface->available();
@ -247,7 +252,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandAuthenticateDevice(const Zi
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data)); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse);
request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString())); request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString()));
request.setTimoutIntervall(5000); request.setTimoutIntervall(2000);
return sendRequest(request); return sendRequest(request);
} }
@ -261,7 +266,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandNodeDescriptorRequest(quint
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data)); ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse);
request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(10000); request.setTimoutIntervall(5000);
return sendRequest(request); return sendRequest(request);
} }

View File

@ -16,6 +16,7 @@ class ZigbeeBridgeController : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ZigbeeBridgeController(QObject *parent = nullptr); explicit ZigbeeBridgeController(QObject *parent = nullptr);
~ZigbeeBridgeController();
bool available() const; bool available() const;

View File

@ -0,0 +1,59 @@
#include "zigbeeutils.h"
#include "zigbeecluster.h"
ZigbeeCluster::ZigbeeCluster(Zigbee::ClusterId clusterId, QObject *parent) :
QObject(parent),
m_clusterId(clusterId)
{
}
Zigbee::ClusterId ZigbeeCluster::clusterId() const
{
return m_clusterId;
}
QString ZigbeeCluster::clusterName() const
{
return ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(m_clusterId));
}
QList<ZigbeeClusterAttribute> ZigbeeCluster::attributes() const
{
return m_attributes.values();
}
bool ZigbeeCluster::hasAttribute(quint16 attributeId) const
{
if (m_attributes.keys().isEmpty())
return false;
return m_attributes.keys().contains(attributeId);
}
ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 id)
{
return m_attributes.value(id);
}
void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute)
{
if (hasAttribute(attribute.id())) {
if (m_attributes.value(attribute.id()) != attribute) {
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
}
} else {
m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute);
}
}
QDebug operator<<(QDebug debug, ZigbeeCluster *cluster)
{
debug.nospace().noquote() << "ZigbeeCluster("
<< ZigbeeUtils::convertUint16ToHexString(static_cast<quint16>(cluster->clusterId())) << ", "
<< cluster->clusterName() << ")";
return debug.space();
}

View File

@ -0,0 +1,42 @@
#ifndef ZIGBEECLUSTER_H
#define ZIGBEECLUSTER_H
#include <QObject>
#include "zigbee.h"
#include "zigbeeclusterattribute.h"
class ZigbeeCluster : public QObject
{
Q_OBJECT
friend class ZigbeeNode;
public:
explicit ZigbeeCluster(Zigbee::ClusterId clusterId, QObject *parent = nullptr);
Zigbee::ClusterId clusterId() const;
QString clusterName() const;
QList<ZigbeeClusterAttribute> attributes() const;
bool hasAttribute(quint16 attributeId) const;
ZigbeeClusterAttribute attribute(quint16 id);
private:
Zigbee::ClusterId m_clusterId = Zigbee::ClusterIdUnknown;
QHash<quint16, ZigbeeClusterAttribute> m_attributes;
protected:
void setAttribute(const ZigbeeClusterAttribute &attribute);
signals:
void attributeChanged(const ZigbeeClusterAttribute &attribute);
public slots:
};
QDebug operator<<(QDebug debug, ZigbeeCluster *cluster);
#endif // ZIGBEECLUSTER_H

View File

@ -0,0 +1,73 @@
#include "zigbeeutils.h"
#include "zigbeeclusterattribute.h"
ZigbeeClusterAttribute::ZigbeeClusterAttribute()
{
}
ZigbeeClusterAttribute::ZigbeeClusterAttribute(quint16 id, Zigbee::DataType dataType, QByteArray data):
m_id(id),
m_dataType(dataType),
m_data(data)
{
}
ZigbeeClusterAttribute::ZigbeeClusterAttribute(const ZigbeeClusterAttribute &other)
{
m_id = other.id();
m_dataType = other.dataType();
m_data = other.data();
}
quint16 ZigbeeClusterAttribute::id() const
{
return m_id;
}
Zigbee::DataType ZigbeeClusterAttribute::dataType() const
{
return m_dataType;
}
QByteArray ZigbeeClusterAttribute::data() const
{
return m_data;
}
ZigbeeClusterAttribute &ZigbeeClusterAttribute::operator=(const ZigbeeClusterAttribute &other)
{
m_id = other.id();
m_dataType = other.dataType();
m_data = other.data();
return *this;
}
bool ZigbeeClusterAttribute::operator==(const ZigbeeClusterAttribute &other) const
{
return m_id == other.id() &&
m_dataType == other.dataType() &&
m_data == other.data();
}
bool ZigbeeClusterAttribute::operator!=(const ZigbeeClusterAttribute &other) const
{
return !operator==(other);
}
bool ZigbeeClusterAttribute::isValid() const
{
return m_id != 0 ||
m_dataType != Zigbee::NoData ||
!m_data.isNull();
}
QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute)
{
debug.nospace().noquote() << "ZigbeeClusterAttribute("
<< ZigbeeUtils::convertUint16ToHexString(attribute.id()) << ", "
<< attribute.dataType() << ", "
<< ZigbeeUtils::convertByteArrayToHexString(attribute.data()) << ")";
return debug.space();
}

View File

@ -0,0 +1,34 @@
#ifndef ZIGBEECLUSTERATTRIBUTE_H
#define ZIGBEECLUSTERATTRIBUTE_H
#include <QDebug>
#include "zigbee.h"
class ZigbeeClusterAttribute
{
public:
ZigbeeClusterAttribute();
ZigbeeClusterAttribute(quint16 id, Zigbee::DataType dataType, QByteArray data);
ZigbeeClusterAttribute(const ZigbeeClusterAttribute &other);
quint16 id() const;
Zigbee::DataType dataType() const;
QByteArray data() const;
ZigbeeClusterAttribute &operator=(const ZigbeeClusterAttribute &other);
bool operator==(const ZigbeeClusterAttribute &other) const;
bool operator!=(const ZigbeeClusterAttribute &other) const;
bool isValid() const;
private:
quint16 m_id = 0;
Zigbee::DataType m_dataType = Zigbee::NoData;
QByteArray m_data;
};
QDebug operator<<(QDebug debug, const ZigbeeClusterAttribute &attribute);
#endif // ZIGBEECLUSTERATTRIBUTE_H

View File

@ -120,6 +120,12 @@ ZigbeeNode *ZigbeeNetwork::coordinatorNode() const
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
{ {
foreach (ZigbeeNode *node, m_uninitializedNodes) {
if (node->shortAddress() == shortAddress) {
return node;
}
}
foreach (ZigbeeNode *node, m_nodes) { foreach (ZigbeeNode *node, m_nodes) {
if (node->shortAddress() == shortAddress) { if (node->shortAddress() == shortAddress) {
return node; return node;
@ -131,6 +137,12 @@ ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(const ZigbeeAddress &address) const ZigbeeNode *ZigbeeNetwork::getZigbeeNode(const ZigbeeAddress &address) const
{ {
foreach (ZigbeeNode *node, m_uninitializedNodes) {
if (node->extendedAddress() == address) {
return node;
}
}
foreach (ZigbeeNode *node, m_nodes) { foreach (ZigbeeNode *node, m_nodes) {
if (node->extendedAddress() == address) { if (node->extendedAddress() == address) {
return node; return node;
@ -164,11 +176,52 @@ void ZigbeeNetwork::saveNetwork()
settings.endGroup(); settings.endGroup();
settings.beginWriteArray("Nodes"); settings.beginWriteArray("Nodes");
for (int i = 0; i < nodes().count(); i++) { for (int x = 0; x < nodes().count(); x++) {
settings.setArrayIndex(i); settings.setArrayIndex(x);
settings.setValue("nwkAddress", nodes().at(i)->shortAddress()); ZigbeeNode *node = nodes().at(x);
settings.setValue("ieeeAddress", nodes().at(i)->extendedAddress().toString()); settings.setValue("nwkAddress", node->shortAddress());
settings.setValue("ieeeAddress", node->extendedAddress().toString());
// TODO: save the rest of the node // TODO: save the rest of the node
// Input clusters
settings.beginWriteArray("inputCluster");
for (int i = 0; i < node->inputClusters().count(); i++) {
settings.setArrayIndex(i);
ZigbeeCluster *cluster = node->inputClusters().at(i);
settings.setValue("id", static_cast<int>(cluster->clusterId()));
settings.beginWriteArray("attributes");
settings.beginWriteArray("attributes");
for (int j = 0; j < cluster->attributes().count(); j++) {
settings.setArrayIndex(j);
ZigbeeClusterAttribute attribute = cluster->attributes().at(j);
settings.setValue("id", attribute.id());
settings.setValue("dataType", static_cast<int>(attribute.dataType()));
settings.setValue("data", attribute.data());
}
settings.endArray();
}
settings.endArray();
// Output clusters
settings.beginWriteArray("outputCluster");
for (int i = 0; i < node->outputClusters().count(); i++) {
settings.setArrayIndex(i);
ZigbeeCluster *cluster = node->outputClusters().at(i);
settings.setValue("id", static_cast<int>(cluster->clusterId()));
settings.beginWriteArray("attributes");
settings.beginWriteArray("attributes");
for (int j = 0; j < cluster->attributes().count(); j++) {
settings.setArrayIndex(j);
ZigbeeClusterAttribute attribute = cluster->attributes().at(j);
settings.setValue("id", attribute.id());
settings.setValue("dataType", static_cast<int>(attribute.dataType()));
settings.setValue("data", attribute.data());
}
settings.endArray();
}
settings.endArray();
} }
settings.endArray(); settings.endArray();
} }
@ -178,27 +231,78 @@ void ZigbeeNetwork::loadNetwork()
qCDebug(dcZigbeeNetwork()) << "Load current network configuration from" << m_settingsFileName; qCDebug(dcZigbeeNetwork()) << "Load current network configuration from" << m_settingsFileName;
QSettings settings(m_settingsFileName, QSettings::IniFormat, this); QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Network"); settings.beginGroup("Network");
quint64 extendedPanId = static_cast<quint64>(settings.value("panId", 0).toUInt()); quint64 extendedPanId = static_cast<quint64>(settings.value("panId", 0).toULongLong());
if (extendedPanId == 0) { if (extendedPanId == 0) {
extendedPanId = ZigbeeUtils::generateRandomPanId(); extendedPanId = ZigbeeUtils::generateRandomPanId();
qCDebug(dcZigbeeNetwork()) << "Create new PAN id" << extendedPanId; qCDebug(dcZigbeeNetwork()) << "Create new PAN ID" << extendedPanId;
} }
setExtendedPanId(extendedPanId); setExtendedPanId(extendedPanId);
setChannel(settings.value("channel", 0).toUInt()); setChannel(settings.value("channel", 0).toUInt());
settings.endGroup(); settings.endGroup();
int nodesCount = settings.beginReadArray("Nodes"); int nodesCount = settings.beginReadArray("Nodes");
for (int i = 0; i < nodesCount; i++) { for (int x = 0; x < nodesCount; x++) {
settings.setArrayIndex(i); settings.setArrayIndex(x);
ZigbeeNode *node = new ZigbeeNode(this); ZigbeeNode *node = createNode();
node->setShortAddress(static_cast<quint16>(settings.value("nwkAddress", 0).toUInt())); node->setShortAddress(static_cast<quint16>(settings.value("nwkAddress", 0).toUInt()));
node->setExtendedAddress(ZigbeeAddress(settings.value("ieeeAddress").toString())); node->setExtendedAddress(ZigbeeAddress(settings.value("ieeeAddress").toString()));
// TODO: load the rest of the node // TODO: load the rest of the node
// Input clusters
int inputClusterCount =settings.beginReadArray("inputCluster");
for (int i = 0; i < inputClusterCount; i++) {
settings.setArrayIndex(i);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("id", 0).toInt());
settings.beginWriteArray("attributes");
int attributeCount = settings.beginReadArray("attributes");
if (attributeCount == 0) {
node->setClusterAttribute(clusterId);
} else {
for (int j = 0; j < attributeCount; j++) {
settings.setArrayIndex(i);
ZigbeeClusterAttribute attribute;
quint16 id = static_cast<quint16>(settings.value("id", 0).toInt());
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(settings.value("dataType", 0).toInt());
QByteArray data = settings.value("data").toByteArray();
node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data));
}
}
settings.endArray();
}
settings.endArray();
// Output clusters
int outputClusterCount =settings.beginReadArray("outputCluster");
for (int i = 0; i < outputClusterCount; i++) {
settings.setArrayIndex(i);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("id", 0).toInt());
settings.beginWriteArray("attributes");
int attributeCount = settings.beginReadArray("attributes");
if (attributeCount == 0) {
node->setClusterAttribute(clusterId);
} else {
for (int j = 0; j < attributeCount; j++) {
settings.setArrayIndex(i);
ZigbeeClusterAttribute attribute;
quint16 id = static_cast<quint16>(settings.value("id", 0).toInt());
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(settings.value("dataType", 0).toInt());
QByteArray data = settings.value("data").toByteArray();
node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data));
}
}
settings.endArray();
}
settings.endArray();
node->setState(StateInitialized);
addNodeInternally(node); addNodeInternally(node);
} }
settings.endArray(); settings.endArray();
qCDebug(dcZigbeeNetwork()) << "Extended PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); qCDebug(dcZigbeeNetwork()) << "Extended PAN ID:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId);
qCDebug(dcZigbeeNetwork()) << "Channel" << m_channel; qCDebug(dcZigbeeNetwork()) << "Channel" << m_channel;
qCDebug(dcZigbeeNetwork()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count()); qCDebug(dcZigbeeNetwork()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count());
foreach (ZigbeeNode *node, nodes()) { foreach (ZigbeeNode *node, nodes()) {
@ -206,16 +310,21 @@ void ZigbeeNetwork::loadNetwork()
} }
} }
void ZigbeeNetwork::addNode(ZigbeeNode *node) void ZigbeeNetwork::addNode(ZigbeeNode *node)
{ {
if (hasNode(node->extendedAddress())) { addNodeInternally(node);
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added."; saveNetwork();
}
void ZigbeeNetwork::addUnitializedNode(ZigbeeNode *node)
{
if (m_uninitializedNodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "The uninitialized node" << node << "has already been added.";
return; return;
} }
m_nodes.append(node); m_uninitializedNodes.append(node);
emit nodeAdded(node);
saveNetwork();
} }
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node) void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
@ -231,13 +340,7 @@ void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
void ZigbeeNetwork::removeNode(ZigbeeNode *node) void ZigbeeNetwork::removeNode(ZigbeeNode *node)
{ {
if (!m_nodes.contains(node)) { removeNodeInternally(node);
qCWarning(dcZigbeeNetwork()) << "Try to remove node" << node << "but not in the node list.";
return;
}
m_nodes.removeAll(node);
emit nodeRemoved(node);
saveNetwork(); saveNetwork();
} }
@ -253,6 +356,13 @@ void ZigbeeNetwork::removeNodeInternally(ZigbeeNode *node)
node->deleteLater(); node->deleteLater();
} }
ZigbeeNode *ZigbeeNetwork::createNode()
{
ZigbeeNode *node = new ZigbeeNode(this);
connect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
return node;
}
void ZigbeeNetwork::clearSettings() void ZigbeeNetwork::clearSettings()
{ {
qCDebug(dcZigbeeNetwork()) << "Clear network settings"; qCDebug(dcZigbeeNetwork()) << "Clear network settings";
@ -296,3 +406,12 @@ void ZigbeeNetwork::setError(ZigbeeNetwork::Error error)
emit errorOccured(m_error); emit errorOccured(m_error);
} }
void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state)
{
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());
if (state == ZigbeeNode::StateInitialized && m_uninitializedNodes.contains(node)) {
m_uninitializedNodes.removeAll(node);
addNode(node);
}
}

View File

@ -87,15 +87,19 @@ private:
QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf"; QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf";
QList<ZigbeeNode *> m_nodes; QList<ZigbeeNode *> m_nodes;
QList<ZigbeeNode *> m_uninitializedNodes;
void saveNetwork(); void saveNetwork();
void loadNetwork(); void loadNetwork();
void addNodeInternally(ZigbeeNode *node);
void removeNodeInternally(ZigbeeNode *node);
protected: protected:
void addNode(ZigbeeNode *node); void addNode(ZigbeeNode *node);
void addNodeInternally(ZigbeeNode *node); void addUnitializedNode(ZigbeeNode *node);
void removeNode(ZigbeeNode *node); void removeNode(ZigbeeNode *node);
void removeNodeInternally(ZigbeeNode *node);
ZigbeeNode *createNode();
void clearSettings(); void clearSettings();
@ -118,6 +122,9 @@ signals:
void stateChanged(State state); void stateChanged(State state);
void errorOccured(Error error); void errorOccured(Error error);
private slots:
void onNodeStateChanged(ZigbeeNode::State state);
public slots: public slots:
virtual void startNetwork() = 0; virtual void startNetwork() = 0;
virtual void stopNetwork() = 0; virtual void stopNetwork() = 0;

View File

@ -480,8 +480,7 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
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()) << " Extended PAN ID:" << extendedPanId();
qCDebug(dcZigbeeNetwork()) << " Permit joining" << permitJoining(); qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining();
m_networkRunning = true; m_networkRunning = true;
@ -490,7 +489,7 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
setExtendedAddress(ZigbeeAddress(extendedAddress)); setExtendedAddress(ZigbeeAddress(extendedAddress));
setChannel(channel); setChannel(channel);
addNode(this); addUnitializedNode(this);
} }
void ZigbeeNetworkManager::onCommandEnableWhitelistFinished() void ZigbeeNetworkManager::onCommandEnableWhitelistFinished()
@ -519,42 +518,40 @@ void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished()
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage(); qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
Q_UNUSED(sequenceNumber) QByteArray data = reply->additionalMessage().data();
Q_UNUSED(status)
quint16 shortAddress = static_cast<quint16>(reply->additionalMessage().data().at(2)); quint8 sequenceNumber = 0;
shortAddress <<= 8; quint8 status = 0;
shortAddress |= reply->additionalMessage().data().at(3); quint16 shortAddress = 0;
quint16 manufacturerCode = 0;
quint16 maximalRxSize = 0;
quint16 maximalTxSize = 0;
quint16 serverMask = 0;
quint8 descriptorFlag = 0;
quint8 macFlags = 0;
quint8 maxBufferSize = 0;
quint16 bitField = 0;
quint16 manufacturerCode = static_cast<quint16>(reply->additionalMessage().data().at(4)); QDataStream stream(&data, QIODevice::ReadOnly);
manufacturerCode <<= 8; stream >> sequenceNumber;
manufacturerCode |= reply->additionalMessage().data().at(5); stream >> status;
stream >> shortAddress;
quint16 maximalRxSize = static_cast<quint16>(reply->additionalMessage().data().at(6)); stream >> manufacturerCode;
maximalRxSize <<= 8; stream >> maximalRxSize;
maximalRxSize |= reply->additionalMessage().data().at(7); stream >> maximalTxSize;
stream >> serverMask;
quint16 maximalTxSize = static_cast<quint16>(reply->additionalMessage().data().at(8)); stream >> descriptorFlag;
maximalTxSize <<= 8; stream >> macFlags;
maximalTxSize |= reply->additionalMessage().data().at(9); stream >> maxBufferSize;
stream >> bitField;
quint16 serverMask = static_cast<quint16>(reply->additionalMessage().data().at(10));
serverMask <<= 8;
serverMask |= reply->additionalMessage().data().at(11);
quint8 descriptorFlag = static_cast<quint8>(reply->additionalMessage().data().at(12));
quint8 macFlags = static_cast<quint8>(reply->additionalMessage().data().at(13));
quint8 maxBufferSize = static_cast<quint8>(reply->additionalMessage().data().at(14));
quint16 bitField = static_cast<quint16>(reply->additionalMessage().data().at(15));
bitField <<= 8;
bitField |= reply->additionalMessage().data().at(16);
// Get node object // Get node object
ZigbeeNode *node = getZigbeeNode(shortAddress); ZigbeeNode *node = getZigbeeNode(shortAddress);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
return;
}
// Set node data // Set node data
node->setManufacturerCode(manufacturerCode); node->setManufacturerCode(manufacturerCode);
@ -570,7 +567,7 @@ void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished()
if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
node->setNodeType(NodeTypeCoordinator); node->setNodeType(NodeTypeCoordinator);
} else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) { } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) {
node->setNodeType(NodeTypeCoordinator); node->setNodeType(NodeTypeRouter);
} else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
node->setNodeType(NodeTypeEndDevice); node->setNodeType(NodeTypeEndDevice);
} }
@ -625,36 +622,39 @@ void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished()
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage(); qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0)); QByteArray data = reply->additionalMessage().data();
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint16 nwkAddress = static_cast<quint16>(reply->additionalMessage().data().at(2)); quint8 sequenceNumber = 0;
nwkAddress <<= 8; quint8 status = 0;
nwkAddress |= reply->additionalMessage().data().at(3); quint16 shortAddress = 0;
quint8 length = 0;
quint8 endPoint = 0;
quint16 profileId = 0;
quint16 deviceId = 0;
quint8 bitField = 0;
quint8 inputClusterCount = 0;
quint8 outputClusterCount = 0;
quint8 length = static_cast<quint8>(reply->additionalMessage().data().at(4)); QDataStream stream(&data, QIODevice::ReadOnly);
stream >> sequenceNumber;
stream >> status;
stream >> shortAddress;
stream >> length;
if (length == 0) { if (length == 0) {
qCWarning(dcZigbeeNetwork()) << "Length 0"; qCWarning(dcZigbeeNetwork()) << "Simple node descriptior has a length of 0.";
return; return;
} }
quint8 endPoint = static_cast<quint8>(reply->additionalMessage().data().at(5)); stream >> endPoint;
stream >> profileId;
quint16 profileId = static_cast<quint16>(reply->additionalMessage().data().at(6)); stream >> deviceId;
profileId <<= 8; stream >> bitField;
profileId |= reply->additionalMessage().data().at(7);
quint16 deviceId = static_cast<quint16>(reply->additionalMessage().data().at(8));
deviceId <<= 8;
deviceId |= reply->additionalMessage().data().at(9);
quint8 bitField = static_cast<quint8>(reply->additionalMessage().data().at(10));
qCDebug(dcZigbeeNetwork()) << "Node simple descriptor:"; qCDebug(dcZigbeeNetwork()) << "Node simple descriptor:";
qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbeeNetwork()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); qCDebug(dcZigbeeNetwork()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); qCDebug(dcZigbeeNetwork()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length);
qCDebug(dcZigbeeNetwork()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint); qCDebug(dcZigbeeNetwork()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint);
qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId)); qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
@ -667,30 +667,40 @@ void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished()
qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField); qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField);
quint8 inputClusterCount = static_cast<quint8>(reply->additionalMessage().data().at(10)); stream >> inputClusterCount;
qCDebug(dcZigbeeNetwork()) << " Input clusters: (" << inputClusterCount << ")";
qCDebug(dcZigbeeNetwork()) << " Input clusters:"; for (int i = 0; i < inputClusterCount; i+=1) {
QByteArray inputClusterListData = reply->additionalMessage().data().mid(11, inputClusterCount * 2); quint16 clusterId = 0;
for (int i = 0; i < inputClusterListData.count(); i+=2) { stream >> clusterId;
quint16 clusterId = static_cast<quint16>(inputClusterListData.at(i));
clusterId <<= 8;
clusterId |= inputClusterListData .at(i+1);
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId)); qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
} }
quint8 outputClusterCount = static_cast<quint8>(reply->additionalMessage().data().at(12 + inputClusterCount * 2)); stream >> outputClusterCount;
qCDebug(dcZigbeeNetwork()) << " Output clusters: (" << outputClusterCount << ")";
qCDebug(dcZigbeeNetwork()) << " Output clusters:"; for (int i = 0; i < outputClusterCount; i+=1) {
QByteArray outputClusterListData = reply->additionalMessage().data().mid(12 + inputClusterCount * 2, outputClusterCount * 2); if (stream.atEnd()) {
for (int i = 0; i < outputClusterListData.count(); i+=2) { qCWarning(dcZigbeeNode()) << "Data stream already at the end but more data expected. Looks like the firmware doesn't provide more data.";
quint16 clusterId = static_cast<quint16>(outputClusterListData.at(i)); break;
clusterId <<= 8; }
clusterId |= outputClusterListData .at(i+1);
quint16 clusterId = 0;
stream >> clusterId;
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId)); qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
} }
// Get node object
ZigbeeNode *node = getZigbeeNode(shortAddress);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor);
return;
}
// Set node data
node->setEndPoint(endPoint);
node->setZigbeeProfile(static_cast<Zigbee::ZigbeeProfile>(profileId));
node->setDeviceId(deviceId);
if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor); if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor);
} }
@ -699,8 +709,24 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender()); ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater(); reply->deleteLater();
// Note: get the short address from the request data
QByteArray requestData = reply->request().message().data();
quint16 shortAddress;
QDataStream stream(&requestData, QIODevice::ReadOnly);
stream >> shortAddress;
if (reply->status() != ZigbeeInterfaceReply::Success) { if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
// Note: the power descriptor is the last request from the initialization
ZigbeeNode *node = getZigbeeNode(shortAddress);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor);
return;
}
if (node->state() != ZigbeeNode::StateInitialized) {
node->setState(ZigbeeNode::StateInitialized);
}
return; return;
} }
@ -712,19 +738,20 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
quint16 bitField = static_cast<quint16>(reply->additionalMessage().data().at(2)); quint16 bitField = static_cast<quint16>(reply->additionalMessage().data().at(2));
bitField <<= 8; bitField <<= 8;
bitField |= reply->additionalMessage().data().at(3); bitField |= static_cast<quint8>(reply->additionalMessage().data().at(3));
// Bit 0 - 3 Power mode // Bit 0 - 3 Power mode
// 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor // 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
// 0001: Receiver switched on periodically // 0001: Receiver switched on periodically
// 0010: Receiver switched on when stimulated, e.g. by pressing a button // 0010: Receiver switched on when stimulated, e.g. by pressing a button
ZigbeeNode::PowerMode powerMode = PowerModeAlwaysOn;
if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeAlwaysOn; powerMode = PowerModeAlwaysOn;
} else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeOnPeriodically; powerMode = PowerModeOnPeriodically;
} else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) { } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeOnWhenStimulated; powerMode = PowerModeOnWhenStimulated;
} }
// Bit 4 - 7 Available power sources // Bit 4 - 7 Available power sources
@ -733,21 +760,23 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
// Bit 2: Disposable battery // Bit 2: Disposable battery
// Bit 4: Reserved // Bit 4: Reserved
QList<ZigbeeNode::PowerSource> availablePowerSources;
if (ZigbeeUtils::checkBitUint16(bitField, 4)) { if (ZigbeeUtils::checkBitUint16(bitField, 4)) {
m_availablePowerSources.append(PowerSourcePermanentMainSupply); availablePowerSources.append(PowerSourcePermanentMainSupply);
} else if (ZigbeeUtils::checkBitUint16(bitField, 5)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 5)) {
m_availablePowerSources.append(PowerSourceRecharchableBattery); availablePowerSources.append(PowerSourceRecharchableBattery);
} else if (ZigbeeUtils::checkBitUint16(bitField, 6)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 6)) {
m_availablePowerSources.append(PowerSourceDisposableBattery); availablePowerSources.append(PowerSourceDisposableBattery);
} }
// Bit 8 - 11 Active source: according to the same schema as available power sources // Bit 8 - 11 Active source: according to the same schema as available power sources
ZigbeeNode::PowerSource powerSource = PowerSourcePermanentMainSupply;
if (ZigbeeUtils::checkBitUint16(bitField, 8)) { if (ZigbeeUtils::checkBitUint16(bitField, 8)) {
m_powerSource = PowerSourcePermanentMainSupply; powerSource = PowerSourcePermanentMainSupply;
} else if (ZigbeeUtils::checkBitUint16(bitField, 9)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 9)) {
m_powerSource = PowerSourceRecharchableBattery; powerSource = PowerSourceRecharchableBattery;
} else if (ZigbeeUtils::checkBitUint16(bitField, 10)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 10)) {
m_powerSource = PowerSourceDisposableBattery; powerSource = PowerSourceDisposableBattery;
} }
// Bit 12 - 15: Battery level if available // Bit 12 - 15: Battery level if available
@ -755,15 +784,15 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
// 0100: Approximately 33% // 0100: Approximately 33%
// 1000: Approximately 66% // 1000: Approximately 66%
// 1100: Approximately 100% (near fully charged) // 1100: Approximately 100% (near fully charged)
ZigbeeNode::PowerLevel powerLevel = PowerLevelCriticalLow;
if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelCriticalLow; powerLevel = PowerLevelCriticalLow;
} else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelLow; powerLevel = PowerLevelLow;
} else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { } else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelOk; powerLevel = PowerLevelOk;
} else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelFull; powerLevel = PowerLevelFull;
} }
qCDebug(dcZigbeeNetwork()) << "Node power descriptor:"; qCDebug(dcZigbeeNetwork()) << "Node power descriptor:";
@ -772,12 +801,32 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
qCDebug(dcZigbeeNetwork()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField); qCDebug(dcZigbeeNetwork()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField);
qCDebug(dcZigbeeNetwork()) << " Power mode:" << m_powerMode; qCDebug(dcZigbeeNetwork()) << " Power mode:" << m_powerMode;
qCDebug(dcZigbeeNetwork()) << " Available power sources:"; qCDebug(dcZigbeeNetwork()) << " Available power sources:";
foreach (const PowerSource &source, m_availablePowerSources) { foreach (const PowerSource &source, availablePowerSources) {
qCDebug(dcZigbeeNetwork()) << " " << source; qCDebug(dcZigbeeNetwork()) << " " << source;
} }
qCDebug(dcZigbeeNetwork()) << " Power source:" << m_powerSource; qCDebug(dcZigbeeNetwork()) << " Power source:" << powerSource;
qCDebug(dcZigbeeNetwork()) << " Power level:" << m_powerLevel; qCDebug(dcZigbeeNetwork()) << " Power level:" << powerLevel;
// Get node object
ZigbeeNode *node = getZigbeeNode(shortAddress);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor);
return;
}
// Set node data
node->setPowerMode(powerMode);
node->setPowerSource(powerSource);
node->setAvailablePowerSources(availablePowerSources);
node->setPowerLevel(powerLevel);
// Note: the power descriptor is the last request from the initialization
if (node->state() != ZigbeeNode::StateInitialized) {
node->setState(ZigbeeNode::StateInitialized);
}
// Note: the power descriptor request for the coordinator is the last step from the network init process
if (m_startingState == StartingStateReadPowerDescriptor) { if (m_startingState == StartingStateReadPowerDescriptor) {
setStartingState(StartingStateNone); setStartingState(StartingStateNone);
setState(StateRunning); setState(StateRunning);
@ -1013,7 +1062,7 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress); qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag); qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag);
ZigbeeNode *node = new ZigbeeNode(this); ZigbeeNode *node = createNode();
node->setShortAddress(shortAddress); node->setShortAddress(shortAddress);
node->setExtendedAddress(ZigbeeAddress(ieeeAddress)); node->setExtendedAddress(ZigbeeAddress(ieeeAddress));
node->setMacCapabilitiesFlag(macCapabilitiesFlag); node->setMacCapabilitiesFlag(macCapabilitiesFlag);
@ -1021,7 +1070,8 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
qCDebug(dcZigbeeNetwork()) << " Node:" << node; qCDebug(dcZigbeeNetwork()) << " Node:" << node;
// FIXME: check if node already added, and if we have to update it // FIXME: check if node already added, and if we have to update it
addNode(node); addUnitializedNode(node);
node->setState(StateInitializing);
ZigbeeInterfaceReply *reply = nullptr; ZigbeeInterfaceReply *reply = nullptr;
reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey()); reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey());
@ -1071,8 +1121,13 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
break; break;
} }
// TODO: find node and set attribute value ZigbeeNode *node = getZigbeeNode(sourceAddress);
if (!node) {
qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
return;
}
node->setClusterAttribute(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeClusterAttribute(attributeId, dataType, data));
} }
void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message) void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message)
@ -1080,23 +1135,16 @@ void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &
QByteArray data = message.data(); QByteArray data = message.data();
quint64 extendedAddress = 0; quint64 extendedAddress = 0;
bool rejoining = 0; bool rejoining = 0;
QDataStream stream(&data, QIODevice::ReadOnly); QDataStream stream(&data, QIODevice::ReadOnly);
stream >> extendedAddress; stream >> extendedAddress;
stream >> rejoining; stream >> rejoining;
ZigbeeAddress address(extendedAddress); ZigbeeAddress address(extendedAddress);
// ZigbeeAddress extendedAddress = ZigbeeAddress(ZigbeeUtils::convertByteArrayToUint64(message.data().mid(0, 8)));
// quint8 rejoining = static_cast<quint8>(message.data().at(9));
qCDebug(dcZigbeeNetwork()) << "Node leaving indication:" << address.toString() << "rejoining:" << rejoining; qCDebug(dcZigbeeNetwork()) << "Node leaving indication:" << address.toString() << "rejoining:" << rejoining;
ZigbeeNode *node = getZigbeeNode(address); ZigbeeNode *node = getZigbeeNode(address);
if (node) { if (node) removeNode(node);
removeNode(node);
}
// TODO: remove node
} }
void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message) void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message)

View File

@ -10,6 +10,11 @@ ZigbeeNode::ZigbeeNode(QObject *parent) :
} }
ZigbeeNode::State ZigbeeNode::state() const
{
return m_state;
}
quint16 ZigbeeNode::shortAddress() const quint16 ZigbeeNode::shortAddress() const
{ {
return m_shortAddress; return m_shortAddress;
@ -50,6 +55,11 @@ quint16 ZigbeeNode::manufacturerCode() const
return m_manufacturerCode; return m_manufacturerCode;
} }
quint16 ZigbeeNode::deviceId() const
{
return m_deviceId;
}
bool ZigbeeNode::complexDescriptorAvailable() const bool ZigbeeNode::complexDescriptorAvailable() const
{ {
return m_complexDescriptorAvailable; return m_complexDescriptorAvailable;
@ -75,6 +85,36 @@ quint8 ZigbeeNode::maximumBufferSize() const
return m_maximumBufferSize; return m_maximumBufferSize;
} }
QList<ZigbeeCluster *> ZigbeeNode::inputClusters() const
{
return m_inputClusters.values();
}
ZigbeeCluster *ZigbeeNode::getInputCluster(Zigbee::ClusterId clusterId) const
{
return m_inputClusters.value(clusterId);
}
bool ZigbeeNode::hasInputCluster(Zigbee::ClusterId clusterId) const
{
return m_inputClusters.keys().contains(clusterId);
}
QList<ZigbeeCluster *> ZigbeeNode::outputClusters() const
{
return m_outputClusters.values();
}
bool ZigbeeNode::hasOutputCluster(Zigbee::ClusterId clusterId) const
{
return m_outputClusters.keys().contains(clusterId);
}
ZigbeeCluster *ZigbeeNode::getOutputCluster(Zigbee::ClusterId clusterId) const
{
return m_outputClusters.value(clusterId);
}
bool ZigbeeNode::isPrimaryTrustCenter() const bool ZigbeeNode::isPrimaryTrustCenter() const
{ {
return m_isPrimaryTrustCenter; return m_isPrimaryTrustCenter;
@ -170,6 +210,16 @@ ZigbeeNode::PowerLevel ZigbeeNode::powerLevel() const
return m_powerLevel; return m_powerLevel;
} }
void ZigbeeNode::setState(ZigbeeNode::State state)
{
if (m_state == state)
return;
qCDebug(dcZigbeeNode()) << "State changed" << state;
m_state = state;
emit stateChanged(m_state);
}
//void ZigbeeNode::identify() //void ZigbeeNode::identify()
//{ //{
@ -246,6 +296,11 @@ void ZigbeeNode::setManufacturerCode(quint16 manufacturerCode)
m_manufacturerCode = manufacturerCode; m_manufacturerCode = manufacturerCode;
} }
void ZigbeeNode::setDeviceId(quint16 deviceId)
{
m_deviceId = deviceId;
}
void ZigbeeNode::setMaximumRxSize(quint16 size) void ZigbeeNode::setMaximumRxSize(quint16 size)
{ {
m_maximumRxSize = size; m_maximumRxSize = size;
@ -303,6 +358,57 @@ void ZigbeeNode::setDescriptorFlag(quint8 descriptorFlag)
m_extendedSimpleDescriptorListAvailable = ((descriptorFlag >> 1) & 0x01); m_extendedSimpleDescriptorListAvailable = ((descriptorFlag >> 1) & 0x01);
} }
void ZigbeeNode::setPowerMode(ZigbeeNode::PowerMode powerMode)
{
m_powerMode = powerMode;
}
void ZigbeeNode::setPowerSource(ZigbeeNode::PowerSource powerSource)
{
m_powerSource = powerSource;
}
void ZigbeeNode::setAvailablePowerSources(QList<ZigbeeNode::PowerSource> availablePowerSources)
{
m_availablePowerSources = availablePowerSources;
}
void ZigbeeNode::setPowerLevel(ZigbeeNode::PowerLevel powerLevel)
{
m_powerLevel = powerLevel;
}
void ZigbeeNode::setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute)
{
//qCDebug(dcZigbeeNode()) << this << "cluster attribute changed" << clusterId << attribute;
ZigbeeCluster *cluster = m_outputClusters.value(clusterId);
// Note: create the cluster if not there yet
bool clusterCreated = false;
if (!cluster) {
cluster = new ZigbeeCluster(clusterId, this);
qCWarning(dcZigbeeNode()) << "Created cluster" << cluster;
connect(cluster, &ZigbeeCluster::attributeChanged, this, &ZigbeeNode::onClusterAttributeChanged);
m_outputClusters.insert(clusterId, cluster);
clusterCreated = true;
}
// Set the attribute if valid
if (attribute.isValid())
cluster->setAttribute(attribute);
if (clusterCreated)
emit clusterAdded(cluster);
}
void ZigbeeNode::onClusterAttributeChanged(const ZigbeeClusterAttribute &attribute)
{
ZigbeeCluster *cluster = static_cast<ZigbeeCluster *>(sender());
qCDebug(dcZigbeeNode()) << "Cluster" << cluster << "attribute changed" << attribute;
emit clusterAttributeChanged(cluster, attribute);
}
//void ZigbeeNode::onRequestUserDescriptorFinished() //void ZigbeeNode::onRequestUserDescriptorFinished()
//{ //{
// ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender()); // ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());

View File

@ -4,6 +4,7 @@
#include <QObject> #include <QObject>
#include "zigbee.h" #include "zigbee.h"
#include "zigbeecluster.h"
#include "zigbeeaddress.h" #include "zigbeeaddress.h"
class ZigbeeNode : public QObject class ZigbeeNode : public QObject
@ -14,6 +15,13 @@ class ZigbeeNode : public QObject
friend class ZigbeeNetworkManager; friend class ZigbeeNetworkManager;
public: public:
enum State {
StateUninitialized,
StateInitializing,
StateInitialized
};
Q_ENUM(State)
enum NodeType { enum NodeType {
NodeTypeCoordinator = 0, NodeTypeCoordinator = 0,
NodeTypeRouter = 1, NodeTypeRouter = 1,
@ -63,7 +71,7 @@ public:
}; };
Q_ENUM(PowerLevel) Q_ENUM(PowerLevel)
ZigbeeNode(QObject *parent = nullptr); State state() const;
quint16 shortAddress() const; quint16 shortAddress() const;
ZigbeeAddress extendedAddress() const; ZigbeeAddress extendedAddress() const;
@ -75,6 +83,7 @@ public:
Relationship relationship() const; Relationship relationship() const;
Zigbee::ZigbeeProfile profile() const; Zigbee::ZigbeeProfile profile() const;
quint16 manufacturerCode() const; quint16 manufacturerCode() const;
quint16 deviceId() const;
bool complexDescriptorAvailable() const; bool complexDescriptorAvailable() const;
bool userDescriptorAvailable() const; bool userDescriptorAvailable() const;
@ -83,6 +92,14 @@ public:
quint16 maximumTxSize() const; quint16 maximumTxSize() const;
quint8 maximumBufferSize() const; quint8 maximumBufferSize() const;
QList<ZigbeeCluster *> inputClusters() const;
ZigbeeCluster *getInputCluster(Zigbee::ClusterId clusterId) const;
bool hasInputCluster(Zigbee::ClusterId clusterId) const;
QList<ZigbeeCluster *> outputClusters() const;
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const;
bool hasOutputCluster(Zigbee::ClusterId clusterId) const;
// Server Mask // Server Mask
bool isPrimaryTrustCenter() const; bool isPrimaryTrustCenter() const;
bool isBackupTrustCenter() const; bool isBackupTrustCenter() const;
@ -111,6 +128,12 @@ public:
PowerLevel powerLevel() const; PowerLevel powerLevel() const;
private: private:
ZigbeeNode(QObject *parent = nullptr);
State m_state = StateUninitialized;
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_inputClusters;
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_outputClusters;
quint16 m_shortAddress = 0; quint16 m_shortAddress = 0;
ZigbeeAddress m_extendedAddress; ZigbeeAddress m_extendedAddress;
quint8 m_endPoint = 1; quint8 m_endPoint = 1;
@ -120,6 +143,7 @@ private:
Relationship m_relationship = Parent; Relationship m_relationship = Parent;
Zigbee::ZigbeeProfile m_profile; Zigbee::ZigbeeProfile m_profile;
quint16 m_manufacturerCode = 0; quint16 m_manufacturerCode = 0;
quint16 m_deviceId = 0;
bool m_complexDescriptorAvailable = false; bool m_complexDescriptorAvailable = false;
bool m_userDescriptorAvailable = false; bool m_userDescriptorAvailable = false;
@ -156,6 +180,8 @@ private:
bool m_extendedSimpleDescriptorListAvailable = false; bool m_extendedSimpleDescriptorListAvailable = false;
protected: protected:
void setState(State state);
void setShortAddress(const quint16 &shortAddress); void setShortAddress(const quint16 &shortAddress);
void setExtendedAddress(const ZigbeeAddress &extendedAddress); void setExtendedAddress(const ZigbeeAddress &extendedAddress);
void setEndPoint(quint8 endPoint); void setEndPoint(quint8 endPoint);
@ -165,6 +191,7 @@ protected:
void setRelationship(Relationship relationship); void setRelationship(Relationship relationship);
void setZigbeeProfile(Zigbee::ZigbeeProfile profile); void setZigbeeProfile(Zigbee::ZigbeeProfile profile);
void setManufacturerCode(quint16 manufacturerCode); void setManufacturerCode(quint16 manufacturerCode);
void setDeviceId(quint16 deviceType);
void setMaximumRxSize(quint16 size); void setMaximumRxSize(quint16 size);
void setMaximumTxSize(quint16 size); void setMaximumTxSize(quint16 size);
@ -176,6 +203,22 @@ protected:
void setMacCapabilitiesFlag(quint16 macFlag); void setMacCapabilitiesFlag(quint16 macFlag);
void setDescriptorFlag(quint8 descriptorFlag); void setDescriptorFlag(quint8 descriptorFlag);
void setPowerMode(PowerMode powerMode);
void setPowerSource(PowerSource powerSource);
void setAvailablePowerSources(QList<PowerSource> availablePowerSources);
void setPowerLevel(PowerLevel powerLevel);
// Cluster commands
void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute());
signals:
void stateChanged(State state);
void clusterAdded(ZigbeeCluster *cluster);
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
private slots:
void onClusterAttributeChanged(const ZigbeeClusterAttribute &attribute);
}; };
QDebug operator<<(QDebug debug, ZigbeeNode *node); QDebug operator<<(QDebug debug, ZigbeeNode *node);

View File

@ -11,6 +11,16 @@ ZigbeeSecurityConfiguration::ZigbeeSecurityConfiguration(const ZigbeeSecurityCon
m_globalTrustCenterLinkKey = other.networkKey(); m_globalTrustCenterLinkKey = other.networkKey();
} }
ZigbeeSecurityConfiguration::ZigbeeSecurityMode ZigbeeSecurityConfiguration::zigbeeSecurityMode() const
{
return m_zigbeeSecurityMode;
}
void ZigbeeSecurityConfiguration::setZigbeeSecurityMode(ZigbeeSecurityConfiguration::ZigbeeSecurityMode zigbeeSecurityMode)
{
m_zigbeeSecurityMode = zigbeeSecurityMode;
}
QString ZigbeeSecurityConfiguration::networkKey() const QString ZigbeeSecurityConfiguration::networkKey() const
{ {
return m_networkKey; return m_networkKey;
@ -33,12 +43,14 @@ void ZigbeeSecurityConfiguration::setGlobalTrustCenterlinkKey(const QString &glo
void ZigbeeSecurityConfiguration::clear() void ZigbeeSecurityConfiguration::clear()
{ {
m_zigbeeSecurityMode = ZigbeeSecurityModeNone;
m_networkKey.clear(); m_networkKey.clear();
m_globalTrustCenterLinkKey = "5A6967426565416C6C69616E63653039";
} }
bool ZigbeeSecurityConfiguration::operator==(const ZigbeeSecurityConfiguration &other) const bool ZigbeeSecurityConfiguration::operator==(const ZigbeeSecurityConfiguration &other) const
{ {
return m_networkKey == other.networkKey() && m_globalTrustCenterLinkKey == other.globalTrustCenterLinkKey(); return m_networkKey == other.networkKey() && m_globalTrustCenterLinkKey == other.globalTrustCenterLinkKey() && m_zigbeeSecurityMode == other.zigbeeSecurityMode();
} }
bool ZigbeeSecurityConfiguration::operator!=(const ZigbeeSecurityConfiguration &other) const bool ZigbeeSecurityConfiguration::operator!=(const ZigbeeSecurityConfiguration &other) const

View File

@ -6,9 +6,18 @@
class ZigbeeSecurityConfiguration class ZigbeeSecurityConfiguration
{ {
public: public:
enum ZigbeeSecurityMode {
ZigbeeSecurityModeNone,
ZigbeeSecurityModeNetworkLayer,
ZigbeeSecurityModeApplicationLayer
};
explicit ZigbeeSecurityConfiguration(); explicit ZigbeeSecurityConfiguration();
ZigbeeSecurityConfiguration(const ZigbeeSecurityConfiguration &other); ZigbeeSecurityConfiguration(const ZigbeeSecurityConfiguration &other);
ZigbeeSecurityMode zigbeeSecurityMode() const;
void setZigbeeSecurityMode(ZigbeeSecurityMode zigbeeSecurityMode);
QString networkKey() const; QString networkKey() const;
void setNetworkKey(const QString &networkKey); void setNetworkKey(const QString &networkKey);
@ -21,6 +30,8 @@ public:
bool operator!=(const ZigbeeSecurityConfiguration &other) const; bool operator!=(const ZigbeeSecurityConfiguration &other) const;
private: private:
ZigbeeSecurityMode m_zigbeeSecurityMode = ZigbeeSecurityModeNone;
// This is the local network key // This is the local network key
QString m_networkKey; QString m_networkKey;

View File

@ -133,7 +133,6 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
quint64 ZigbeeUtils::generateRandomPanId() quint64 ZigbeeUtils::generateRandomPanId()
{ {
srand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000)); qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000));
srand(static_cast<uint>(qrand()));
return static_cast<quint64>((ULLONG_MAX - 0) * (qrand()/static_cast<double>(RAND_MAX))); return static_cast<quint64>((ULLONG_MAX - 0) * (qrand()/static_cast<double>(RAND_MAX)));
} }