Fix network saving/loading and add basic nodes connected mechanism

pull/2/head
Simon Stürz 2019-05-17 00:15:07 +02:00
parent 7745f09581
commit 8de27cec12
7 changed files with 232 additions and 172 deletions

View File

@ -39,10 +39,8 @@ ZigbeeClusterAttribute ZigbeeCluster::attribute(quint16 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);
}
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
} else {
m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute);

View File

@ -162,6 +162,31 @@ bool ZigbeeNetwork::hasNode(const ZigbeeAddress &address) const
return getZigbeeNode(address) != nullptr;
}
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
{
if (m_nodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added.";
return;
}
node->setConnected(state() == StateRunning);
m_nodes.append(node);
emit nodeAdded(node);
}
void ZigbeeNetwork::removeNodeInternally(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);
node->deleteLater();
}
void ZigbeeNetwork::saveNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName;
@ -171,59 +196,9 @@ void ZigbeeNetwork::saveNetwork()
settings.setValue("channel", channel());
settings.endGroup();
settings.beginGroup("Nodes");
settings.remove("");
settings.endGroup();
settings.beginWriteArray("Nodes");
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();
foreach (ZigbeeNode *node, nodes()) {
saveNode(node);
}
settings.endArray();
}
void ZigbeeNetwork::loadNetwork()
@ -240,129 +215,81 @@ void ZigbeeNetwork::loadNetwork()
setChannel(settings.value("channel", 0).toUInt());
settings.endGroup();
int nodesCount = settings.beginReadArray("Nodes");
for (int x = 0; x < nodesCount; x++) {
settings.setArrayIndex(x);
// Load nodes
settings.beginGroup("Nodes");
foreach (const QString ieeeAddressString, settings.childGroups()) {
settings.beginGroup(ieeeAddressString);
ZigbeeNode *node = createNode();
node->setExtendedAddress(ZigbeeAddress(ieeeAddressString));
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");
settings.beginGroup("inputCluster");
foreach (const QString &clusterIdString, settings.childGroups()) {
settings.beginGroup(clusterIdString);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(clusterIdString.toInt());
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();
foreach (const QString &attributeIdString, settings.childGroups()) {
settings.beginGroup(attributeIdString);
quint16 id = static_cast<quint16>(attributeIdString.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.endGroup(); // attributeId
}
settings.endGroup(); // clusterId
}
settings.endArray();
settings.endGroup(); // inputCluster
// 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");
// Output cluster
settings.beginGroup("outputCluster");
foreach (const QString &clusterIdString, settings.childGroups()) {
settings.beginGroup(clusterIdString);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(clusterIdString.toInt());
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();
foreach (const QString &attributeIdString, settings.childGroups()) {
settings.beginGroup(attributeIdString);
quint16 id = static_cast<quint16>(attributeIdString.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.endGroup(); // attributeId
}
settings.endGroup(); // clusterId
}
settings.endArray();
settings.endGroup(); // inputCluster
node->setState(StateInitialized);
addNodeInternally(node);
settings.endGroup(); // ieeeAddress
}
settings.endArray();
settings.endGroup(); // Nodes
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()) {
qCDebug(dcZigbeeNetwork()) << " - " << node;
qCDebug(dcZigbeeNetwork()) << "Output cluster:";
foreach (ZigbeeCluster *cluster, node->outputClusters()) {
qCDebug(dcZigbeeNetwork()) << " " << cluster;
foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) {
qCDebug(dcZigbeeNetwork()) << " " << attribute;
}
}
qCDebug(dcZigbeeNetwork()) << "Input cluster:";
foreach (ZigbeeCluster *cluster, node->inputClusters()) {
qCDebug(dcZigbeeNetwork()) << " " << cluster;
foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) {
qCDebug(dcZigbeeNetwork()) << " " << attribute;
}
}
}
}
void ZigbeeNetwork::addNode(ZigbeeNode *node)
{
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_uninitializedNodes.append(node);
}
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
{
if (m_nodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added.";
return;
}
m_nodes.append(node);
emit nodeAdded(node);
}
void ZigbeeNetwork::removeNode(ZigbeeNode *node)
{
removeNodeInternally(node);
saveNetwork();
}
void ZigbeeNetwork::removeNodeInternally(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);
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";
@ -375,7 +302,7 @@ void ZigbeeNetwork::clearSettings()
qCDebug(dcZigbeeNetwork()) << "Remove zigbee nodes from network";
foreach (ZigbeeNode *node, m_nodes) {
removeNodeInternally(node);
removeNode(node);
}
qCDebug(dcZigbeeNetwork()) << "Clear network settings" << m_settingsFileName;
@ -383,6 +310,100 @@ void ZigbeeNetwork::clearSettings()
settings.clear();
}
void ZigbeeNetwork::saveNode(ZigbeeNode *node)
{
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Nodes");
// Clear settings for this node before storing it
settings.beginGroup(node->extendedAddress().toString());
settings.remove("");
settings.endGroup();
// Save this node
settings.beginGroup(node->extendedAddress().toString());
settings.setValue("nwkAddress", node->shortAddress());
// TODO: save the rest of the node
// Input clusters
settings.beginGroup("inputCluster");
foreach (ZigbeeCluster *cluster, node->inputClusters()) {
settings.beginGroup(QString::number(static_cast<int>(cluster->clusterId())));
foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) {
settings.beginGroup(QString::number(static_cast<int>(attribute.id())));
settings.setValue("dataType", static_cast<int>(attribute.dataType()));
settings.setValue("data", attribute.data());
settings.endGroup(); // attributeId
}
settings.endGroup(); // clusterId
}
settings.endGroup(); // inputCluster
// Output clusters
settings.beginGroup("outputCluster");
foreach (ZigbeeCluster *cluster, node->outputClusters()) {
settings.beginGroup(QString::number(static_cast<int>(cluster->clusterId())));
foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) {
settings.beginGroup(QString::number(static_cast<int>(attribute.id())));
settings.setValue("dataType", static_cast<int>(attribute.dataType()));
settings.setValue("data", attribute.data());
settings.endGroup(); // attributeId
}
settings.endGroup(); // clusterId
}
settings.endGroup(); // inputCluster
settings.endGroup(); // Node ieee address
settings.endGroup(); // Nodes
}
void ZigbeeNetwork::removeNodeFromSettings(ZigbeeNode *node)
{
qCDebug(dcZigbeeNetwork()) << "Remove node" << node << "from settings" << m_settingsFileName;
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Nodes");
// Clear settings for this node before storing it
settings.beginGroup(node->extendedAddress().toString());
settings.remove("");
settings.endGroup();
settings.endGroup(); // Nodes
}
void ZigbeeNetwork::addNode(ZigbeeNode *node)
{
qCDebug(dcZigbeeNetwork()) << "Add node" << node;
addNodeInternally(node);
saveNode(node);
}
void ZigbeeNetwork::addUnitializedNode(ZigbeeNode *node)
{
if (m_uninitializedNodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "The uninitialized node" << node << "has already been added.";
return;
}
connect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
m_uninitializedNodes.append(node);
}
void ZigbeeNetwork::removeNode(ZigbeeNode *node)
{
qCDebug(dcZigbeeNetwork()) << "Remove node" << node;
removeNodeInternally(node);
removeNodeFromSettings(node);
}
ZigbeeNode *ZigbeeNetwork::createNode()
{
ZigbeeNode *node = new ZigbeeNode(this);
return node;
}
void ZigbeeNetwork::setState(ZigbeeNetwork::State state)
{
if (m_state == state)
@ -393,7 +414,6 @@ void ZigbeeNetwork::setState(ZigbeeNetwork::State state)
emit stateChanged(m_state);
if (state == StateRunning) saveNetwork();
if (state == StateStarting) loadNetwork();
}
void ZigbeeNetwork::setError(ZigbeeNetwork::Error error)
@ -411,7 +431,17 @@ void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state)
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());
if (state == ZigbeeNode::StateInitialized && m_uninitializedNodes.contains(node)) {
m_uninitializedNodes.removeAll(node);
disconnect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged);
addNode(node);
}
}
void ZigbeeNetwork::onNodeClusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute)
{
Q_UNUSED(cluster)
Q_UNUSED(attribute)
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());
saveNode(node);
}

View File

@ -18,6 +18,7 @@ public:
Q_ENUM(ControllerType)
enum State {
StateUninitialized,
StateDisconnected,
StateStarting,
StateRunning,
@ -72,7 +73,7 @@ public:
private:
ControllerType m_controllerType = ControlerTypeNxp;
State m_state = StateDisconnected;
State m_state = StateUninitialized;
Error m_error = ErrorNoError;
// Serial port configuration
@ -89,20 +90,23 @@ private:
QList<ZigbeeNode *> m_nodes;
QList<ZigbeeNode *> m_uninitializedNodes;
void saveNetwork();
void loadNetwork();
void addNodeInternally(ZigbeeNode *node);
void removeNodeInternally(ZigbeeNode *node);
protected:
void saveNetwork();
void loadNetwork();
void clearSettings();
void saveNode(ZigbeeNode *node);
void removeNodeFromSettings(ZigbeeNode *node);
void addNode(ZigbeeNode *node);
void addUnitializedNode(ZigbeeNode *node);
void removeNode(ZigbeeNode *node);
ZigbeeNode *createNode();
void clearSettings();
void setState(State state);
void setError(Error error);
@ -124,6 +128,7 @@ signals:
private slots:
void onNodeStateChanged(ZigbeeNode::State state);
void onNodeClusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
public slots:
virtual void startNetwork() = 0;

View File

@ -176,7 +176,6 @@ void ZigbeeNetworkManager::onCommandResetControllerFinished()
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
//if (m_startingState == StartingStateReset && !m_networkRunning) setStartingState(StartingStateGetVersion);
}
void ZigbeeNetworkManager::onCommandSoftResetControllerFinished()
@ -207,7 +206,6 @@ void ZigbeeNetworkManager::onCommandErasePersistentDataFinished()
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateErase) {
setStartingState(StartingStateReset);
// setState(StateStarting);
}
}
@ -427,7 +425,6 @@ void ZigbeeNetworkManager::onCommandAuthenticateDeviceFinished()
quint16 shortPan = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(38, 2));
quint64 extendedPanId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(40, 8));
qCDebug(dcZigbeeNetwork()) << "Authentication response:";
qCDebug(dcZigbeeNetwork()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress);
qCDebug(dcZigbeeNetwork()) << " Key:" << encryptedKey;
@ -489,7 +486,9 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
setExtendedAddress(ZigbeeAddress(extendedAddress));
setChannel(channel);
addUnitializedNode(this);
if (!hasNode(this->shortAddress()))
addUnitializedNode(this);
}
void ZigbeeNetworkManager::onCommandEnableWhitelistFinished()
@ -830,6 +829,9 @@ void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
if (m_startingState == StartingStateReadPowerDescriptor) {
setStartingState(StartingStateNone);
setState(StateRunning);
foreach (ZigbeeNode *node, nodes()) {
node->setConnected(true);
}
}
}
@ -1193,6 +1195,9 @@ void ZigbeeNetworkManager::startNetwork()
connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived);
connect(m_controller, &ZigbeeBridgeController::availableChanged, this, &ZigbeeNetworkManager::onControllerAvailableChanged);
if (state() == StateUninitialized)
loadNetwork();
if (!m_controller->enable(serialPortName(), serialBaudrate())) {
setState(StateDisconnected);
setStartingState(StartingStateNone);
@ -1267,6 +1272,10 @@ void ZigbeeNetworkManager::onControllerAvailableChanged(bool available)
}
if (!available) {
foreach (ZigbeeNode *node, nodes()) {
node->setConnected(false);
}
setError(ErrorHardwareUnavailable);
setState(StateDisconnected);
setStartingState(StartingStateNone);
@ -1281,7 +1290,7 @@ void ZigbeeNetworkManager::onControllerAvailableChanged(bool available)
void ZigbeeNetworkManager::factoryResetNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Factory reset network and forgett all information. This cannot be undone.";
qCDebug(dcZigbeeNetwork()) << "Factory reset network and forget all information. This cannot be undone.";
clearSettings();
setState(StateStarting);

View File

@ -25,7 +25,6 @@ public:
bool permitJoining() const;
void setPermitJoining(bool permitJoining);
private:
enum StartingState {
StartingStateNone,

View File

@ -15,6 +15,11 @@ ZigbeeNode::State ZigbeeNode::state() const
return m_state;
}
bool ZigbeeNode::connected() const
{
return m_connected;
}
quint16 ZigbeeNode::shortAddress() const
{
return m_shortAddress;
@ -220,6 +225,16 @@ void ZigbeeNode::setState(ZigbeeNode::State state)
emit stateChanged(m_state);
}
void ZigbeeNode::setConnected(bool connected)
{
if (m_connected == connected)
return;
qCDebug(dcZigbeeNode()) << "Connected changed" << connected;
m_connected = connected;
emit connectedChanged(m_connected);
}
//void ZigbeeNode::identify()
//{
@ -380,14 +395,14 @@ void ZigbeeNode::setPowerLevel(ZigbeeNode::PowerLevel powerLevel)
void ZigbeeNode::setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute)
{
//qCDebug(dcZigbeeNode()) << this << "cluster attribute changed" << clusterId << 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;
qCDebug(dcZigbeeNode()) << "Created cluster" << cluster;
connect(cluster, &ZigbeeCluster::attributeChanged, this, &ZigbeeNode::onClusterAttributeChanged);
m_outputClusters.insert(clusterId, cluster);
clusterCreated = true;

View File

@ -72,6 +72,7 @@ public:
Q_ENUM(PowerLevel)
State state() const;
bool connected() const;
quint16 shortAddress() const;
ZigbeeAddress extendedAddress() const;
@ -129,6 +130,7 @@ public:
private:
ZigbeeNode(QObject *parent = nullptr);
bool m_connected = false;
State m_state = StateUninitialized;
QHash<Zigbee::ClusterId, ZigbeeCluster *> m_inputClusters;
@ -181,6 +183,7 @@ private:
protected:
void setState(State state);
void setConnected(bool connected);
void setShortAddress(const quint16 &shortAddress);
void setExtendedAddress(const ZigbeeAddress &extendedAddress);
@ -213,6 +216,7 @@ protected:
signals:
void stateChanged(State state);
void connectedChanged(bool connected);
void clusterAdded(ZigbeeCluster *cluster);
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);