Add cluster and attribute base classes and improve node initialization
This commit is contained in:
parent
2922a87449
commit
7745f09581
@ -14,6 +14,7 @@ ZigbeeInterface::ZigbeeInterface(QObject *parent) :
|
||||
|
||||
ZigbeeInterface::~ZigbeeInterface()
|
||||
{
|
||||
qCCritical(dcZigbeeInterface()) << "Destroy interface";
|
||||
disable();
|
||||
}
|
||||
|
||||
@ -127,14 +128,21 @@ void ZigbeeInterface::onReadyRead()
|
||||
// Check message sanity
|
||||
quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data);
|
||||
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) {
|
||||
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 {
|
||||
// We got a valid message
|
||||
ZigbeeInterfaceMessage message(messageType, m_data);
|
||||
qCDebug(dcZigbeeInterface()) << "<--" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(m_crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(m_lengthValue);
|
||||
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);
|
||||
break;
|
||||
@ -150,6 +158,7 @@ void ZigbeeInterface::onReadyRead()
|
||||
// Read data bytes depending on the reading state
|
||||
switch (m_readingState) {
|
||||
case WaitForStart:
|
||||
qCWarning(dcZigbeeInterfaceTraffic()) << "Wait for start but reviced data:" << byte;
|
||||
break;
|
||||
case WaitForTypeMsb:
|
||||
m_messageTypeValue = byte;
|
||||
|
||||
@ -11,6 +11,8 @@ SOURCES += \
|
||||
interface/zigbeeinterfacerequest.cpp \
|
||||
interface/zigbeeinterfacereply.cpp \
|
||||
nxp/nxpzigbeenetworkmanager.cpp \
|
||||
zigbeecluster.cpp \
|
||||
zigbeeclusterattribute.cpp \
|
||||
zigbeenetwork.cpp \
|
||||
zigbeenetworkmanager.cpp \
|
||||
zigbee.cpp \
|
||||
@ -27,6 +29,8 @@ HEADERS += \
|
||||
interface/zigbeeinterfacerequest.h \
|
||||
interface/zigbeeinterfacereply.h \
|
||||
nxp/nxpzigbeenetworkmanager.h \
|
||||
zigbeecluster.h \
|
||||
zigbeeclusterattribute.h \
|
||||
zigbeenetwork.h \
|
||||
zigbeenetworkmanager.h \
|
||||
zigbee.h \
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "loggingcategory.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork")
|
||||
Q_LOGGING_CATEGORY(dcZigbeeNode, "ZigbeeNode")
|
||||
Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface")
|
||||
Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController")
|
||||
Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic")
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNode)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic)
|
||||
|
||||
@ -216,6 +216,7 @@ public:
|
||||
|
||||
enum ClusterId {
|
||||
// Basics
|
||||
ClusterIdUnknown = 0xffff,
|
||||
ClusterIdBasic = 0x0000,
|
||||
ClusterIdPower = 0x0001,
|
||||
ClusterIdDeviceTemperature = 0x0002,
|
||||
@ -292,6 +293,24 @@ public:
|
||||
};
|
||||
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 {
|
||||
// Lightning devices
|
||||
|
||||
@ -12,6 +12,11 @@ ZigbeeBridgeController::ZigbeeBridgeController(QObject *parent) :
|
||||
connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived);
|
||||
}
|
||||
|
||||
ZigbeeBridgeController::~ZigbeeBridgeController()
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Destroy controller";
|
||||
}
|
||||
|
||||
bool ZigbeeBridgeController::available() const
|
||||
{
|
||||
return m_interface->available();
|
||||
@ -247,7 +252,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandAuthenticateDevice(const Zi
|
||||
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data));
|
||||
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse);
|
||||
request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString()));
|
||||
request.setTimoutIntervall(5000);
|
||||
request.setTimoutIntervall(2000);
|
||||
|
||||
return sendRequest(request);
|
||||
}
|
||||
@ -261,7 +266,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandNodeDescriptorRequest(quint
|
||||
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data));
|
||||
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse);
|
||||
request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
|
||||
request.setTimoutIntervall(10000);
|
||||
request.setTimoutIntervall(5000);
|
||||
|
||||
return sendRequest(request);
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ class ZigbeeBridgeController : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ZigbeeBridgeController(QObject *parent = nullptr);
|
||||
~ZigbeeBridgeController();
|
||||
|
||||
bool available() const;
|
||||
|
||||
|
||||
59
libnymea-zigbee/zigbeecluster.cpp
Normal file
59
libnymea-zigbee/zigbeecluster.cpp
Normal 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();
|
||||
}
|
||||
42
libnymea-zigbee/zigbeecluster.h
Normal file
42
libnymea-zigbee/zigbeecluster.h
Normal 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
|
||||
73
libnymea-zigbee/zigbeeclusterattribute.cpp
Normal file
73
libnymea-zigbee/zigbeeclusterattribute.cpp
Normal 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();
|
||||
}
|
||||
34
libnymea-zigbee/zigbeeclusterattribute.h
Normal file
34
libnymea-zigbee/zigbeeclusterattribute.h
Normal 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
|
||||
@ -120,6 +120,12 @@ ZigbeeNode *ZigbeeNetwork::coordinatorNode() const
|
||||
|
||||
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
|
||||
{
|
||||
foreach (ZigbeeNode *node, m_uninitializedNodes) {
|
||||
if (node->shortAddress() == shortAddress) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ZigbeeNode *node, m_nodes) {
|
||||
if (node->shortAddress() == shortAddress) {
|
||||
return node;
|
||||
@ -131,6 +137,12 @@ ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
|
||||
|
||||
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(const ZigbeeAddress &address) const
|
||||
{
|
||||
foreach (ZigbeeNode *node, m_uninitializedNodes) {
|
||||
if (node->extendedAddress() == address) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ZigbeeNode *node, m_nodes) {
|
||||
if (node->extendedAddress() == address) {
|
||||
return node;
|
||||
@ -164,11 +176,52 @@ void ZigbeeNetwork::saveNetwork()
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginWriteArray("Nodes");
|
||||
for (int i = 0; i < nodes().count(); i++) {
|
||||
settings.setArrayIndex(i);
|
||||
settings.setValue("nwkAddress", nodes().at(i)->shortAddress());
|
||||
settings.setValue("ieeeAddress", nodes().at(i)->extendedAddress().toString());
|
||||
for (int x = 0; x < nodes().count(); x++) {
|
||||
settings.setArrayIndex(x);
|
||||
ZigbeeNode *node = nodes().at(x);
|
||||
settings.setValue("nwkAddress", node->shortAddress());
|
||||
settings.setValue("ieeeAddress", node->extendedAddress().toString());
|
||||
// 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();
|
||||
}
|
||||
@ -178,27 +231,78 @@ void ZigbeeNetwork::loadNetwork()
|
||||
qCDebug(dcZigbeeNetwork()) << "Load current network configuration from" << m_settingsFileName;
|
||||
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
|
||||
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) {
|
||||
extendedPanId = ZigbeeUtils::generateRandomPanId();
|
||||
qCDebug(dcZigbeeNetwork()) << "Create new PAN id" << extendedPanId;
|
||||
qCDebug(dcZigbeeNetwork()) << "Create new PAN ID" << extendedPanId;
|
||||
}
|
||||
setExtendedPanId(extendedPanId);
|
||||
setChannel(settings.value("channel", 0).toUInt());
|
||||
settings.endGroup();
|
||||
|
||||
int nodesCount = settings.beginReadArray("Nodes");
|
||||
for (int i = 0; i < nodesCount; i++) {
|
||||
settings.setArrayIndex(i);
|
||||
ZigbeeNode *node = new ZigbeeNode(this);
|
||||
for (int x = 0; x < nodesCount; x++) {
|
||||
settings.setArrayIndex(x);
|
||||
ZigbeeNode *node = createNode();
|
||||
node->setShortAddress(static_cast<quint16>(settings.value("nwkAddress", 0).toUInt()));
|
||||
node->setExtendedAddress(ZigbeeAddress(settings.value("ieeeAddress").toString()));
|
||||
// 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);
|
||||
}
|
||||
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()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count());
|
||||
foreach (ZigbeeNode *node, nodes()) {
|
||||
@ -206,16 +310,21 @@ void ZigbeeNetwork::loadNetwork()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ZigbeeNetwork::addNode(ZigbeeNode *node)
|
||||
{
|
||||
if (hasNode(node->extendedAddress())) {
|
||||
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added.";
|
||||
addNodeInternally(node);
|
||||
saveNetwork();
|
||||
}
|
||||
|
||||
void ZigbeeNetwork::addUnitializedNode(ZigbeeNode *node)
|
||||
{
|
||||
if (m_uninitializedNodes.contains(node)) {
|
||||
qCWarning(dcZigbeeNetwork()) << "The uninitialized node" << node << "has already been added.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodes.append(node);
|
||||
emit nodeAdded(node);
|
||||
saveNetwork();
|
||||
m_uninitializedNodes.append(node);
|
||||
}
|
||||
|
||||
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
|
||||
@ -231,13 +340,7 @@ void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
|
||||
|
||||
void ZigbeeNetwork::removeNode(ZigbeeNode *node)
|
||||
{
|
||||
if (!m_nodes.contains(node)) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Try to remove node" << node << "but not in the node list.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodes.removeAll(node);
|
||||
emit nodeRemoved(node);
|
||||
removeNodeInternally(node);
|
||||
saveNetwork();
|
||||
}
|
||||
|
||||
@ -253,6 +356,13 @@ void ZigbeeNetwork::removeNodeInternally(ZigbeeNode *node)
|
||||
node->deleteLater();
|
||||
}
|
||||
|
||||
ZigbeeNode *ZigbeeNetwork::createNode()
|
||||
{
|
||||
ZigbeeNode *node = new ZigbeeNode(this);
|
||||
connect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
|
||||
return node;
|
||||
}
|
||||
|
||||
void ZigbeeNetwork::clearSettings()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Clear network settings";
|
||||
@ -296,3 +406,12 @@ void ZigbeeNetwork::setError(ZigbeeNetwork::Error 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -87,15 +87,19 @@ private:
|
||||
|
||||
QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf";
|
||||
QList<ZigbeeNode *> m_nodes;
|
||||
QList<ZigbeeNode *> m_uninitializedNodes;
|
||||
|
||||
void saveNetwork();
|
||||
void loadNetwork();
|
||||
void addNodeInternally(ZigbeeNode *node);
|
||||
void removeNodeInternally(ZigbeeNode *node);
|
||||
|
||||
protected:
|
||||
void addNode(ZigbeeNode *node);
|
||||
void addNodeInternally(ZigbeeNode *node);
|
||||
void addUnitializedNode(ZigbeeNode *node);
|
||||
void removeNode(ZigbeeNode *node);
|
||||
void removeNodeInternally(ZigbeeNode *node);
|
||||
|
||||
ZigbeeNode *createNode();
|
||||
|
||||
void clearSettings();
|
||||
|
||||
@ -118,6 +122,9 @@ signals:
|
||||
void stateChanged(State state);
|
||||
void errorOccured(Error error);
|
||||
|
||||
private slots:
|
||||
void onNodeStateChanged(ZigbeeNode::State state);
|
||||
|
||||
public slots:
|
||||
virtual void startNetwork() = 0;
|
||||
virtual void stopNetwork() = 0;
|
||||
|
||||
@ -480,8 +480,7 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
|
||||
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress);
|
||||
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
|
||||
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId();
|
||||
qCDebug(dcZigbeeNetwork()) << " Permit joining" << permitJoining();
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining();
|
||||
|
||||
m_networkRunning = true;
|
||||
|
||||
@ -490,7 +489,7 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
|
||||
setExtendedAddress(ZigbeeAddress(extendedAddress));
|
||||
setChannel(channel);
|
||||
|
||||
addNode(this);
|
||||
addUnitializedNode(this);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkManager::onCommandEnableWhitelistFinished()
|
||||
@ -519,42 +518,40 @@ void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished()
|
||||
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||
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)
|
||||
Q_UNUSED(status)
|
||||
QByteArray data = reply->additionalMessage().data();
|
||||
|
||||
quint16 shortAddress = static_cast<quint16>(reply->additionalMessage().data().at(2));
|
||||
shortAddress <<= 8;
|
||||
shortAddress |= reply->additionalMessage().data().at(3);
|
||||
quint8 sequenceNumber = 0;
|
||||
quint8 status = 0;
|
||||
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));
|
||||
manufacturerCode <<= 8;
|
||||
manufacturerCode |= reply->additionalMessage().data().at(5);
|
||||
|
||||
quint16 maximalRxSize = static_cast<quint16>(reply->additionalMessage().data().at(6));
|
||||
maximalRxSize <<= 8;
|
||||
maximalRxSize |= reply->additionalMessage().data().at(7);
|
||||
|
||||
quint16 maximalTxSize = static_cast<quint16>(reply->additionalMessage().data().at(8));
|
||||
maximalTxSize <<= 8;
|
||||
maximalTxSize |= reply->additionalMessage().data().at(9);
|
||||
|
||||
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);
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
stream >> sequenceNumber;
|
||||
stream >> status;
|
||||
stream >> shortAddress;
|
||||
stream >> manufacturerCode;
|
||||
stream >> maximalRxSize;
|
||||
stream >> maximalTxSize;
|
||||
stream >> serverMask;
|
||||
stream >> descriptorFlag;
|
||||
stream >> macFlags;
|
||||
stream >> maxBufferSize;
|
||||
stream >> bitField;
|
||||
|
||||
// Get node object
|
||||
ZigbeeNode *node = getZigbeeNode(shortAddress);
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set node data
|
||||
node->setManufacturerCode(manufacturerCode);
|
||||
@ -570,7 +567,7 @@ void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished()
|
||||
if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
|
||||
node->setNodeType(NodeTypeCoordinator);
|
||||
} 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)) {
|
||||
node->setNodeType(NodeTypeEndDevice);
|
||||
}
|
||||
@ -625,36 +622,39 @@ void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished()
|
||||
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||
|
||||
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
|
||||
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
|
||||
QByteArray data = reply->additionalMessage().data();
|
||||
|
||||
quint16 nwkAddress = static_cast<quint16>(reply->additionalMessage().data().at(2));
|
||||
nwkAddress <<= 8;
|
||||
nwkAddress |= reply->additionalMessage().data().at(3);
|
||||
quint8 sequenceNumber = 0;
|
||||
quint8 status = 0;
|
||||
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) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Length 0";
|
||||
qCWarning(dcZigbeeNetwork()) << "Simple node descriptior has a length of 0.";
|
||||
return;
|
||||
}
|
||||
|
||||
quint8 endPoint = static_cast<quint8>(reply->additionalMessage().data().at(5));
|
||||
|
||||
quint16 profileId = static_cast<quint16>(reply->additionalMessage().data().at(6));
|
||||
profileId <<= 8;
|
||||
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));
|
||||
stream >> endPoint;
|
||||
stream >> profileId;
|
||||
stream >> deviceId;
|
||||
stream >> bitField;
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Node simple descriptor:";
|
||||
qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
||||
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()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint);
|
||||
qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
|
||||
@ -667,30 +667,40 @@ void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished()
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField);
|
||||
|
||||
quint8 inputClusterCount = static_cast<quint8>(reply->additionalMessage().data().at(10));
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << " Input clusters:";
|
||||
QByteArray inputClusterListData = reply->additionalMessage().data().mid(11, inputClusterCount * 2);
|
||||
for (int i = 0; i < inputClusterListData.count(); i+=2) {
|
||||
quint16 clusterId = static_cast<quint16>(inputClusterListData.at(i));
|
||||
clusterId <<= 8;
|
||||
clusterId |= inputClusterListData .at(i+1);
|
||||
|
||||
stream >> inputClusterCount;
|
||||
qCDebug(dcZigbeeNetwork()) << " Input clusters: (" << inputClusterCount << ")";
|
||||
for (int i = 0; i < inputClusterCount; i+=1) {
|
||||
quint16 clusterId = 0;
|
||||
stream >> 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));
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << " Output clusters:";
|
||||
QByteArray outputClusterListData = reply->additionalMessage().data().mid(12 + inputClusterCount * 2, outputClusterCount * 2);
|
||||
for (int i = 0; i < outputClusterListData.count(); i+=2) {
|
||||
quint16 clusterId = static_cast<quint16>(outputClusterListData.at(i));
|
||||
clusterId <<= 8;
|
||||
clusterId |= outputClusterListData .at(i+1);
|
||||
stream >> outputClusterCount;
|
||||
qCDebug(dcZigbeeNetwork()) << " Output clusters: (" << outputClusterCount << ")";
|
||||
for (int i = 0; i < outputClusterCount; i+=1) {
|
||||
if (stream.atEnd()) {
|
||||
qCWarning(dcZigbeeNode()) << "Data stream already at the end but more data expected. Looks like the firmware doesn't provide more data.";
|
||||
break;
|
||||
}
|
||||
|
||||
quint16 clusterId = 0;
|
||||
stream >> 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);
|
||||
}
|
||||
|
||||
@ -699,8 +709,24 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
||||
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -712,19 +738,20 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
||||
|
||||
quint16 bitField = static_cast<quint16>(reply->additionalMessage().data().at(2));
|
||||
bitField <<= 8;
|
||||
bitField |= reply->additionalMessage().data().at(3);
|
||||
bitField |= static_cast<quint8>(reply->additionalMessage().data().at(3));
|
||||
|
||||
// Bit 0 - 3 Power mode
|
||||
// 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
|
||||
// 0001: Receiver switched on periodically
|
||||
// 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)) {
|
||||
m_powerMode = PowerModeAlwaysOn;
|
||||
powerMode = PowerModeAlwaysOn;
|
||||
} 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)) {
|
||||
m_powerMode = PowerModeOnWhenStimulated;
|
||||
powerMode = PowerModeOnWhenStimulated;
|
||||
}
|
||||
|
||||
// Bit 4 - 7 Available power sources
|
||||
@ -733,21 +760,23 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
||||
// Bit 2: Disposable battery
|
||||
// Bit 4: Reserved
|
||||
|
||||
QList<ZigbeeNode::PowerSource> availablePowerSources;
|
||||
if (ZigbeeUtils::checkBitUint16(bitField, 4)) {
|
||||
m_availablePowerSources.append(PowerSourcePermanentMainSupply);
|
||||
availablePowerSources.append(PowerSourcePermanentMainSupply);
|
||||
} else if (ZigbeeUtils::checkBitUint16(bitField, 5)) {
|
||||
m_availablePowerSources.append(PowerSourceRecharchableBattery);
|
||||
availablePowerSources.append(PowerSourceRecharchableBattery);
|
||||
} 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
|
||||
ZigbeeNode::PowerSource powerSource = PowerSourcePermanentMainSupply;
|
||||
if (ZigbeeUtils::checkBitUint16(bitField, 8)) {
|
||||
m_powerSource = PowerSourcePermanentMainSupply;
|
||||
powerSource = PowerSourcePermanentMainSupply;
|
||||
} else if (ZigbeeUtils::checkBitUint16(bitField, 9)) {
|
||||
m_powerSource = PowerSourceRecharchableBattery;
|
||||
powerSource = PowerSourceRecharchableBattery;
|
||||
} else if (ZigbeeUtils::checkBitUint16(bitField, 10)) {
|
||||
m_powerSource = PowerSourceDisposableBattery;
|
||||
powerSource = PowerSourceDisposableBattery;
|
||||
}
|
||||
|
||||
// Bit 12 - 15: Battery level if available
|
||||
@ -755,15 +784,15 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
||||
// 0100: Approximately 33%
|
||||
// 1000: Approximately 66%
|
||||
// 1100: Approximately 100% (near fully charged)
|
||||
|
||||
ZigbeeNode::PowerLevel powerLevel = PowerLevelCriticalLow;
|
||||
if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
|
||||
m_powerLevel = PowerLevelCriticalLow;
|
||||
powerLevel = PowerLevelCriticalLow;
|
||||
} 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)) {
|
||||
m_powerLevel = PowerLevelOk;
|
||||
powerLevel = PowerLevelOk;
|
||||
} else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
|
||||
m_powerLevel = PowerLevelFull;
|
||||
powerLevel = PowerLevelFull;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Node power descriptor:";
|
||||
@ -772,12 +801,32 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
|
||||
qCDebug(dcZigbeeNetwork()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField);
|
||||
qCDebug(dcZigbeeNetwork()) << " Power mode:" << m_powerMode;
|
||||
qCDebug(dcZigbeeNetwork()) << " Available power sources:";
|
||||
foreach (const PowerSource &source, m_availablePowerSources) {
|
||||
foreach (const PowerSource &source, availablePowerSources) {
|
||||
qCDebug(dcZigbeeNetwork()) << " " << source;
|
||||
}
|
||||
qCDebug(dcZigbeeNetwork()) << " Power source:" << m_powerSource;
|
||||
qCDebug(dcZigbeeNetwork()) << " Power level:" << m_powerLevel;
|
||||
qCDebug(dcZigbeeNetwork()) << " Power source:" << powerSource;
|
||||
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) {
|
||||
setStartingState(StartingStateNone);
|
||||
setState(StateRunning);
|
||||
@ -1013,7 +1062,7 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
|
||||
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
|
||||
qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag);
|
||||
|
||||
ZigbeeNode *node = new ZigbeeNode(this);
|
||||
ZigbeeNode *node = createNode();
|
||||
node->setShortAddress(shortAddress);
|
||||
node->setExtendedAddress(ZigbeeAddress(ieeeAddress));
|
||||
node->setMacCapabilitiesFlag(macCapabilitiesFlag);
|
||||
@ -1021,7 +1070,8 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
|
||||
qCDebug(dcZigbeeNetwork()) << " Node:" << node;
|
||||
|
||||
// FIXME: check if node already added, and if we have to update it
|
||||
addNode(node);
|
||||
addUnitializedNode(node);
|
||||
node->setState(StateInitializing);
|
||||
|
||||
ZigbeeInterfaceReply *reply = nullptr;
|
||||
reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey());
|
||||
@ -1071,8 +1121,13 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
|
||||
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)
|
||||
@ -1080,23 +1135,16 @@ void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &
|
||||
QByteArray data = message.data();
|
||||
quint64 extendedAddress = 0;
|
||||
bool rejoining = 0;
|
||||
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
stream >> extendedAddress;
|
||||
stream >> rejoining;
|
||||
|
||||
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;
|
||||
|
||||
ZigbeeNode *node = getZigbeeNode(address);
|
||||
if (node) {
|
||||
removeNode(node);
|
||||
}
|
||||
|
||||
// TODO: remove node
|
||||
if (node) removeNode(node);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message)
|
||||
|
||||
@ -10,6 +10,11 @@ ZigbeeNode::ZigbeeNode(QObject *parent) :
|
||||
|
||||
}
|
||||
|
||||
ZigbeeNode::State ZigbeeNode::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
quint16 ZigbeeNode::shortAddress() const
|
||||
{
|
||||
return m_shortAddress;
|
||||
@ -50,6 +55,11 @@ quint16 ZigbeeNode::manufacturerCode() const
|
||||
return m_manufacturerCode;
|
||||
}
|
||||
|
||||
quint16 ZigbeeNode::deviceId() const
|
||||
{
|
||||
return m_deviceId;
|
||||
}
|
||||
|
||||
bool ZigbeeNode::complexDescriptorAvailable() const
|
||||
{
|
||||
return m_complexDescriptorAvailable;
|
||||
@ -75,6 +85,36 @@ quint8 ZigbeeNode::maximumBufferSize() const
|
||||
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
|
||||
{
|
||||
return m_isPrimaryTrustCenter;
|
||||
@ -170,6 +210,16 @@ ZigbeeNode::PowerLevel ZigbeeNode::powerLevel() const
|
||||
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()
|
||||
//{
|
||||
@ -246,6 +296,11 @@ void ZigbeeNode::setManufacturerCode(quint16 manufacturerCode)
|
||||
m_manufacturerCode = manufacturerCode;
|
||||
}
|
||||
|
||||
void ZigbeeNode::setDeviceId(quint16 deviceId)
|
||||
{
|
||||
m_deviceId = deviceId;
|
||||
}
|
||||
|
||||
void ZigbeeNode::setMaximumRxSize(quint16 size)
|
||||
{
|
||||
m_maximumRxSize = size;
|
||||
@ -303,6 +358,57 @@ void ZigbeeNode::setDescriptorFlag(quint8 descriptorFlag)
|
||||
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()
|
||||
//{
|
||||
// ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "zigbee.h"
|
||||
#include "zigbeecluster.h"
|
||||
#include "zigbeeaddress.h"
|
||||
|
||||
class ZigbeeNode : public QObject
|
||||
@ -14,6 +15,13 @@ class ZigbeeNode : public QObject
|
||||
friend class ZigbeeNetworkManager;
|
||||
|
||||
public:
|
||||
enum State {
|
||||
StateUninitialized,
|
||||
StateInitializing,
|
||||
StateInitialized
|
||||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
enum NodeType {
|
||||
NodeTypeCoordinator = 0,
|
||||
NodeTypeRouter = 1,
|
||||
@ -63,7 +71,7 @@ public:
|
||||
};
|
||||
Q_ENUM(PowerLevel)
|
||||
|
||||
ZigbeeNode(QObject *parent = nullptr);
|
||||
State state() const;
|
||||
|
||||
quint16 shortAddress() const;
|
||||
ZigbeeAddress extendedAddress() const;
|
||||
@ -75,6 +83,7 @@ public:
|
||||
Relationship relationship() const;
|
||||
Zigbee::ZigbeeProfile profile() const;
|
||||
quint16 manufacturerCode() const;
|
||||
quint16 deviceId() const;
|
||||
|
||||
bool complexDescriptorAvailable() const;
|
||||
bool userDescriptorAvailable() const;
|
||||
@ -83,6 +92,14 @@ public:
|
||||
quint16 maximumTxSize() 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
|
||||
bool isPrimaryTrustCenter() const;
|
||||
bool isBackupTrustCenter() const;
|
||||
@ -111,6 +128,12 @@ public:
|
||||
PowerLevel powerLevel() const;
|
||||
|
||||
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;
|
||||
ZigbeeAddress m_extendedAddress;
|
||||
quint8 m_endPoint = 1;
|
||||
@ -120,6 +143,7 @@ private:
|
||||
Relationship m_relationship = Parent;
|
||||
Zigbee::ZigbeeProfile m_profile;
|
||||
quint16 m_manufacturerCode = 0;
|
||||
quint16 m_deviceId = 0;
|
||||
|
||||
bool m_complexDescriptorAvailable = false;
|
||||
bool m_userDescriptorAvailable = false;
|
||||
@ -156,6 +180,8 @@ private:
|
||||
bool m_extendedSimpleDescriptorListAvailable = false;
|
||||
|
||||
protected:
|
||||
void setState(State state);
|
||||
|
||||
void setShortAddress(const quint16 &shortAddress);
|
||||
void setExtendedAddress(const ZigbeeAddress &extendedAddress);
|
||||
void setEndPoint(quint8 endPoint);
|
||||
@ -165,6 +191,7 @@ protected:
|
||||
void setRelationship(Relationship relationship);
|
||||
void setZigbeeProfile(Zigbee::ZigbeeProfile profile);
|
||||
void setManufacturerCode(quint16 manufacturerCode);
|
||||
void setDeviceId(quint16 deviceType);
|
||||
|
||||
void setMaximumRxSize(quint16 size);
|
||||
void setMaximumTxSize(quint16 size);
|
||||
@ -176,6 +203,22 @@ protected:
|
||||
void setMacCapabilitiesFlag(quint16 macFlag);
|
||||
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);
|
||||
|
||||
@ -11,6 +11,16 @@ ZigbeeSecurityConfiguration::ZigbeeSecurityConfiguration(const ZigbeeSecurityCon
|
||||
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
|
||||
{
|
||||
return m_networkKey;
|
||||
@ -33,12 +43,14 @@ void ZigbeeSecurityConfiguration::setGlobalTrustCenterlinkKey(const QString &glo
|
||||
|
||||
void ZigbeeSecurityConfiguration::clear()
|
||||
{
|
||||
m_zigbeeSecurityMode = ZigbeeSecurityModeNone;
|
||||
m_networkKey.clear();
|
||||
m_globalTrustCenterLinkKey = "5A6967426565416C6C69616E63653039";
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -6,9 +6,18 @@
|
||||
class ZigbeeSecurityConfiguration
|
||||
{
|
||||
public:
|
||||
enum ZigbeeSecurityMode {
|
||||
ZigbeeSecurityModeNone,
|
||||
ZigbeeSecurityModeNetworkLayer,
|
||||
ZigbeeSecurityModeApplicationLayer
|
||||
};
|
||||
|
||||
explicit ZigbeeSecurityConfiguration();
|
||||
ZigbeeSecurityConfiguration(const ZigbeeSecurityConfiguration &other);
|
||||
|
||||
ZigbeeSecurityMode zigbeeSecurityMode() const;
|
||||
void setZigbeeSecurityMode(ZigbeeSecurityMode zigbeeSecurityMode);
|
||||
|
||||
QString networkKey() const;
|
||||
void setNetworkKey(const QString &networkKey);
|
||||
|
||||
@ -21,6 +30,8 @@ public:
|
||||
bool operator!=(const ZigbeeSecurityConfiguration &other) const;
|
||||
|
||||
private:
|
||||
ZigbeeSecurityMode m_zigbeeSecurityMode = ZigbeeSecurityModeNone;
|
||||
|
||||
// This is the local network key
|
||||
QString m_networkKey;
|
||||
|
||||
|
||||
@ -133,7 +133,6 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
|
||||
|
||||
quint64 ZigbeeUtils::generateRandomPanId()
|
||||
{
|
||||
srand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000));
|
||||
srand(static_cast<uint>(qrand()));
|
||||
qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000));
|
||||
return static_cast<quint64>((ULLONG_MAX - 0) * (qrand()/static_cast<double>(RAND_MAX)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user