First look at zigbee node api integration

This commit is contained in:
Simon Stürz 2021-05-11 08:33:46 +02:00 committed by Michael Zanetti
parent 47c41204ff
commit 6c37b3a750
19 changed files with 1419 additions and 188 deletions

View File

@ -127,6 +127,8 @@
#include "zigbee/zigbeeadaptersproxy.h"
#include "zigbee/zigbeenetwork.h"
#include "zigbee/zigbeenetworks.h"
#include "zigbee/zigbeenodes.h"
#include "zigbee/zigbeenodesproxy.h"
#include "applogcontroller.h"
#include "tagwatcher.h"
#include "appdata.h"
@ -314,6 +316,9 @@ void registerQmlTypes() {
qmlRegisterType<ZigbeeAdaptersProxy>(uri, 1, 0, "ZigbeeAdaptersProxy");
qmlRegisterUncreatableType<ZigbeeNetwork>(uri, 1, 0, "ZigbeeNetwork", "Get it from the ZigbeeManager");
qmlRegisterUncreatableType<ZigbeeNetworks>(uri, 1, 0, "ZigbeeNetworks", "Get it from the ZigbeeManager");
qmlRegisterUncreatableType<ZigbeeNode>(uri, 1, 0, "ZigbeeNode", "Get it from the ZigbeeNodes");
qmlRegisterUncreatableType<ZigbeeNodes>(uri, 1, 0, "ZigbeeNodes", "Get it from the ZigbeeNetwork");
qmlRegisterType<ZigbeeNodesProxy>(uri, 1, 0, "ZigbeeNodesProxy");
qmlRegisterType<ModbusRtuManager>(uri, 1, 0, "ModbusRtuManager");
qmlRegisterUncreatableType<ModbusRtuMaster>(uri, 1, 0, "ModbusRtuMaster", "Get it from the ModbusRtuMasters");

View File

@ -24,6 +24,8 @@ SOURCES += \
$$PWD/models/scriptsproxymodel.cpp \
$$PWD/tagwatcher.cpp \
$$PWD/zigbee/zigbeenode.cpp \
$$PWD/zigbee/zigbeenodes.cpp \
$$PWD/zigbee/zigbeenodesproxy.cpp \
$${PWD}/logging.cpp \
$${PWD}/applogcontroller.cpp \
$${PWD}/wifisetup/btwifisetup.cpp \
@ -179,6 +181,8 @@ HEADERS += \
$$PWD/models/scriptsproxymodel.h \
$$PWD/tagwatcher.h \
$$PWD/zigbee/zigbeenode.h \
$$PWD/zigbee/zigbeenodes.h \
$$PWD/zigbee/zigbeenodesproxy.h \
$${PWD}/logging.h \
$${PWD}/applogcontroller.h \
$${PWD}/wifisetup/btwifisetup.h \

View File

@ -36,9 +36,14 @@
#include "zigbee/zigbeeadapters.h"
#include "zigbee/zigbeenetwork.h"
#include "zigbee/zigbeenetworks.h"
#include "zigbee/zigbeenode.h"
#include "zigbee/zigbeenodes.h"
#include <QMetaEnum>
#include "logging.h"
NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee")
ZigbeeManager::ZigbeeManager(QObject *parent) :
JsonHandler(parent),
m_adapters(new ZigbeeAdapters(this)),
@ -100,7 +105,7 @@ int ZigbeeManager::addNetwork(const QString &serialPort, uint baudRate, const QS
params.insert("baudRate", baudRate);
params.insert("backend", backend);
qDebug() << "Add zigbee network" << params;
qCDebug(dcZigbee()) << "Add zigbee network" << params;
return m_engine->jsonRpcClient()->sendCommand("Zigbee.AddNetwork", params, this, "addNetworkResponse");
}
@ -108,7 +113,7 @@ void ZigbeeManager::removeNetwork(const QUuid &networkUuid)
{
QVariantMap params;
params.insert("networkUuid", networkUuid);
qDebug() << "Remove zigbee network" << params;
qCDebug(dcZigbee()) << "Remove zigbee network" << params;
m_engine->jsonRpcClient()->sendCommand("Zigbee.RemoveNetwork", params, this, "removeNetworkResponse");
}
@ -127,6 +132,21 @@ void ZigbeeManager::factoryResetNetwork(const QUuid &networkUuid)
m_engine->jsonRpcClient()->sendCommand("Zigbee.FactoryResetNetwork", params, this, "factoryResetNetworkResponse");
}
void ZigbeeManager::getNodes(const QUuid &networkUuid)
{
QVariantMap params;
params.insert("networkUuid", networkUuid);
m_engine->jsonRpcClient()->sendCommand("Zigbee.GetNodes", params, this, "getNodesResponse");
}
int ZigbeeManager::removeNode(const QUuid &networkUuid, const QString &ieeeAddress)
{
QVariantMap params;
params.insert("networkUuid", networkUuid);
params.insert("ieeeAddress", ieeeAddress);
return m_engine->jsonRpcClient()->sendCommand("Zigbee.RemoveNode", params, this, "removeNodeResponse");
}
void ZigbeeManager::init()
{
m_adapters->clear();
@ -142,7 +162,7 @@ void ZigbeeManager::init()
void ZigbeeManager::getAvailableBackendsResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee get available backends response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee get available backends response" << commandId << params;
m_availableBackends.clear();
foreach (const QVariant &backendVariant, params.value("backends").toList()) {
m_availableBackends << backendVariant.toString();
@ -152,56 +172,73 @@ void ZigbeeManager::getAvailableBackendsResponse(int commandId, const QVariantMa
void ZigbeeManager::getAdaptersResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee get adapters response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee get adapters response" << commandId << params;
m_adapters->clear();
foreach (const QVariant &adapterVariant, params.value("adapters").toList()) {
QVariantMap adapterMap = adapterVariant.toMap();
ZigbeeAdapter *adapter = unpackAdapter(adapterMap);
qDebug() << "Zigbee adapter added" << adapter->description() << adapter->serialPort() << adapter->hardwareRecognized();
qCDebug(dcZigbee()) << "Zigbee adapter added" << adapter->description() << adapter->serialPort() << adapter->hardwareRecognized();
m_adapters->addAdapter(adapter);
}
// ZigbeeAdapter *fakeAdapter = new ZigbeeAdapter();
// fakeAdapter->setSerialPort("/dev/fake");
// fakeAdapter->setBackend("Fake");
// fakeAdapter->setBaudRate(9600);
// fakeAdapter->setDescription("Fake adapter");
// fakeAdapter->setHardwareRecognized(true);
// fakeAdapter->setName("Fake");
// m_adapters->addAdapter(fakeAdapter);
}
void ZigbeeManager::getNetworksResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee get networks response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee get networks response" << commandId << params;
m_networks->clear();
foreach (const QVariant &networkVariant, params.value("zigbeeNetworks").toList()) {
QVariantMap networkMap = networkVariant.toMap();
ZigbeeNetwork *network = unpackNetwork(networkMap);
qDebug() << "Zigbee network added" << network->networkUuid().toString() << network->serialPort() << network->macAddress();
qCDebug(dcZigbee()) << "Zigbee network added" << network->networkUuid().toString() << network->serialPort() << network->macAddress();
m_networks->addNetwork(network);
// Get nodes from this network
getNodes(network->networkUuid());
}
}
void ZigbeeManager::addNetworkResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee add network response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee add network response" << commandId << params;
emit addNetworkReply(commandId, params.value("zigbeeError").toString(), params.value("networkUuid").toUuid());
}
void ZigbeeManager::removeNetworkResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee remove network response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee remove network response" << commandId << params;
}
void ZigbeeManager::setPermitJoinResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee set permit join network response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee set permit join network response" << commandId << params;
}
void ZigbeeManager::factoryResetNetworkResponse(int commandId, const QVariantMap &params)
{
qDebug() << "Zigbee factory reset network response" << commandId << params;
qCDebug(dcZigbee()) << "Zigbee factory reset network response" << commandId << params;
}
void ZigbeeManager::getNodesResponse(int commandId, const QVariantMap &params)
{
qCDebug(dcZigbee()) << "Zigbee get nodes response" << commandId << params;
foreach (const QVariant &nodeVariant, params.value("zigbeeNodes").toList()) {
QVariantMap nodeMap = nodeVariant.toMap();
QUuid networkUuid = nodeMap.value("networkUuid").toUuid();
ZigbeeNetwork *network = m_networks->getNetwork(networkUuid);
if (!network) {
qCWarning(dcZigbee()) << "Could not find network for node" << nodeMap;
return;
}
addOrUpdateNode(network, nodeMap);
}
}
void ZigbeeManager::removeNodeResponse(int commandId, const QVariantMap &params)
{
qCDebug(dcZigbee()) << "Zigbee remove node response" << commandId << params;
emit removeNodeReply(commandId, params.value("zigbeeError").toString());
}
void ZigbeeManager::notificationReceived(const QVariantMap &notification)
@ -236,14 +273,54 @@ void ZigbeeManager::notificationReceived(const QVariantMap &notification)
QUuid networkUuid = networkMap.value("networkUuid").toUuid();
ZigbeeNetwork *network = m_networks->getNetwork(networkUuid);
if (!network) {
qWarning() << "Could not find network for changed notification";
qCWarning(dcZigbee()) << "Could not find network for changed notification";
return;
}
fillNetworkData(network, networkMap);
return;
}
qDebug() << "Unhandled Zigbee notification" << notificationString << notification;
if (notificationString == "Zigbee.NodeAdded") {
QVariantMap nodeMap = notification.value("params").toMap().value("zigbeeNode").toMap();
QUuid networkUuid = nodeMap.value("networkUuid").toUuid();
ZigbeeNetwork *network = m_networks->getNetwork(networkUuid);
if (!network) {
qCWarning(dcZigbee()) << "Could not find network for node added notification" << nodeMap;
return;
}
addOrUpdateNode(network, nodeMap);
return;
}
if (notificationString == "Zigbee.NodeRemoved") {
QVariantMap nodeMap = notification.value("params").toMap().value("zigbeeNode").toMap();
QUuid networkUuid = nodeMap.value("networkUuid").toUuid();
ZigbeeNetwork *network = m_networks->getNetwork(networkUuid);
if (!network) {
qCWarning(dcZigbee()) << "Could not find network for node removed notification" << nodeMap;
return;
}
QString ieeeAddress = nodeMap.value("ieeeAddress").toString();
network->nodes()->removeNode(ieeeAddress);
return;
}
if (notificationString == "Zigbee.NodeChanged") {
QVariantMap nodeMap = notification.value("params").toMap().value("zigbeeNode").toMap();
QUuid networkUuid = nodeMap.value("networkUuid").toUuid();
ZigbeeNetwork *network = m_networks->getNetwork(networkUuid);
if (!network) {
qCWarning(dcZigbee()) << "Could not find network for node changed notification" << nodeMap;
return;
}
addOrUpdateNode(network, nodeMap);
return;
}
qCDebug(dcZigbee()) << "Unhandled Zigbee notification" << notificationString << notification;
}
ZigbeeAdapter *ZigbeeManager::unpackAdapter(const QVariantMap &adapterMap)
@ -266,6 +343,15 @@ ZigbeeNetwork *ZigbeeManager::unpackNetwork(const QVariantMap &networkMap)
return network;
}
ZigbeeNode *ZigbeeManager::unpackNode(const QVariantMap &nodeMap)
{
QUuid networkUuid = nodeMap.value("networkUuid").toUuid();
QString ieeeAddress = nodeMap.value("ieeeAddress").toString();
ZigbeeNode *node = new ZigbeeNode(networkUuid, ieeeAddress, this);
node->updateNodeProperties(nodeMap);
return node;
}
void ZigbeeManager::fillNetworkData(ZigbeeNetwork *network, const QVariantMap &networkMap)
{
network->setNetworkUuid(networkMap.value("networkUuid").toUuid());
@ -283,3 +369,14 @@ void ZigbeeManager::fillNetworkData(ZigbeeNetwork *network, const QVariantMap &n
network->setNetworkState(ZigbeeNetwork::stringToZigbeeNetworkState(networkMap.value("networkState").toString()));
}
void ZigbeeManager::addOrUpdateNode(ZigbeeNetwork *network, const QVariantMap &nodeMap)
{
QString ieeeAddress = nodeMap.value("ieeeAddress").toString();
ZigbeeNode *node = network->nodes()->getNode(ieeeAddress);
if (node) {
node->updateNodeProperties(nodeMap);
} else {
network->nodes()->addNode(unpackNode(nodeMap));
}
}

View File

@ -35,11 +35,13 @@
#include "zigbeeadapter.h"
#include "jsonrpc/jsonhandler.h"
class Engine;
class JsonRpcClient;
class ZigbeeAdapters;
class ZigbeeNetwork;
class ZigbeeNetworks;
class Engine;
class ZigbeeNode;
class ZigbeeNodes;
class ZigbeeManager : public JsonHandler
{
@ -63,15 +65,19 @@ public:
ZigbeeAdapters *adapters() const;
ZigbeeNetworks *networks() const;
// Network
Q_INVOKABLE int addNetwork(const QString &serialPort, uint baudRate, const QString &backend);
Q_INVOKABLE void removeNetwork(const QUuid &networkUuid);
Q_INVOKABLE void setPermitJoin(const QUuid &networkUuid, uint duration = 120);
Q_INVOKABLE void factoryResetNetwork(const QUuid &networkUuid);
Q_INVOKABLE void getNodes(const QUuid &networkUuid);
Q_INVOKABLE int removeNode(const QUuid &networkUuid, const QString &ieeeAddress);
signals:
void engineChanged();
void availableBackendsChanged();
void addNetworkReply(int commandId, const QString &error, const QUuid &networkUuid);
void removeNodeReply(int commandId, const QString &error);
private:
void init();
@ -85,6 +91,9 @@ private:
Q_INVOKABLE void setPermitJoinResponse(int commandId, const QVariantMap &params);
Q_INVOKABLE void factoryResetNetworkResponse(int commandId, const QVariantMap &params);
Q_INVOKABLE void getNodesResponse(int commandId, const QVariantMap &params);
Q_INVOKABLE void removeNodeResponse(int commandId, const QVariantMap &params);
Q_INVOKABLE void notificationReceived(const QVariantMap &notification);
private:
@ -95,8 +104,9 @@ private:
ZigbeeAdapter *unpackAdapter(const QVariantMap &adapterMap);
ZigbeeNetwork *unpackNetwork(const QVariantMap &networkMap);
ZigbeeNode *unpackNode(const QVariantMap &nodeMap);
void fillNetworkData(ZigbeeNetwork *network, const QVariantMap &networkMap);
void addOrUpdateNode(ZigbeeNetwork *network, const QVariantMap &nodeMap);
};
#endif // ZIGBEEMANAGER_H

View File

@ -30,13 +30,14 @@
#include "zigbeenetwork.h"
ZigbeeNetwork::ZigbeeNetwork(QObject *parent) : QObject(parent)
ZigbeeNetwork::ZigbeeNetwork(QObject *parent) :
QObject(parent),
m_nodes(new ZigbeeNodes(this))
{
m_permitJoinTimer = new QTimer(this);
m_permitJoinTimer->setInterval(1000);
m_permitJoinTimer->setSingleShot(true);
connect(m_permitJoinTimer, &QTimer::timeout, this, [this](){
setPermitJoiningRemaining(m_permitJoiningRemaining - 1);
if (m_permitJoiningRemaining <= 0) {
m_permitJoinTimer->stop();
@ -44,6 +45,12 @@ ZigbeeNetwork::ZigbeeNetwork(QObject *parent) : QObject(parent)
});
}
ZigbeeNodes *ZigbeeNetwork::nodes() const
{
return m_nodes;
}
QUuid ZigbeeNetwork::networkUuid() const
{
return m_networkUuid;

View File

@ -35,6 +35,7 @@
#include <QObject>
#include <QTimer>
#include "zigbeenodes.h"
#include "zigbeeadapter.h"
class ZigbeeNetwork : public QObject
@ -54,6 +55,7 @@ class ZigbeeNetwork : public QObject
Q_PROPERTY(uint permitJoiningRemaining READ permitJoiningRemaining NOTIFY permitJoiningRemainingChanged)
Q_PROPERTY(QString backend READ backend NOTIFY backendChanged)
Q_PROPERTY(ZigbeeNetworkState networkState READ networkState NOTIFY networkStateChanged)
Q_PROPERTY(ZigbeeNodes *nodes READ nodes CONSTANT)
// Internal properties
@ -69,6 +71,8 @@ public:
explicit ZigbeeNetwork(QObject *parent = nullptr);
ZigbeeNodes *nodes() const;
QUuid networkUuid() const;
void setNetworkUuid(const QUuid &networkUuid);
@ -145,6 +149,8 @@ private:
QString m_backend;
ZigbeeNetworkState m_networkState;
ZigbeeNodes *m_nodes = nullptr;
QTimer *m_permitJoinTimer = nullptr;
};

View File

@ -92,7 +92,6 @@ QHash<int, QByteArray> ZigbeeNetworks::roleNames() const
roles.insert(RoleBackend, "backend");
roles.insert(RoleNetworkState, "networkState");
return roles;
}
void ZigbeeNetworks::addNetwork(ZigbeeNetwork *network)

View File

@ -1,8 +1,39 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenode.h"
ZigbeeNode::ZigbeeNode(QUuid networkUuid, QObject *parent) :
ZigbeeNode::ZigbeeNode(const QUuid &networkUuid, const QString &ieeeAddress, QObject *parent) :
QObject(parent),
m_networkUuid(networkUuid)
m_networkUuid(networkUuid),
m_ieeeAddress(ieeeAddress)
{
}
@ -11,3 +42,187 @@ QUuid ZigbeeNode::networkUuid() const
{
return m_networkUuid;
}
QString ZigbeeNode::ieeeAddress() const
{
return m_ieeeAddress;
}
quint16 ZigbeeNode::networkAddress() const
{
return m_networkAddress;
}
void ZigbeeNode::setNetworkAddress(quint16 networkAddress)
{
if (m_networkAddress == networkAddress)
return;
m_networkAddress = networkAddress;
emit networkAddressChanged(m_networkAddress);
}
ZigbeeNode::ZigbeeNodeType ZigbeeNode::type() const
{
return m_type;
}
void ZigbeeNode::setType(ZigbeeNode::ZigbeeNodeType type)
{
if (m_type == type)
return;
m_type = type;
emit typeChanged(m_type);
}
ZigbeeNode::ZigbeeNodeState ZigbeeNode::state() const
{
return m_state;
}
void ZigbeeNode::setState(ZigbeeNode::ZigbeeNodeState state)
{
if (m_state == state)
return;
m_state = state;
emit stateChanged(m_state);
}
QString ZigbeeNode::manufacturer() const
{
return m_manufacturer;
}
void ZigbeeNode::setManufacturer(const QString &manufacturer)
{
if (m_manufacturer == manufacturer)
return;
m_manufacturer = manufacturer;
emit manufacturerChanged(m_manufacturer);
}
QString ZigbeeNode::model() const
{
return m_model;
}
void ZigbeeNode::setModel(const QString &model)
{
if (m_model == model)
return;
m_model = model;
emit modelChanged(m_model);
}
QString ZigbeeNode::version() const
{
return m_version;
}
void ZigbeeNode::setVersion(const QString &version)
{
if (m_version == version)
return;
m_version = version;
emit versionChanged(m_version);
}
bool ZigbeeNode::rxOnWhenIdle() const
{
return m_rxOnWhenIdle;
}
void ZigbeeNode::setRxOnWhenIdle(bool rxOnWhenIdle)
{
if (m_rxOnWhenIdle == rxOnWhenIdle)
return;
m_rxOnWhenIdle = rxOnWhenIdle;
emit rxOnWhenIdleChanged(m_rxOnWhenIdle);
}
bool ZigbeeNode::reachable() const
{
return m_reachable;
}
void ZigbeeNode::setReachable(bool reachable)
{
if (m_reachable == reachable)
return;
m_reachable = reachable;
emit reachableChanged(m_reachable);
}
uint ZigbeeNode::lqi() const
{
return m_lqi;
}
void ZigbeeNode::setLqi(uint lqi)
{
if (m_lqi == lqi)
return;
m_lqi = lqi;
emit lqiChanged(m_lqi);
}
QDateTime ZigbeeNode::lastSeen() const
{
return m_lastSeen;
}
void ZigbeeNode::setLastSeen(const QDateTime &lastSeen)
{
if (m_lastSeen == lastSeen)
return;
m_lastSeen = lastSeen;
emit lastSeenChanged(m_lastSeen);
}
ZigbeeNode::ZigbeeNodeState ZigbeeNode::stringToNodeState(const QString &nodeState)
{
if (nodeState == "ZigbeeNodeStateUninitialized") {
return ZigbeeNodeStateUninitialized;
} else if (nodeState == "ZigbeeNodeStateInitializing") {
return ZigbeeNodeStateInitializing;
} else if (nodeState == "ZigbeeNodeStateInitialized") {
return ZigbeeNodeStateInitialized;
} else {
return ZigbeeNodeStateHandled;
}
}
ZigbeeNode::ZigbeeNodeType ZigbeeNode::stringToNodeType(const QString &nodeType)
{
if (nodeType == "ZigbeeNodeTypeCoordinator") {
return ZigbeeNodeTypeCoordinator;
} else if (nodeType == "ZigbeeNodeTypeRouter") {
return ZigbeeNodeTypeRouter;
} else {
return ZigbeeNodeTypeEndDevice;
}
}
void ZigbeeNode::updateNodeProperties(const QVariantMap &nodeMap)
{
setNetworkAddress(nodeMap.value("networkAddress").toUInt());
setType(ZigbeeNode::stringToNodeType(nodeMap.value("type").toString()));
setState(ZigbeeNode::stringToNodeState(nodeMap.value("state").toString()));
setManufacturer(nodeMap.value("manufacturer").toString());
setModel(nodeMap.value("model").toString());
setVersion(nodeMap.value("version").toString());
setRxOnWhenIdle(nodeMap.value("receiverOnWhileIdle").toBool());
setReachable(nodeMap.value("reachable").toBool());
setLqi(nodeMap.value("lqi").toUInt());
setLastSeen(QDateTime::fromMSecsSinceEpoch(nodeMap.value("lastSeen").toUInt() * 1000));
}

View File

@ -1,28 +1,138 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEENODE_H
#define ZIGBEENODE_H
#include <QUuid>
#include <QObject>
#include <QDateTime>
#include <QVariantMap>
class ZigbeeNode : public QObject
{
Q_OBJECT
Q_PROPERTY(QUuid networkUuid READ networkUuid CONSTANT)
Q_PROPERTY(QString ieeeAddress READ ieeeAddress CONSTANT)
Q_PROPERTY(quint16 networkAddress READ networkAddress WRITE setNetworkAddress NOTIFY networkAddressChanged)
Q_PROPERTY(ZigbeeNodeType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(ZigbeeNodeState state READ state WRITE setState NOTIFY stateChanged)
Q_PROPERTY(QString manufacturer READ manufacturer WRITE setManufacturer NOTIFY manufacturerChanged)
Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
Q_PROPERTY(bool rxOnWhenIdle READ rxOnWhenIdle WRITE setRxOnWhenIdle NOTIFY rxOnWhenIdleChanged)
Q_PROPERTY(bool reachable READ reachable WRITE setReachable NOTIFY reachableChanged)
Q_PROPERTY(uint lqi READ lqi WRITE setLqi NOTIFY lqiChanged)
Q_PROPERTY(QDateTime lastSeen READ lastSeen WRITE setLastSeen NOTIFY lastSeenChanged)
public:
explicit ZigbeeNode(QUuid networkUuid, QObject *parent = nullptr);
enum ZigbeeNodeType {
ZigbeeNodeTypeCoordinator,
ZigbeeNodeTypeRouter,
ZigbeeNodeTypeEndDevice
};
Q_ENUM(ZigbeeNodeType)
enum ZigbeeNodeState {
ZigbeeNodeStateUninitialized,
ZigbeeNodeStateInitializing,
ZigbeeNodeStateInitialized,
ZigbeeNodeStateHandled
};
Q_ENUM(ZigbeeNodeState)
explicit ZigbeeNode(const QUuid &networkUuid, const QString &ieeeAddress, QObject *parent = nullptr);
QUuid networkUuid() const;
QString ieeeAddress() const;
void setIeeeAddress(const QString &ieeeAddress);
quint16 networkAddress() const;
void setNetworkAddress(quint16 networkAddress);
ZigbeeNodeType type() const;
void setType(ZigbeeNodeType type);
ZigbeeNodeState state() const;
void setState(ZigbeeNodeState state);
QString manufacturer() const;
void setManufacturer(const QString &manufacturer);
QString model() const;
void setModel(const QString &model);
QString version() const;
void setVersion(const QString &version);
bool rxOnWhenIdle() const;
void setRxOnWhenIdle(bool rxOnWhenIdle);
bool reachable() const;
void setReachable(bool reachable);
uint lqi() const;
void setLqi(uint lqi);
QDateTime lastSeen() const;
void setLastSeen(const QDateTime &lastSeen);
static ZigbeeNodeState stringToNodeState(const QString &nodeState);
static ZigbeeNodeType stringToNodeType(const QString &nodeType);
void updateNodeProperties(const QVariantMap &nodeMap);
signals:
void networkAddressChanged(quint16 networkAddress);
void typeChanged(ZigbeeNodeType type);
void stateChanged(ZigbeeNodeState state);
void manufacturerChanged(const QString &manufacturer);
void modelChanged(const QString &model);
void versionChanged(const QString &version);
void rxOnWhenIdleChanged(bool rxOnWhenIdle);
void reachableChanged(bool reachable);
void lqiChanged(uint lqi);
void lastSeenChanged(const QDateTime &lastSeen);
private:
QUuid m_networkUuid;
QString m_ieeeAddress;
quint16 m_networkAddress = 0;
ZigbeeNodeType m_type = ZigbeeNodeTypeEndDevice;
ZigbeeNodeState m_state = ZigbeeNodeStateUninitialized;
QString m_manufacturer;
QString m_model;
QString m_version;
bool m_rxOnWhenIdle = false;
bool m_reachable = false;
uint m_lqi = 0;
QDateTime m_lastSeen;
};
#endif // ZIGBEENODE_H

View File

@ -0,0 +1,193 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenodes.h"
ZigbeeNodes::ZigbeeNodes(QObject *parent) : QAbstractListModel(parent)
{
}
int ZigbeeNodes::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_nodes.count();
}
QVariant ZigbeeNodes::data(const QModelIndex &index, int role) const
{
switch (role) {
case RoleNetworkUuid:
return m_nodes.at(index.row())->networkUuid();
case RoleIeeeAddress:
return m_nodes.at(index.row())->ieeeAddress();
case RoleNetworkAddress:
return m_nodes.at(index.row())->networkAddress();
case RoleType:
return m_nodes.at(index.row())->type();
case RoleState:
return m_nodes.at(index.row())->state();
case RoleManufacturer:
return m_nodes.at(index.row())->manufacturer();
case RoleModel:
return m_nodes.at(index.row())->model();
case RoleVersion:
return m_nodes.at(index.row())->version();
case RoleRxOnWhenIdle:
return m_nodes.at(index.row())->rxOnWhenIdle();
case RoleReachable:
return m_nodes.at(index.row())->reachable();
case RoleLqi:
return m_nodes.at(index.row())->lqi();
case RoleLastSeen:
return m_nodes.at(index.row())->lastSeen();
}
return QVariant();
}
QHash<int, QByteArray> ZigbeeNodes::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleNetworkUuid, "networkUuid");
roles.insert(RoleIeeeAddress, "ieeeAddress");
roles.insert(RoleNetworkAddress, "networkAddress");
roles.insert(RoleType, "type");
roles.insert(RoleState, "state");
roles.insert(RoleManufacturer, "manufacturer");
roles.insert(RoleModel, "model");
roles.insert(RoleVersion, "version");
roles.insert(RoleRxOnWhenIdle, "rxOnWhenIdle");
roles.insert(RoleReachable, "reachable");
roles.insert(RoleLqi, "lqi");
roles.insert(RoleLastSeen, "lastSeen");
return roles;
}
void ZigbeeNodes::addNode(ZigbeeNode *node)
{
node->setParent(this);
beginInsertRows(QModelIndex(), m_nodes.count(), m_nodes.count());
m_nodes.append(node);
connect(node, &ZigbeeNode::networkAddressChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleNetworkAddress});
});
connect(node, &ZigbeeNode::typeChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleType});
});
connect(node, &ZigbeeNode::stateChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleState});
});
connect(node, &ZigbeeNode::manufacturerChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleManufacturer});
});
connect(node, &ZigbeeNode::modelChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleModel});
});
connect(node, &ZigbeeNode::versionChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleVersion});
});
connect(node, &ZigbeeNode::rxOnWhenIdleChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleRxOnWhenIdle});
});
connect(node, &ZigbeeNode::reachableChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleReachable});
});
connect(node, &ZigbeeNode::lqiChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleLqi});
});
connect(node, &ZigbeeNode::lastSeenChanged, this, [this, node]() {
QModelIndex idx = index(m_nodes.indexOf(node), 0);
emit dataChanged(idx, idx, {RoleLastSeen});
});
endInsertRows();
emit countChanged();
}
void ZigbeeNodes::removeNode(const QString &ieeeAddress)
{
for (int i = 0; i < m_nodes.count(); i++) {
if (m_nodes.at(i)->ieeeAddress() == ieeeAddress) {
beginRemoveRows(QModelIndex(), i, i);
m_nodes.takeAt(i)->deleteLater();
endRemoveRows();
emit countChanged();
return;
}
}
}
void ZigbeeNodes::clear()
{
beginResetModel();
qDeleteAll(m_nodes);
m_nodes.clear();
endResetModel();
emit countChanged();
}
ZigbeeNode *ZigbeeNodes::get(int index) const
{
if (index < 0 || index >= m_nodes.count()) {
return nullptr;
}
return m_nodes.at(index);
}
ZigbeeNode *ZigbeeNodes::getNode(const QString &ieeeAddress) const
{
foreach (ZigbeeNode *node, m_nodes) {
if (node->ieeeAddress() == ieeeAddress) {
return node;
}
}
return nullptr;
}

View File

@ -0,0 +1,84 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEENODES_H
#define ZIGBEENODES_H
#include <QObject>
#include <QAbstractListModel>
#include "zigbeenode.h"
class ZigbeeNodes : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
enum Roles {
RoleNetworkUuid,
RoleIeeeAddress,
RoleNetworkAddress,
RoleType,
RoleState,
RoleManufacturer,
RoleModel,
RoleVersion,
RoleRxOnWhenIdle,
RoleReachable,
RoleLqi,
RoleLastSeen
};
Q_ENUM(Roles)
explicit ZigbeeNodes(QObject *parent = nullptr);
virtual ~ZigbeeNodes() override = default;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
void addNode(ZigbeeNode *node);
void removeNode(const QString &ieeeAddress);
void clear();
Q_INVOKABLE virtual ZigbeeNode *get(int index) const;
Q_INVOKABLE ZigbeeNode *getNode(const QString &ieeeAddress) const;
signals:
void countChanged();
protected:
QList<ZigbeeNode *> m_nodes;
};
#endif // ZIGBEENODES_H

View File

@ -0,0 +1,76 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenodesproxy.h"
#include "zigbeenode.h"
#include "zigbeenodes.h"
#include <QDebug>
ZigbeeNodesProxy::ZigbeeNodesProxy(QObject *parent) :
QSortFilterProxyModel(parent)
{
}
ZigbeeNodes *ZigbeeNodesProxy::zigbeeNodes() const
{
return m_zigbeeNodes;
}
void ZigbeeNodesProxy::setZigbeeNodes(ZigbeeNodes *zigbeeNodes)
{
if (m_zigbeeNodes == zigbeeNodes)
return;
m_zigbeeNodes = zigbeeNodes;
emit zigbeeNodesChanged(m_zigbeeNodes);
qWarning() << "Set nodes to proxy" << m_zigbeeNodes->rowCount();
connect(m_zigbeeNodes, &ZigbeeNodes::countChanged, this, [this](){
emit countChanged();
});
setSourceModel(m_zigbeeNodes);
setSortRole(ZigbeeNodes::RoleNetworkAddress);
sort(0, Qt::DescendingOrder);
invalidateFilter();
emit countChanged();
}
ZigbeeNode *ZigbeeNodesProxy::get(int index) const
{
if (index >= 0 && index < m_zigbeeNodes->rowCount()) {
return m_zigbeeNodes->get(mapToSource(this->index(index, 0)).row());
}
return nullptr;
}

View File

@ -0,0 +1,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEENODESPROXY_H
#define ZIGBEENODESPROXY_H
#include <QObject>
#include <QSortFilterProxyModel>
class ZigbeeNode;
class ZigbeeNodes;
class ZigbeeNodesProxy : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(ZigbeeNodes *zigbeeNodes READ zigbeeNodes WRITE setZigbeeNodes NOTIFY zigbeeNodesChanged)
public:
explicit ZigbeeNodesProxy(QObject *parent = nullptr);
ZigbeeNodes *zigbeeNodes() const;
void setZigbeeNodes(ZigbeeNodes *zigbeeNodes);
Q_INVOKABLE ZigbeeNode *get(int index) const;
signals:
void countChanged();
void zigbeeNodesChanged(ZigbeeNodes *zigbeeNodes);
private:
ZigbeeNodes *m_zigbeeNodes = nullptr;
};
#endif // ZIGBEENODESPROXY_H

View File

@ -262,5 +262,6 @@
<file>ui/images/modbus.svg</file>
<file>ui/images/setupwizard/wired-connection.svg</file>
<file>ui/images/setupwizard/wireless-connection.svg</file>
<file>ui/images/system-suspend.svg</file>
</qresource>
</RCC>

View File

@ -219,7 +219,7 @@
<file>ui/components/ThingInfoPane.qml</file>
<file>ui/system/ZigbeeSettingsPage.qml</file>
<file>ui/system/ZigbeeAddNetworkPage.qml</file>
<file>ui/system/ZigbeeNetworkPage.qml</file>
<file>ui/system/ZigbeeNetworkSettingsPage.qml</file>
<file>ui/MainMenu.qml</file>
<file>ui/components/NymeaItemDelegate.qml</file>
<file>ui/components/NymeaSwipeDelegate.qml</file>
@ -251,5 +251,6 @@
<file>ui/system/ModbusRtuReconfigureMasterPage.qml</file>
<file>ui/connection/NewConnectionWizard.qml</file>
<file>ui/components/WizardPageBase.qml</file>
<file>ui/system/ZigbeeNetworkPage.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" width="96" height="96" version="1.1" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<metadata id="metadata4879">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" transform="rotate(90)" x="78.505" y="-28.143" width="96" height="96" style="color:#000000;fill:none"/>
<path id="path4145" transform="translate(-67.857 78.505)" d="m48.018 11.98c-16.282 0.0038-30.558 10.962-34.775 26.693-4.2175 15.731 2.6648 32.354 16.764 40.494 14.099 8.14 31.934 5.7877 43.449-5.7305 6.9212-6.9231 10.526-16.131 10.539-25.438h-3.9902c-0.00963 8.2694-3.2168 16.448-9.377 22.609-10.249 10.252-26.074 12.338-38.621 5.0938-12.547-7.244-18.652-21.992-14.898-35.994 3.7539-14.002 16.42-23.725 30.91-23.729v-4z" style="color-rendering:auto;color:#000000;fill:#808080;font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:none;font-variant-numeric:normal;font-variant-position:normal;image-rendering:auto;isolation:auto;mix-blend-mode:normal;shape-padding:0;shape-rendering:auto;solid-color:#000000;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path id="path4271" d="m21.942 103.82c-0.51329 0.53896-1.1934 1.2961-2.0403 2.2713-0.82127 0.97525-1.7067 2.066-2.6563 3.2722-0.94959 1.1806-1.912 2.4253-2.8873 3.7342-0.94959 1.2832-1.8094 2.5151-2.5793 3.6957h10.394v3.8882h-16.015v-2.8873c0.56462-1.0266 1.2704-2.143 2.1173-3.3492 0.84693-1.2062 1.7195-2.4125 2.6178-3.6187 0.89826-1.2319 1.7837-2.3996 2.6563-3.5032 0.89826-1.1036 1.6939-2.066 2.3868-2.8873h-9.7507v-3.8882h15.756z" style="fill:#808080"/>
<path id="path4273" d="m-0.67371 104.09c-0.82494 0.89993-1.8249 2.0748-2.9998 3.5247-1.1749 1.4249-2.3873 2.9873-3.6372 4.6872-1.2499 1.6749-2.4873 3.4122-3.7122 5.2121-1.1999 1.7749-2.2623 3.4622-3.1873 5.0621h14.313v4.0122h-20.012v-2.9623c0.49996-0.92493 1.0749-1.9249 1.7249-2.9998 0.67495-1.0999 1.3874-2.2248 2.1373-3.3748s1.5249-2.3123 2.3248-3.4872c0.82494-1.1749 1.6374-2.2998 2.4373-3.3748 0.79994-1.0999 1.5749-2.1373 2.3248-3.1123 0.77494-0.99993 1.4999-1.8874 2.1748-2.6623h-13.069v-4.0122h19.181z" style="fill:#808080"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -42,120 +42,347 @@ SettingsPageBase {
property ZigbeeNetwork network: null
header: NymeaHeader {
text: qsTr("ZigBee network settings")
text: qsTr("ZigBee network")
backButtonVisible: true
onBackPressed: pageStack.pop()
HeaderButton {
imageSource: "/ui/images/configure.svg"
text: qsTr("Network settings")
onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeNetworkSettingsPage.qml"), { zigbeeManager: zigbeeManager, network: network })
}
}
busy: d.pendingCommandId != -1
QtObject {
id: d
property int pendingCommandId: -1
function removeNode(networkUuid, ieeeAddress) {
d.pendingCommandId = root.zigbeeManager.removeNode(networkUuid, ieeeAddress)
}
}
Connections {
target: root.zigbeeManager
onRemoveNodeReply: {
if (commandId == d.pendingCommandId) {
d.pendingCommandId = -1
var props = {};
switch (error) {
case "ZigbeeErrorNoError":
return;
case "ZigbeeErrorAdapterNotAvailable":
props.text = qsTr("The selected adapter is not available or the selected serial port configration is incorrect.");
break;
case "ZigbeeErrorAdapterAlreadyInUse":
props.text = qsTr("The selected adapter is already in use.");
break;
default:
props.errorCode = error;
}
var comp = Qt.createComponent("../components/ErrorDialog.qml")
var popup = comp.createObject(app, props)
popup.open();
}
}
}
SettingsPageSectionHeader {
text: qsTr("Network information")
text: qsTr("Network")
}
NymeaSwipeDelegate {
RowLayout {
Layout.fillWidth: true
text: qsTr("Network state")
subText: {
switch (root.network.networkState) {
case ZigbeeNetwork.ZigbeeNetworkStateOnline:
return qsTr("The network is online")
case ZigbeeNetwork.ZigbeeNetworkStateOffline:
return qsTr("The network is offline")
case ZigbeeNetwork.ZigbeeNetworkStateStarting:
return qsTr("The network is starting...")
case ZigbeeNetwork.ZigbeeNetworkStateUpdating:
return qsTr("The controller is currently installing an update")
case ZigbeeNetwork.ZigbeeNetworkStateError:
return qsTr("The network is in an error state.")
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Label {
//Layout.fillWidth: true
text: {
switch (network.networkState) {
case ZigbeeNetwork.ZigbeeNetworkStateOnline:
return qsTr("Online")
case ZigbeeNetwork.ZigbeeNetworkStateOffline:
return qsTr("Offline")
case ZigbeeNetwork.ZigbeeNetworkStateStarting:
return qsTr("Starting")
case ZigbeeNetwork.ZigbeeNetworkStateUpdating:
return qsTr("Updating")
case ZigbeeNetwork.ZigbeeNetworkStateError:
return qsTr("Error")
}
}
}
progressive: false
Led {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
state: {
switch (network.networkState) {
case ZigbeeNetwork.ZigbeeNetworkStateOnline:
return "on"
case ZigbeeNetwork.ZigbeeNetworkStateOffline:
return "off"
case ZigbeeNetwork.ZigbeeNetworkStateStarting:
return "orange"
case ZigbeeNetwork.ZigbeeNetworkStateUpdating:
return "orange"
case ZigbeeNetwork.ZigbeeNetworkStateError:
return "red"
}
}
}
}
NymeaSwipeDelegate {
Label {
Layout.fillWidth: true
text: qsTr("Channel")
subText: root.network.channel
progressive: false
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Channel") + ": " + network.channel
}
NymeaSwipeDelegate {
RowLayout {
Layout.fillWidth: true
text: qsTr("Network PAN ID")
subText: root.network.panId
progressive: false
}
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
SettingsPageSectionHeader {
text: qsTr("Hardware information")
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("MAC address:")
subText: root.network.macAddress
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Serial port")
subText: root.network.serialPort
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Baud rate")
subText: root.network.baudRate
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Controller backend")
subText: root.network.backend
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Controller firmware version")
subText: root.network.firmwareVersion
progressive: false
prominentSubText: false
}
SettingsPageSectionHeader {
text: qsTr("Manage network")
}
ColumnLayout {
Button {
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Remove network")
onClicked: {
root.zigbeeManager.removeNetwork(root.network.networkUuid)
pageStack.pop()
text: qsTr("Permit new devices:")
}
Label {
text: network.permitJoiningEnabled ? qsTr("Open for %0 s").arg(network.permitJoiningRemaining) : qsTr("Closed")
}
ColorIcon {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
name: network.permitJoiningEnabled ? "/ui/images/lock-open.svg" : "/ui/images/lock-closed.svg"
visible: !network.permitJoiningEnabled
}
Canvas {
id: canvas
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
rotation: -90
visible: network.permitJoiningEnabled
property real progress: network.permitJoiningRemaining / network.permitJoiningDuration
onProgressChanged: {
canvas.requestPaint()
}
onPaint: {
var ctx = canvas.getContext("2d");
ctx.save();
ctx.reset();
var data = [1 - progress, progress];
var myTotal = 0;
for(var e = 0; e < data.length; e++) {
myTotal += data[e];
}
ctx.fillStyle = Style.accentColor
ctx.strokeStyle = Style.accentColor
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(canvas.width/2,canvas.height/2);
ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2,0,(Math.PI*2*((1-progress)/myTotal)),false);
ctx.lineTo(canvas.width/2,canvas.height/2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2 - 1,0,Math.PI*2,false);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: network.permitJoiningEnabled ? qsTr("Extend open duration") : qsTr("Open for new devices")
enabled: network.networkState === ZigbeeNetwork.ZigbeeNetworkStateOnline
onClicked: zigbeeManager.setPermitJoin(network.networkUuid)
}
SettingsPageSectionHeader {
text: qsTr("Zigbee nodes")
}
Repeater {
id: zigbeeNodeRepeater
model: ZigbeeNodesProxy {
id: zigbeeNodesProxy
zigbeeNodes: root.network.nodes
}
delegate: BigTile {
property ZigbeeNode node: root.network.nodes.get(index)
Layout.fillWidth: true
interactive: false
contentItem: ColumnLayout {
spacing: app.margins
Loader {
id: nodeTypeLoader
Layout.fillWidth: true
sourceComponent: node.type === ZigbeeNode.ZigbeeNodeTypeCoordinator ? coordinatorComponent : deviceComponent
}
Component {
id: coordinatorComponent
ColumnLayout {
RowLayout {
Led {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
state: {
switch (network.networkState) {
case ZigbeeNetwork.ZigbeeNetworkStateOnline:
return "on"
case ZigbeeNetwork.ZigbeeNetworkStateOffline:
return "off"
case ZigbeeNetwork.ZigbeeNetworkStateStarting:
return "orange"
case ZigbeeNetwork.ZigbeeNetworkStateUpdating:
return "orange"
case ZigbeeNetwork.ZigbeeNetworkStateError:
return "red"
}
}
}
Label {
Layout.fillWidth: true
text: qsTr("Coordinator")
}
}
Label { text: network.backend }
Label {
visible: node.version !== ""
text: qsTr("Version") + ": " + network.firmwareVersion
}
Label {
text: qsTr("IEEE address") + ": " + node.ieeeAddress
}
Label {
text: qsTr("Network address") + ": 0x" + (node.networkAddress + Math.pow(16, 4)).toString(16).slice(-4).toUpperCase();
}
}
}
Component {
id: deviceComponent
ColumnLayout {
RowLayout {
Led {
id: reachableLed
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
state: node.reachable ? "on" : "red"
}
Connections {
target: node
onLastSeenChanged: {
communicationIndicatorLed.state = "on"
communicationIndicatorLedTimer.start()
}
}
Timer {
id: communicationIndicatorLedTimer
interval: 200
repeat: false
onTriggered: communicationIndicatorLed.state = "off"
}
Led {
id: communicationIndicatorLed
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
state: "off"
}
BusyIndicator {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
running: visible
visible: node.state !== ZigbeeNode.ZigbeeNodeStateInitialized
}
Label {
Layout.fillWidth: true
text: node.type === ZigbeeNode.ZigbeeNodeTypeRouter ? qsTr("Router") : qsTr("End device")
}
Loader {
id: iconLoader
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
active: !node.rxOnWhenIdle
sourceComponent: sleepyDeviceComponent
}
Component {
id: sleepyDeviceComponent
ColorIcon {
name: "/ui/images/system-suspend.svg"
}
}
}
Label {
text: node.manufacturer + " - " + node.model
}
Label {
visible: node.version !== ""
text: qsTr("Version") + ": " + node.version
}
Label {
text: qsTr("IEEE address") + ": " + node.ieeeAddress
}
Label {
text: qsTr("Network address") + ": 0x" + (node.networkAddress + Math.pow(16, 4)).toString(16).slice(-4).toUpperCase();
}
Label {
text: qsTr("Signal strength") + ": " + Math.round(node.lqi * 100.0 / 255.0) + "%"
}
Button {
id: removeNodeButton
text: qsTr("Remove node")
onClicked: d.removeNode(network.networkUuid, node.ieeeAddress)
}
}
}
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Factory reset controller")
onClicked: {
root.zigbeeManager.factoryResetNetwork(root.network.networkUuid)
}
}
// NymeaSwipeDelegate {
// Layout.fillWidth: true
// iconName: "../images/zigbee.svg"
// text: node.manufacturer + " - " + node.model + " - " + node.version
// subText: node.ieeeAddress + " " + node.networkAddress
// }
}
}

View File

@ -0,0 +1,161 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.8
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.3
import "../components"
import Nymea 1.0
SettingsPageBase {
id: root
property ZigbeeManager zigbeeManager: null
property ZigbeeNetwork network: null
header: NymeaHeader {
text: qsTr("ZigBee network settings")
backButtonVisible: true
onBackPressed: pageStack.pop()
}
SettingsPageSectionHeader {
text: qsTr("Network information")
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Network state")
subText: {
switch (root.network.networkState) {
case ZigbeeNetwork.ZigbeeNetworkStateOnline:
return qsTr("The network is online")
case ZigbeeNetwork.ZigbeeNetworkStateOffline:
return qsTr("The network is offline")
case ZigbeeNetwork.ZigbeeNetworkStateStarting:
return qsTr("The network is starting...")
case ZigbeeNetwork.ZigbeeNetworkStateUpdating:
return qsTr("The controller is currently installing an update")
case ZigbeeNetwork.ZigbeeNetworkStateError:
return qsTr("The network is in an error state.")
}
}
progressive: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Channel")
subText: root.network ? root.network.channel : ""
progressive: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Network PAN ID")
subText: root.network ? root.network.panId : ""
progressive: false
}
SettingsPageSectionHeader {
text: qsTr("Hardware information")
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("MAC address:")
subText: root.network ? root.network.macAddress : ""
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Serial port")
subText: root.network ? root.network.serialPort : ""
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Baud rate")
subText: root.network ? root.network.baudRate : ""
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Controller backend")
subText: root.network ? root.network.backend : ""
progressive: false
prominentSubText: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Controller firmware version")
subText: root.network ? root.network.firmwareVersion : ""
progressive: false
prominentSubText: false
}
SettingsPageSectionHeader {
text: qsTr("Manage network")
}
ColumnLayout {
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Remove network")
onClicked: {
root.zigbeeManager.removeNetwork(root.network.networkUuid)
pageStack.pop()
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Factory reset controller")
onClicked: {
root.zigbeeManager.factoryResetNetwork(root.network.networkUuid)
}
}
}
}

View File

@ -81,8 +81,11 @@ SettingsPageBase {
Layout.fillWidth: true
interactive: false
onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeNetworkPage.qml"), { zigbeeManager: zigbeeManager, network: zigbeeManager.networks.get(index) })
contentItem: ColumnLayout {
spacing: app.margins
RowLayout {
ColorIcon {
name: "/ui/images/zigbee/" + model.backend + ".svg"
@ -95,14 +98,8 @@ SettingsPageBase {
text: model.backend
font.pixelSize: app.largeFont
}
ProgressButton {
size: Style.iconSize
imageSource: "/ui/images/configure.svg"
longpressEnabled: false
onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeNetworkPage.qml"), { zigbeeManager: zigbeeManager, network: zigbeeManager.networks.get(index) })
}
}
RowLayout {
Label {
Layout.fillWidth: true
@ -148,65 +145,21 @@ SettingsPageBase {
RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("Permit new devices:")
text: qsTr("MAC address:")
}
Label {
text: model.permitJoiningEnabled ? qsTr("Open for %0 s").arg(model.permitJoiningRemaining) : qsTr("Closed")
}
ColorIcon {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
name: model.permitJoiningEnabled ? "/ui/images/lock-open.svg" : "/ui/images/lock-closed.svg"
visible: !model.permitJoiningEnabled
}
Canvas {
id: canvas
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
rotation: -90
visible: model.permitJoiningEnabled
property real progress: model.permitJoiningRemaining / model.permitJoiningDuration
onProgressChanged: {
canvas.requestPaint()
}
onPaint: {
var ctx = canvas.getContext("2d");
ctx.save();
ctx.reset();
var data = [1 - progress, progress];
var myTotal = 0;
for(var e = 0; e < data.length; e++) {
myTotal += data[e];
}
ctx.fillStyle = Style.accentColor
ctx.strokeStyle = Style.accentColor
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(canvas.width/2,canvas.height/2);
ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2,0,(Math.PI*2*((1-progress)/myTotal)),false);
ctx.lineTo(canvas.width/2,canvas.height/2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2 - 1,0,Math.PI*2,false);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
text: model.macAddress
}
}
Button {
Layout.fillWidth: true
text: model.permitJoiningEnabled ? qsTr("Extend open duration") : qsTr("Open for new devices")
enabled: model.networkState === ZigbeeNetwork.ZigbeeNetworkStateOnline
onClicked: zigbeeManager.setPermitJoin(model.networkUuid)
RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("Firmware version:")
}
Label {
text: model.firmwareVersion
}
}
}
}